@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.223

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 (541) hide show
  1. package/README.md +2 -1
  2. package/package.json +13 -13
  3. package/src/lib/components/activity-list.js +12 -5
  4. package/src/lib/components/activity-list.js.map +1 -1
  5. package/src/lib/components/companies-bulk-bar.d.ts +1 -4
  6. package/src/lib/components/companies-bulk-bar.js +7 -20
  7. package/src/lib/components/companies-bulk-bar.js.map +1 -1
  8. package/src/lib/components/companies-section.d.ts +3 -3
  9. package/src/lib/components/companies-section.js +149 -46
  10. package/src/lib/components/companies-section.js.map +1 -1
  11. package/src/lib/components/company-edit-drawer.js +281 -20
  12. package/src/lib/components/company-edit-drawer.js.map +1 -1
  13. package/src/lib/components/company-properties-card.js +99 -8
  14. package/src/lib/components/company-properties-card.js.map +1 -1
  15. package/src/lib/components/contact-detail-page.js +3 -1
  16. package/src/lib/components/contact-detail-page.js.map +1 -1
  17. package/src/lib/components/contact-merge-dialog.js +33 -10
  18. package/src/lib/components/contact-merge-dialog.js.map +1 -1
  19. package/src/lib/components/contact-properties-card.d.ts +0 -69
  20. package/src/lib/components/contact-properties-card.js +350 -60
  21. package/src/lib/components/contact-properties-card.js.map +1 -1
  22. package/src/lib/components/contact-reports-to-field.d.ts +46 -0
  23. package/src/lib/components/contact-reports-to-field.js +67 -0
  24. package/src/lib/components/contact-reports-to-field.js.map +1 -0
  25. package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
  26. package/src/lib/components/contacts-bulk-bar.js +7 -19
  27. package/src/lib/components/contacts-bulk-bar.js.map +1 -1
  28. package/src/lib/components/contacts-section.js +46 -33
  29. package/src/lib/components/contacts-section.js.map +1 -1
  30. package/src/lib/components/crm-call-actions.d.ts +10 -0
  31. package/src/lib/components/crm-call-actions.js +26 -9
  32. package/src/lib/components/crm-call-actions.js.map +1 -1
  33. package/src/lib/components/crm-next-activity-column.js +1 -1
  34. package/src/lib/components/crm-next-activity-column.js.map +1 -1
  35. package/src/lib/components/crm-record-picker.d.ts +15 -0
  36. package/src/lib/components/crm-record-picker.js +16 -10
  37. package/src/lib/components/crm-record-picker.js.map +1 -1
  38. package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
  39. package/src/lib/components/crm-transfer-buttons.js +167 -0
  40. package/src/lib/components/crm-transfer-buttons.js.map +1 -0
  41. package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
  42. package/src/lib/components/deal-contact-roles-card.js +368 -0
  43. package/src/lib/components/deal-contact-roles-card.js.map +1 -0
  44. package/src/lib/components/deal-detail-page.d.ts +3 -2
  45. package/src/lib/components/deal-detail-page.js +25 -6
  46. package/src/lib/components/deal-detail-page.js.map +1 -1
  47. package/src/lib/components/deal-edit-drawer.d.ts +10 -0
  48. package/src/lib/components/deal-edit-drawer.js +219 -10
  49. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  50. package/src/lib/components/deal-properties-card.d.ts +7 -0
  51. package/src/lib/components/deal-properties-card.js +34 -3
  52. package/src/lib/components/deal-properties-card.js.map +1 -1
  53. package/src/lib/components/deal-stage-card.d.ts +4 -0
  54. package/src/lib/components/deal-stage-card.js +10 -2
  55. package/src/lib/components/deal-stage-card.js.map +1 -1
  56. package/src/lib/components/deals-bulk-bar.d.ts +0 -3
  57. package/src/lib/components/deals-bulk-bar.js +7 -20
  58. package/src/lib/components/deals-bulk-bar.js.map +1 -1
  59. package/src/lib/components/deals-section.d.ts +3 -3
  60. package/src/lib/components/deals-section.js +123 -63
  61. package/src/lib/components/deals-section.js.map +1 -1
  62. package/src/lib/components/fields-section.js +31 -17
  63. package/src/lib/components/fields-section.js.map +1 -1
  64. package/src/lib/components/lead-convert-dialog.d.ts +4 -0
  65. package/src/lib/components/lead-convert-dialog.js +23 -1
  66. package/src/lib/components/lead-convert-dialog.js.map +1 -1
  67. package/src/lib/components/lead-detail-page.js +8 -2
  68. package/src/lib/components/lead-detail-page.js.map +1 -1
  69. package/src/lib/components/lead-profile-fields.d.ts +71 -0
  70. package/src/lib/components/lead-profile-fields.js +386 -0
  71. package/src/lib/components/lead-profile-fields.js.map +1 -0
  72. package/src/lib/components/lead-properties-card.d.ts +2 -1
  73. package/src/lib/components/lead-properties-card.js +85 -176
  74. package/src/lib/components/lead-properties-card.js.map +1 -1
  75. package/src/lib/components/lead-source-select.d.ts +4 -23
  76. package/src/lib/components/lead-source-select.js +9 -73
  77. package/src/lib/components/lead-source-select.js.map +1 -1
  78. package/src/lib/components/lead-status-chip.d.ts +9 -3
  79. package/src/lib/components/lead-status-chip.js +8 -4
  80. package/src/lib/components/lead-status-chip.js.map +1 -1
  81. package/src/lib/components/lead-status-options.d.ts +20 -0
  82. package/src/lib/components/lead-status-options.js +51 -0
  83. package/src/lib/components/lead-status-options.js.map +1 -0
  84. package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
  85. package/src/lib/components/lead-unqualify-dialog.js +50 -18
  86. package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
  87. package/src/lib/components/leads-bulk-bar.d.ts +0 -3
  88. package/src/lib/components/leads-bulk-bar.js +29 -29
  89. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  90. package/src/lib/components/leads-section.js +120 -68
  91. package/src/lib/components/leads-section.js.map +1 -1
  92. package/src/lib/components/linked-deals-card.d.ts +4 -0
  93. package/src/lib/components/linked-deals-card.js +47 -3
  94. package/src/lib/components/linked-deals-card.js.map +1 -1
  95. package/src/lib/components/log-activity-dialog.js +43 -3
  96. package/src/lib/components/log-activity-dialog.js.map +1 -1
  97. package/src/lib/components/new-contact-drawer.d.ts +8 -0
  98. package/src/lib/components/new-contact-drawer.js +108 -6
  99. package/src/lib/components/new-contact-drawer.js.map +1 -1
  100. package/src/lib/components/new-lead-drawer.d.ts +9 -2
  101. package/src/lib/components/new-lead-drawer.js +88 -121
  102. package/src/lib/components/new-lead-drawer.js.map +1 -1
  103. package/src/lib/components/picklist-select.d.ts +36 -0
  104. package/src/lib/components/picklist-select.js +114 -0
  105. package/src/lib/components/picklist-select.js.map +1 -0
  106. package/src/lib/components/picklist-values-card.d.ts +34 -0
  107. package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
  108. package/src/lib/components/picklist-values-card.js.map +1 -0
  109. package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
  110. package/src/lib/components/pipeline-stages-dialog.js +26 -4
  111. package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
  112. package/src/lib/components/pipelines-dialog.js +15 -6
  113. package/src/lib/components/pipelines-dialog.js.map +1 -1
  114. package/src/lib/components/recent-activity-feed.js +20 -5
  115. package/src/lib/components/recent-activity-feed.js.map +1 -1
  116. package/src/lib/components/recipes-card.js +4 -2
  117. package/src/lib/components/recipes-card.js.map +1 -1
  118. package/src/lib/components/record-tasks-card.js +15 -8
  119. package/src/lib/components/record-tasks-card.js.map +1 -1
  120. package/src/lib/components/reports/forecast-card.d.ts +6 -0
  121. package/src/lib/components/reports/forecast-card.js +101 -3
  122. package/src/lib/components/reports/forecast-card.js.map +1 -1
  123. package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
  124. package/src/lib/components/reports/lead-funnel-card.js +9 -5
  125. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  126. package/src/lib/components/reports/lead-source-card.d.ts +23 -0
  127. package/src/lib/components/reports/lead-source-card.js +318 -0
  128. package/src/lib/components/reports/lead-source-card.js.map +1 -0
  129. package/src/lib/components/reports/pipeline-card.js +2 -1
  130. package/src/lib/components/reports/pipeline-card.js.map +1 -1
  131. package/src/lib/components/reports/report-export.js +1 -1
  132. package/src/lib/components/reports/report-export.js.map +1 -1
  133. package/src/lib/components/reports-section.js +8 -0
  134. package/src/lib/components/reports-section.js.map +1 -1
  135. package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
  136. package/src/lib/components/sharing-rule-drawer.js +108 -19
  137. package/src/lib/components/sharing-rule-drawer.js.map +1 -1
  138. package/src/lib/components/sharing-rules-card.js +11 -3
  139. package/src/lib/components/sharing-rules-card.js.map +1 -1
  140. package/src/lib/components/task-cells.d.ts +9 -1
  141. package/src/lib/components/task-cells.js +9 -4
  142. package/src/lib/components/task-cells.js.map +1 -1
  143. package/src/lib/components/task-edit-drawer.js +111 -43
  144. package/src/lib/components/task-edit-drawer.js.map +1 -1
  145. package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
  146. package/src/lib/components/tasks-bulk-bar.js +7 -20
  147. package/src/lib/components/tasks-bulk-bar.js.map +1 -1
  148. package/src/lib/components/tasks-calendar.d.ts +3 -0
  149. package/src/lib/components/tasks-calendar.js +8 -1
  150. package/src/lib/components/tasks-calendar.js.map +1 -1
  151. package/src/lib/components/tasks-section.d.ts +3 -3
  152. package/src/lib/components/tasks-section.js +58 -43
  153. package/src/lib/components/tasks-section.js.map +1 -1
  154. package/src/lib/constants/api-routes.d.ts +2 -9
  155. package/src/lib/constants/api-routes.js +1 -7
  156. package/src/lib/constants/api-routes.js.map +1 -1
  157. package/src/lib/constants/bundle-common.d.ts +6 -0
  158. package/src/lib/constants/bundle-common.js +11 -0
  159. package/src/lib/constants/bundle-common.js.map +1 -1
  160. package/src/lib/constants/company-filters.d.ts +14 -0
  161. package/src/lib/constants/company-filters.js +51 -1
  162. package/src/lib/constants/company-filters.js.map +1 -1
  163. package/src/lib/constants/contact-filters.d.ts +2 -0
  164. package/src/lib/constants/contact-filters.js +18 -1
  165. package/src/lib/constants/contact-filters.js.map +1 -1
  166. package/src/lib/constants/deal-filters.d.ts +22 -1
  167. package/src/lib/constants/deal-filters.js +67 -4
  168. package/src/lib/constants/deal-filters.js.map +1 -1
  169. package/src/lib/declarations.console-server.d.ts +3 -0
  170. package/src/lib/declarations.console-server.js +35 -0
  171. package/src/lib/declarations.console-server.js.map +1 -1
  172. package/src/lib/declarations.d.ts +26 -0
  173. package/src/lib/declarations.js +35 -0
  174. package/src/lib/declarations.js.map +1 -0
  175. package/src/lib/declarations.server.d.ts +11 -0
  176. package/src/lib/declarations.server.js +97 -1
  177. package/src/lib/declarations.server.js.map +1 -1
  178. package/src/lib/hooks/use-company-picklists.d.ts +15 -0
  179. package/src/lib/hooks/use-company-picklists.js +55 -0
  180. package/src/lib/hooks/use-company-picklists.js.map +1 -0
  181. package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
  182. package/src/lib/hooks/use-crm-picklist.js +53 -0
  183. package/src/lib/hooks/use-crm-picklist.js.map +1 -0
  184. package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
  185. package/src/lib/hooks/use-crm-record-names.js +45 -19
  186. package/src/lib/hooks/use-crm-record-names.js.map +1 -1
  187. package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
  188. package/src/lib/hooks/use-crm-task-picklists.js +45 -0
  189. package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
  190. package/src/lib/hooks/use-deals.d.ts +14 -0
  191. package/src/lib/hooks/use-deals.js +29 -0
  192. package/src/lib/hooks/use-deals.js.map +1 -1
  193. package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
  194. package/src/lib/hooks/use-lead-picklists.js +46 -0
  195. package/src/lib/hooks/use-lead-picklists.js.map +1 -0
  196. package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
  197. package/src/lib/hooks/use-lead-source-picklist.js +12 -22
  198. package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
  199. package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
  200. package/src/lib/hooks/use-lead-status-picklist.js +40 -0
  201. package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
  202. package/src/lib/model/companies.d.ts +32 -3
  203. package/src/lib/model/companies.js +133 -16
  204. package/src/lib/model/companies.js.map +1 -1
  205. package/src/lib/model/contact-merge.d.ts +27 -3
  206. package/src/lib/model/contact-merge.js +81 -7
  207. package/src/lib/model/contact-merge.js.map +1 -1
  208. package/src/lib/model/contact-record.d.ts +17 -0
  209. package/src/lib/model/contact-record.js +17 -2
  210. package/src/lib/model/contact-record.js.map +1 -1
  211. package/src/lib/model/contact-update.d.ts +31 -2
  212. package/src/lib/model/contact-update.js +14 -0
  213. package/src/lib/model/contact-update.js.map +1 -1
  214. package/src/lib/model/crm-list-query.d.ts +5 -0
  215. package/src/lib/model/crm-list-query.js +8 -0
  216. package/src/lib/model/crm-list-query.js.map +1 -1
  217. package/src/lib/model/crm-next-activity.d.ts +107 -0
  218. package/src/lib/model/crm-next-activity.js +140 -0
  219. package/src/lib/model/crm-next-activity.js.map +1 -0
  220. package/src/lib/model/crm-recipes.d.ts +40 -0
  221. package/src/lib/model/crm-recipes.js +259 -0
  222. package/src/lib/model/crm-recipes.js.map +1 -0
  223. package/src/lib/model/crm-record-counts.d.ts +36 -0
  224. package/src/lib/model/crm-record-counts.js +54 -0
  225. package/src/lib/model/crm-record-counts.js.map +1 -0
  226. package/src/lib/model/crm-record-lists.d.ts +23 -0
  227. package/src/lib/model/crm-record-lists.js +161 -0
  228. package/src/lib/model/crm-record-lists.js.map +1 -0
  229. package/src/lib/model/crm-reports.d.ts +73 -3
  230. package/src/lib/model/crm-reports.js +120 -1
  231. package/src/lib/model/crm-reports.js.map +1 -1
  232. package/src/lib/model/crm-sharing.d.ts +21 -3
  233. package/src/lib/model/crm-sharing.js +27 -6
  234. package/src/lib/model/crm-sharing.js.map +1 -1
  235. package/src/lib/model/crm-task-reminders.d.ts +152 -0
  236. package/src/lib/model/crm-task-reminders.js +161 -0
  237. package/src/lib/model/crm-task-reminders.js.map +1 -0
  238. package/src/lib/model/deal-board-model.d.ts +8 -2
  239. package/src/lib/model/deal-board-model.js +15 -2
  240. package/src/lib/model/deal-board-model.js.map +1 -1
  241. package/src/lib/model/deal-contact-roles.d.ts +45 -0
  242. package/src/lib/model/deal-contact-roles.js +73 -0
  243. package/src/lib/model/deal-contact-roles.js.map +1 -0
  244. package/src/lib/model/deal-form-model.d.ts +56 -0
  245. package/src/lib/model/deal-form-model.js +79 -7
  246. package/src/lib/model/deal-form-model.js.map +1 -1
  247. package/src/lib/model/download-text-file.d.ts +23 -0
  248. package/src/lib/model/download-text-file.js +34 -0
  249. package/src/lib/model/download-text-file.js.map +1 -0
  250. package/src/lib/model/lead-filters.d.ts +36 -2
  251. package/src/lib/model/lead-filters.js +123 -2
  252. package/src/lib/model/lead-filters.js.map +1 -1
  253. package/src/lib/model/lead-source-direction.d.ts +38 -0
  254. package/src/lib/model/lead-source-direction.js +52 -0
  255. package/src/lib/model/lead-source-direction.js.map +1 -0
  256. package/src/lib/model/next-activity.d.ts +1 -1
  257. package/src/lib/model/next-activity.js.map +1 -1
  258. package/src/lib/model/picklist-values.d.ts +119 -0
  259. package/src/lib/model/picklist-values.js +256 -0
  260. package/src/lib/model/picklist-values.js.map +1 -0
  261. package/src/lib/model/record-facts-disclosed.d.ts +81 -0
  262. package/src/lib/model/record-facts-disclosed.js +281 -0
  263. package/src/lib/model/record-facts-disclosed.js.map +1 -0
  264. package/src/lib/model/record-facts.d.ts +215 -34
  265. package/src/lib/model/record-facts.js +307 -128
  266. package/src/lib/model/record-facts.js.map +1 -1
  267. package/src/lib/model/task-picklists.d.ts +52 -0
  268. package/src/lib/model/task-picklists.js +83 -0
  269. package/src/lib/model/task-picklists.js.map +1 -0
  270. package/src/lib/model/task-routes.d.ts +13 -0
  271. package/src/lib/model/task-routes.js +23 -4
  272. package/src/lib/model/task-routes.js.map +1 -1
  273. package/src/lib/plan-entitlements.js +6 -4
  274. package/src/lib/plan-entitlements.js.map +1 -1
  275. package/src/lib/plugin.js +17 -0
  276. package/src/lib/plugin.js.map +1 -1
  277. package/src/lib/server/api-v1/contacts.js +220 -14
  278. package/src/lib/server/api-v1/contacts.js.map +1 -1
  279. package/src/lib/server/api-v1/crm-activities.js +14 -1
  280. package/src/lib/server/api-v1/crm-activities.js.map +1 -1
  281. package/src/lib/server/api-v1/crm-companies.js +123 -14
  282. package/src/lib/server/api-v1/crm-companies.js.map +1 -1
  283. package/src/lib/server/api-v1/crm-deals.js +291 -26
  284. package/src/lib/server/api-v1/crm-deals.js.map +1 -1
  285. package/src/lib/server/api-v1/crm-leads.js +144 -38
  286. package/src/lib/server/api-v1/crm-leads.js.map +1 -1
  287. package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
  288. package/src/lib/server/api-v1/crm-pipelines.js +8 -2
  289. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
  290. package/src/lib/server/api-v1/crm-tasks.js +78 -34
  291. package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
  292. package/src/lib/server/api-v1/openapi.d.ts +0 -11
  293. package/src/lib/server/api-v1/openapi.js +171 -16
  294. package/src/lib/server/api-v1/openapi.js.map +1 -1
  295. package/src/lib/server/assign-contact-owner.d.ts +188 -0
  296. package/src/lib/server/assign-contact-owner.js +446 -0
  297. package/src/lib/server/assign-contact-owner.js.map +1 -0
  298. package/src/lib/server/associate-company-by-domain.d.ts +70 -0
  299. package/src/lib/server/associate-company-by-domain.js +153 -0
  300. package/src/lib/server/associate-company-by-domain.js.map +1 -0
  301. package/src/lib/server/automation-steps.d.ts +140 -0
  302. package/src/lib/server/automation-steps.js +669 -0
  303. package/src/lib/server/automation-steps.js.map +1 -0
  304. package/src/lib/server/capture-contact.d.ts +17 -0
  305. package/src/lib/server/capture-contact.js +95 -26
  306. package/src/lib/server/capture-contact.js.map +1 -1
  307. package/src/lib/server/capture-host-contact.d.ts +104 -0
  308. package/src/lib/server/capture-host-contact.js +151 -0
  309. package/src/lib/server/capture-host-contact.js.map +1 -0
  310. package/src/lib/server/company-children.d.ts +25 -0
  311. package/src/lib/server/company-children.js +42 -0
  312. package/src/lib/server/company-children.js.map +1 -0
  313. package/src/lib/server/company-delete.d.ts +18 -0
  314. package/src/lib/server/company-delete.js +44 -21
  315. package/src/lib/server/company-delete.js.map +1 -1
  316. package/src/lib/server/contact-email-history.js +21 -19
  317. package/src/lib/server/contact-email-history.js.map +1 -1
  318. package/src/lib/server/contact-remove.js +27 -2
  319. package/src/lib/server/contact-remove.js.map +1 -1
  320. package/src/lib/server/contact-reports-to.d.ts +61 -0
  321. package/src/lib/server/contact-reports-to.js +114 -0
  322. package/src/lib/server/contact-reports-to.js.map +1 -0
  323. package/src/lib/server/contact-update.d.ts +42 -1
  324. package/src/lib/server/contact-update.js +204 -23
  325. package/src/lib/server/contact-update.js.map +1 -1
  326. package/src/lib/server/convert-host-lead.d.ts +46 -1
  327. package/src/lib/server/convert-host-lead.js +173 -15
  328. package/src/lib/server/convert-host-lead.js.map +1 -1
  329. package/src/lib/server/convert-open-lead.js +12 -5
  330. package/src/lib/server/convert-open-lead.js.map +1 -1
  331. package/src/lib/server/crm-email-activity.d.ts +118 -0
  332. package/src/lib/server/crm-email-activity.js +148 -0
  333. package/src/lib/server/crm-email-activity.js.map +1 -0
  334. package/src/lib/server/crm-inbound-email.js +1 -1
  335. package/src/lib/server/crm-inbound-email.js.map +1 -1
  336. package/src/lib/server/crm-next-activity.d.ts +74 -0
  337. package/src/lib/server/crm-next-activity.js +194 -0
  338. package/src/lib/server/crm-next-activity.js.map +1 -0
  339. package/src/lib/server/crm-record-indexes.d.ts +45 -0
  340. package/src/lib/server/crm-record-indexes.js +78 -0
  341. package/src/lib/server/crm-record-indexes.js.map +1 -0
  342. package/src/lib/server/crm-sharing.d.ts +9 -1
  343. package/src/lib/server/crm-sharing.js +23 -3
  344. package/src/lib/server/crm-sharing.js.map +1 -1
  345. package/src/lib/server/deal-contact-roles.d.ts +27 -0
  346. package/src/lib/server/deal-contact-roles.js +89 -0
  347. package/src/lib/server/deal-contact-roles.js.map +1 -0
  348. package/src/lib/server/email-send.js +2 -1
  349. package/src/lib/server/email-send.js.map +1 -1
  350. package/src/lib/server/lead-convert.d.ts +5 -0
  351. package/src/lib/server/lead-convert.js +19 -3
  352. package/src/lib/server/lead-convert.js.map +1 -1
  353. package/src/lib/server/lead-create.d.ts +17 -2
  354. package/src/lib/server/lead-create.js +46 -14
  355. package/src/lib/server/lead-create.js.map +1 -1
  356. package/src/lib/server/lead-nurturing.d.ts +6 -0
  357. package/src/lib/server/lead-nurturing.js +57 -20
  358. package/src/lib/server/lead-nurturing.js.map +1 -1
  359. package/src/lib/server/lead-picklists.d.ts +35 -0
  360. package/src/lib/server/lead-picklists.js +52 -0
  361. package/src/lib/server/lead-picklists.js.map +1 -0
  362. package/src/lib/server/lead-source-picklist.d.ts +1 -13
  363. package/src/lib/server/lead-source-picklist.js +6 -33
  364. package/src/lib/server/lead-source-picklist.js.map +1 -1
  365. package/src/lib/server/merge-contacts.js +23 -5
  366. package/src/lib/server/merge-contacts.js.map +1 -1
  367. package/src/lib/server/next-activity-routes.js +2 -1
  368. package/src/lib/server/next-activity-routes.js.map +1 -1
  369. package/src/lib/server/person-eraser.d.ts +53 -0
  370. package/src/lib/server/person-eraser.js +149 -0
  371. package/src/lib/server/person-eraser.js.map +1 -0
  372. package/src/lib/server/person-records.d.ts +69 -0
  373. package/src/lib/server/person-records.js +317 -0
  374. package/src/lib/server/person-records.js.map +1 -0
  375. package/src/lib/server/person-refund.d.ts +97 -0
  376. package/src/lib/server/person-refund.js +221 -0
  377. package/src/lib/server/person-refund.js.map +1 -0
  378. package/src/lib/server/picklist-values.d.ts +21 -0
  379. package/src/lib/server/picklist-values.js +308 -0
  380. package/src/lib/server/picklist-values.js.map +1 -0
  381. package/src/lib/server/read-picklist.d.ts +44 -0
  382. package/src/lib/server/read-picklist.js +65 -0
  383. package/src/lib/server/read-picklist.js.map +1 -0
  384. package/src/lib/server/recipe-routes.js +22 -8
  385. package/src/lib/server/recipe-routes.js.map +1 -1
  386. package/src/lib/server/record-email-state.js +7 -1
  387. package/src/lib/server/record-email-state.js.map +1 -1
  388. package/src/lib/server/record-facts.d.ts +3 -0
  389. package/src/lib/server/record-facts.js +233 -31
  390. package/src/lib/server/record-facts.js.map +1 -1
  391. package/src/lib/server/record-origin.d.ts +27 -0
  392. package/src/lib/server/record-origin.js +104 -0
  393. package/src/lib/server/record-origin.js.map +1 -0
  394. package/src/lib/server/record-timeline.js +40 -3
  395. package/src/lib/server/record-timeline.js.map +1 -1
  396. package/src/lib/server/suite-gate.js +4 -3
  397. package/src/lib/server/suite-gate.js.map +1 -1
  398. package/src/lib/server/task-reminders-route.js +2 -1
  399. package/src/lib/server/task-reminders-route.js.map +1 -1
  400. package/src/lib/server/task-routes.js +33 -17
  401. package/src/lib/server/task-routes.js.map +1 -1
  402. package/src/lib/server-deal-stage.d.ts +5 -1
  403. package/src/lib/server-deal-stage.js +10 -5
  404. package/src/lib/server-deal-stage.js.map +1 -1
  405. package/src/lib/server.d.ts +8 -3
  406. package/src/lib/server.js +47 -43
  407. package/src/lib/server.js.map +1 -1
  408. package/src/lib/testing/memory-firestore.d.ts +55 -0
  409. package/src/lib/testing/memory-firestore.js +335 -0
  410. package/src/lib/testing/memory-firestore.js.map +1 -0
  411. package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
  412. package/src/lib/testing/stand-in-email-send-index.js +49 -0
  413. package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
  414. package/src/lib/transfer/activities.d.ts +30 -0
  415. package/src/lib/transfer/activities.js +132 -0
  416. package/src/lib/transfer/activities.js.map +1 -0
  417. package/src/lib/transfer/aliases.d.ts +22 -0
  418. package/src/lib/transfer/aliases.js +1342 -0
  419. package/src/lib/transfer/aliases.js.map +1 -0
  420. package/src/lib/transfer/common.d.ts +222 -0
  421. package/src/lib/transfer/common.js +832 -0
  422. package/src/lib/transfer/common.js.map +1 -0
  423. package/src/lib/transfer/companies.d.ts +43 -0
  424. package/src/lib/transfer/companies.js +549 -0
  425. package/src/lib/transfer/companies.js.map +1 -0
  426. package/src/lib/transfer/contacts.d.ts +31 -0
  427. package/src/lib/transfer/contacts.js +727 -0
  428. package/src/lib/transfer/contacts.js.map +1 -0
  429. package/src/lib/transfer/deals.d.ts +66 -0
  430. package/src/lib/transfer/deals.js +698 -0
  431. package/src/lib/transfer/deals.js.map +1 -0
  432. package/src/lib/transfer/email-templates-package.d.ts +40 -0
  433. package/src/lib/transfer/email-templates-package.js +76 -0
  434. package/src/lib/transfer/email-templates-package.js.map +1 -0
  435. package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
  436. package/src/lib/transfer/email-templates-package.server.js +176 -0
  437. package/src/lib/transfer/email-templates-package.server.js.map +1 -0
  438. package/src/lib/transfer/fields.d.ts +102 -0
  439. package/src/lib/transfer/fields.js +1755 -0
  440. package/src/lib/transfer/fields.js.map +1 -0
  441. package/src/lib/transfer/leads.d.ts +30 -0
  442. package/src/lib/transfer/leads.js +582 -0
  443. package/src/lib/transfer/leads.js.map +1 -0
  444. package/src/lib/transfer/pipelines.d.ts +21 -0
  445. package/src/lib/transfer/pipelines.js +172 -0
  446. package/src/lib/transfer/pipelines.js.map +1 -0
  447. package/src/lib/transfer/register.d.ts +47 -0
  448. package/src/lib/transfer/register.js +277 -0
  449. package/src/lib/transfer/register.js.map +1 -0
  450. package/src/lib/transfer/tasks.d.ts +30 -0
  451. package/src/lib/transfer/tasks.js +418 -0
  452. package/src/lib/transfer/tasks.js.map +1 -0
  453. package/src/lib/transfer/ui.d.ts +20 -0
  454. package/src/lib/transfer/ui.js +42 -0
  455. package/src/lib/transfer/ui.js.map +1 -0
  456. package/src/lib/components/company-import-drawer.d.ts +0 -42
  457. package/src/lib/components/company-import-drawer.js +0 -99
  458. package/src/lib/components/company-import-drawer.js.map +0 -1
  459. package/src/lib/components/contact-import-drawer.d.ts +0 -46
  460. package/src/lib/components/contact-import-drawer.js +0 -149
  461. package/src/lib/components/contact-import-drawer.js.map +0 -1
  462. package/src/lib/components/crm-export-all-button.d.ts +0 -39
  463. package/src/lib/components/crm-export-all-button.js +0 -98
  464. package/src/lib/components/crm-export-all-button.js.map +0 -1
  465. package/src/lib/components/csv-import-drawer.d.ts +0 -139
  466. package/src/lib/components/csv-import-drawer.js +0 -757
  467. package/src/lib/components/csv-import-drawer.js.map +0 -1
  468. package/src/lib/components/deal-import-drawer.d.ts +0 -24
  469. package/src/lib/components/deal-import-drawer.js +0 -83
  470. package/src/lib/components/deal-import-drawer.js.map +0 -1
  471. package/src/lib/components/lead-import-drawer.d.ts +0 -27
  472. package/src/lib/components/lead-import-drawer.js +0 -118
  473. package/src/lib/components/lead-import-drawer.js.map +0 -1
  474. package/src/lib/components/lead-source-values-card.d.ts +0 -27
  475. package/src/lib/components/lead-source-values-card.js.map +0 -1
  476. package/src/lib/components/task-import-drawer.d.ts +0 -24
  477. package/src/lib/components/task-import-drawer.js +0 -82
  478. package/src/lib/components/task-import-drawer.js.map +0 -1
  479. package/src/lib/model/companies-csv.d.ts +0 -36
  480. package/src/lib/model/companies-csv.js +0 -38
  481. package/src/lib/model/companies-csv.js.map +0 -1
  482. package/src/lib/model/contacts-csv.d.ts +0 -54
  483. package/src/lib/model/contacts-csv.js +0 -67
  484. package/src/lib/model/contacts-csv.js.map +0 -1
  485. package/src/lib/model/crm-company-import.d.ts +0 -154
  486. package/src/lib/model/crm-company-import.js +0 -331
  487. package/src/lib/model/crm-company-import.js.map +0 -1
  488. package/src/lib/model/crm-csv.d.ts +0 -239
  489. package/src/lib/model/crm-csv.js +0 -467
  490. package/src/lib/model/crm-csv.js.map +0 -1
  491. package/src/lib/model/crm-deal-import.d.ts +0 -112
  492. package/src/lib/model/crm-deal-import.js +0 -263
  493. package/src/lib/model/crm-deal-import.js.map +0 -1
  494. package/src/lib/model/crm-import.d.ts +0 -250
  495. package/src/lib/model/crm-import.js +0 -467
  496. package/src/lib/model/crm-import.js.map +0 -1
  497. package/src/lib/model/crm-lead-import.d.ts +0 -138
  498. package/src/lib/model/crm-lead-import.js +0 -446
  499. package/src/lib/model/crm-lead-import.js.map +0 -1
  500. package/src/lib/model/crm-task-import.d.ts +0 -94
  501. package/src/lib/model/crm-task-import.js +0 -275
  502. package/src/lib/model/crm-task-import.js.map +0 -1
  503. package/src/lib/model/deals-csv.d.ts +0 -32
  504. package/src/lib/model/deals-csv.js +0 -36
  505. package/src/lib/model/deals-csv.js.map +0 -1
  506. package/src/lib/model/import-column-shapes.d.ts +0 -36
  507. package/src/lib/model/import-column-shapes.js +0 -76
  508. package/src/lib/model/import-column-shapes.js.map +0 -1
  509. package/src/lib/model/lead-source-values.d.ts +0 -82
  510. package/src/lib/model/lead-source-values.js +0 -149
  511. package/src/lib/model/lead-source-values.js.map +0 -1
  512. package/src/lib/model/leads-csv.d.ts +0 -40
  513. package/src/lib/model/leads-csv.js +0 -40
  514. package/src/lib/model/leads-csv.js.map +0 -1
  515. package/src/lib/model/tasks-csv.d.ts +0 -28
  516. package/src/lib/model/tasks-csv.js +0 -28
  517. package/src/lib/model/tasks-csv.js.map +0 -1
  518. package/src/lib/server/companies-import.d.ts +0 -57
  519. package/src/lib/server/companies-import.js +0 -242
  520. package/src/lib/server/companies-import.js.map +0 -1
  521. package/src/lib/server/contacts-import.d.ts +0 -109
  522. package/src/lib/server/contacts-import.js +0 -393
  523. package/src/lib/server/contacts-import.js.map +0 -1
  524. package/src/lib/server/deals-import.d.ts +0 -76
  525. package/src/lib/server/deals-import.js +0 -248
  526. package/src/lib/server/deals-import.js.map +0 -1
  527. package/src/lib/server/export-route.d.ts +0 -60
  528. package/src/lib/server/export-route.js +0 -447
  529. package/src/lib/server/export-route.js.map +0 -1
  530. package/src/lib/server/import-context.d.ts +0 -87
  531. package/src/lib/server/import-context.js +0 -182
  532. package/src/lib/server/import-context.js.map +0 -1
  533. package/src/lib/server/lead-source-values.d.ts +0 -50
  534. package/src/lib/server/lead-source-values.js +0 -191
  535. package/src/lib/server/lead-source-values.js.map +0 -1
  536. package/src/lib/server/leads-import.d.ts +0 -84
  537. package/src/lib/server/leads-import.js +0 -367
  538. package/src/lib/server/leads-import.js.map +0 -1
  539. package/src/lib/server/tasks-import.d.ts +0 -54
  540. package/src/lib/server/tasks-import.js +0 -160
  541. package/src/lib/server/tasks-import.js.map +0 -1
@@ -1,112 +0,0 @@
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 ImportChunkResult, type ImportDroppedValue } from '@aglyn/aglyn/app-utils/csv-import';
18
- /** The shared ceilings, under this collection's names. */
19
- export declare const DEAL_IMPORT_MAX_ROWS = 5000;
20
- export declare const DEAL_IMPORT_CHUNK_SIZE = 200;
21
- export declare const DEAL_IMPORT_MAX_BODY_BYTES = 2000000;
22
- export declare const DEAL_IMPORT_PREVIEW_ROWS = 10;
23
- /** The same caps the deal drawer holds a typed deal to. */
24
- export declare const DEAL_IMPORT_TITLE_MAX = 120;
25
- export declare const DEAL_IMPORT_NOTES_MAX = 4000;
26
- /** The most cents one row may carry — past this the number is a slip. */
27
- export declare const DEAL_IMPORT_AMOUNT_CENTS_MAX = 1000000000000;
28
- /** The fields a column may be mapped to, in the order the mapping menu lists them. */
29
- export declare const DEAL_IMPORT_FIELDS: readonly ["title", "pipeline", "stage", "amount", "currency", "ownerEmail", "expectedClose", "notes"];
30
- export type DealImportField = (typeof DEAL_IMPORT_FIELDS)[number];
31
- /** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */
32
- export declare const DEAL_IMPORT_FIELD_LABELS: Record<DealImportField, string>;
33
- /** Column index → field. A column absent from the map is not imported. */
34
- export type DealImportMapping = Record<number, DealImportField>;
35
- /** A proposed mapping from a file's header row, each field taken at most once. */
36
- export declare function guessDealImportMapping(columns: readonly string[]): DealImportMapping;
37
- /**
38
- * What the browser posts for one line: the cells the mapping selected,
39
- * under the field they were mapped to, verbatim. `unknown` because the
40
- * server reads this off an untrusted body.
41
- */
42
- export type DealImportRawRow = Partial<Record<DealImportField, unknown>>;
43
- /**
44
- * One parsed line under the mapping. Empty cells are left absent. A deal
45
- * has no custom fields yet, so a custom target the shared drawer could
46
- * name is dropped here rather than refused at the type.
47
- */
48
- export declare function mapDealImportRow(cells: readonly string[], mapping: Record<number, DealImportField | `custom:${string}`>): DealImportRawRow;
49
- export type DealImportSkipReason = 'missing-title' | 'unknown-pipeline' | 'unknown-stage' | 'records-band' | 'write-failed';
50
- /** How a skip reason reads on screen and in the downloaded file. */
51
- export declare const DEAL_IMPORT_SKIP_LABELS: Record<DealImportSkipReason, string>;
52
- /** One row, ready for the server to resolve and write. */
53
- export interface DealImportRow {
54
- title: string;
55
- /** The pipeline's name as typed, trimmed; absent means the default pipeline. */
56
- pipeline?: string;
57
- /** The stage's name as typed, trimmed; absent means the pipeline's first open stage. */
58
- stage?: string;
59
- amountCents?: number;
60
- /** Lowercase ISO 4217. */
61
- currency?: string;
62
- /** Normalized, for the server to resolve against the org's members. */
63
- ownerEmail?: string;
64
- /** Epoch ms at noon UTC of the typed calendar day, or the typed instant. */
65
- expectedCloseAtMs?: number;
66
- notes?: string;
67
- dropped: ImportDroppedValue[];
68
- }
69
- export type DealImportRowVerdict = {
70
- ok: true;
71
- row: DealImportRow;
72
- } | {
73
- ok: false;
74
- reason: 'missing-title';
75
- input: string;
76
- };
77
- /**
78
- * A money cell as cents — `1,250.00`, `$1250`, `1250` → 125000 — or
79
- * `null` when it is not a number. Rounded to the cent: a spreadsheet
80
- * that computed `12.345` meant a price, not a third of a cent.
81
- */
82
- export declare function parseImportAmountCents(value: unknown): number | null;
83
- /**
84
- * A date cell as epoch ms: a calendar day (`2026-09-30`) at noon UTC — a
85
- * day, not an instant, so any zone reads the same date back — or an ISO
86
- * instant as itself. `null` when it is neither.
87
- */
88
- export declare function parseImportDate(value: unknown): number | null;
89
- /**
90
- * One raw row as the values that will be written, or the reason it cannot
91
- * be. Refused here only for a missing title; the pipeline and the stage
92
- * are refused by the server, which alone can look them up; every other
93
- * unreadable cell is dropped and named.
94
- */
95
- export declare function normalizeDealImportRow(raw: DealImportRawRow): DealImportRowVerdict;
96
- /** A name as the key two spellings of one pipeline or stage meet at. */
97
- export declare function dealImportNameKey(name: string): string;
98
- /** One row the server did not store, by its index in the request, named by the deal. */
99
- export interface DealImportSkippedRow {
100
- index: number;
101
- title: string;
102
- reason: DealImportSkipReason;
103
- }
104
- /** What one request did. The drawer sums these across a file. */
105
- export type DealImportChunkResult = ImportChunkResult<DealImportSkippedRow>;
106
- export declare function emptyDealImportResult(): DealImportChunkResult;
107
- export declare function mergeDealImportResults(total: DealImportChunkResult, chunk: DealImportChunkResult, offset?: number): DealImportChunkResult;
108
- /** The skipped rows as a file the operator can fix and re-import. */
109
- export declare function dealImportSkippedCsv(columns: readonly string[], entries: readonly {
110
- cells: readonly string[];
111
- reason: DealImportSkipReason;
112
- }[]): string;
@@ -1,263 +0,0 @@
1
- import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
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
- * BRINGING A SPREADSHEET OF DEALS INTO THE CRM — the pure half (AGL-2662).
19
- *
20
- * The contact import's three stages (`crm-import.ts`) over the deal
21
- * vocabulary: a header row is matched to a proposed mapping, one line is
22
- * mapped to a raw row of verbatim strings, and the server normalizes each
23
- * row here before it resolves the two names a deal cannot be filed without.
24
- *
25
- * ## A deal names its pipeline and its stage by NAME
26
- *
27
- * A spreadsheet says "Sales" and "Proposal sent", never a document id, so
28
- * the file carries names and the server resolves them against the org's
29
- * own pipelines — case-insensitively, trimmed — and REFUSES the row, by
30
- * name, when it cannot: an unknown pipeline is `unknown-pipeline`, an
31
- * unknown stage in a known pipeline `unknown-stage`. A row with no
32
- * pipeline cell lands in the default pipeline, and one with no stage cell
33
- * in that pipeline's first open stage, the way the deal drawer opens.
34
- *
35
- * ## A deal has no key, so nothing is merged
36
- *
37
- * A contact is one address and a company one domain, but two deals titled
38
- * "Renewal" are two deals. Every row CREATES; importing a file twice files
39
- * it twice. What is refused is refused before any write.
40
- *
41
- * ## A bad cell is dropped and named; a bad row is skipped and named
42
- *
43
- * The contact import's rule: an amount that is not a number, a currency
44
- * that is not a code, a close date that is not a date, an owner address
45
- * that is not an address — each is left off the record and REPORTED under
46
- * {@link DealImportRow.dropped}, never silently discarded.
47
- */ import { normalizeContactEmail } from "@aglyn/aglyn/app-utils/contacts";
48
- import { CSV_IMPORT_CHUNK_SIZE, CSV_IMPORT_MAX_BODY_BYTES, CSV_IMPORT_MAX_ROWS, CSV_IMPORT_PREVIEW_ROWS, emptyImportResult, guessImportMapping, importAliasKeys, importSkippedCsv, importTextValue, mapImportRow, mergeImportResults } from "@aglyn/aglyn/app-utils/csv-import";
49
- /** The shared ceilings, under this collection's names. */ export const DEAL_IMPORT_MAX_ROWS = CSV_IMPORT_MAX_ROWS;
50
- export const DEAL_IMPORT_CHUNK_SIZE = CSV_IMPORT_CHUNK_SIZE;
51
- export const DEAL_IMPORT_MAX_BODY_BYTES = CSV_IMPORT_MAX_BODY_BYTES;
52
- export const DEAL_IMPORT_PREVIEW_ROWS = CSV_IMPORT_PREVIEW_ROWS;
53
- /** The same caps the deal drawer holds a typed deal to. */ export const DEAL_IMPORT_TITLE_MAX = 120;
54
- export const DEAL_IMPORT_NOTES_MAX = 4000;
55
- /** The most cents one row may carry — past this the number is a slip. */ export const DEAL_IMPORT_AMOUNT_CENTS_MAX = 1000000000000;
56
- /** The fields a column may be mapped to, in the order the mapping menu lists them. */ export const DEAL_IMPORT_FIELDS = [
57
- 'title',
58
- 'pipeline',
59
- 'stage',
60
- 'amount',
61
- 'currency',
62
- 'ownerEmail',
63
- 'expectedClose',
64
- 'notes'
65
- ];
66
- /** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */ export const DEAL_IMPORT_FIELD_LABELS = {
67
- title: 'Title (required)',
68
- pipeline: 'Pipeline (by name)',
69
- stage: 'Stage (by name)',
70
- amount: 'Amount (major units, 1250.00)',
71
- currency: 'Currency (three-letter code)',
72
- ownerEmail: 'Owner (team member email)',
73
- expectedClose: 'Expected close (YYYY-MM-DD)',
74
- notes: 'Notes'
75
- };
76
- /**
77
- * Header aliases per field, matched after the shared header normalization.
78
- *
79
- * First in each list is the header this CRM's own deals export writes, so
80
- * an export re-imports without a hand mapping; the export's Status,
81
- * Contact, Company, Closed and Lost reason columns are deliberately
82
- * absent, because the stage decides the status and a link is made on the
83
- * record, not from a file.
84
- */ const FIELD_ALIASES = {
85
- title: [
86
- 'title',
87
- 'deal',
88
- 'deal name',
89
- 'deal title',
90
- 'name',
91
- 'opportunity',
92
- 'opportunity name'
93
- ],
94
- pipeline: [
95
- 'pipeline',
96
- 'pipeline name',
97
- 'board'
98
- ],
99
- stage: [
100
- 'stage',
101
- 'stage name',
102
- 'deal stage',
103
- 'step'
104
- ],
105
- amount: [
106
- 'amount',
107
- 'value',
108
- 'deal value',
109
- 'deal amount',
110
- 'total',
111
- 'price'
112
- ],
113
- currency: [
114
- 'currency',
115
- 'currency code'
116
- ],
117
- ownerEmail: [
118
- 'owner',
119
- 'owner email',
120
- 'deal owner',
121
- 'assigned to',
122
- 'rep'
123
- ],
124
- expectedClose: [
125
- 'expected close',
126
- 'close date',
127
- 'expected close date',
128
- 'closing date',
129
- 'expected closing'
130
- ],
131
- notes: [
132
- 'notes',
133
- 'note',
134
- 'description',
135
- 'comments'
136
- ]
137
- };
138
- const FIELD_ALIAS_KEYS = importAliasKeys(DEAL_IMPORT_FIELDS, FIELD_ALIASES);
139
- /** A proposed mapping from a file's header row, each field taken at most once. */ export function guessDealImportMapping(columns) {
140
- return guessImportMapping(columns, DEAL_IMPORT_FIELDS, FIELD_ALIAS_KEYS);
141
- }
142
- /**
143
- * One parsed line under the mapping. Empty cells are left absent. A deal
144
- * has no custom fields yet, so a custom target the shared drawer could
145
- * name is dropped here rather than refused at the type.
146
- */ export function mapDealImportRow(cells, mapping) {
147
- const _mapImportRow = mapImportRow(cells, mapping), { custom: _custom } = _mapImportRow, row = _object_without_properties_loose(_mapImportRow, [
148
- "custom"
149
- ]);
150
- return row;
151
- }
152
- /** How a skip reason reads on screen and in the downloaded file. */ export const DEAL_IMPORT_SKIP_LABELS = {
153
- 'missing-title': 'No title',
154
- 'unknown-pipeline': 'No pipeline by that name',
155
- 'unknown-stage': 'No stage by that name in that pipeline',
156
- 'records-band': 'CRM records limit reached',
157
- 'write-failed': 'Could not be saved'
158
- };
159
- /**
160
- * A money cell as cents — `1,250.00`, `$1250`, `1250` → 125000 — or
161
- * `null` when it is not a number. Rounded to the cent: a spreadsheet
162
- * that computed `12.345` meant a price, not a third of a cent.
163
- */ export function parseImportAmountCents(value) {
164
- if (typeof value === 'number') {
165
- return Number.isFinite(value) && value >= 0 ? Math.round(value * 100) : null;
166
- }
167
- const text = String(value != null ? value : '').trim().replace(/[,\s]/g, '').replace(/^[^\d.-]+/, '');
168
- if (!/^\d+(\.\d+)?$/.test(text)) return null;
169
- const cents = Math.round(Number(text) * 100);
170
- return Number.isFinite(cents) && cents <= DEAL_IMPORT_AMOUNT_CENTS_MAX ? cents : null;
171
- }
172
- /**
173
- * A date cell as epoch ms: a calendar day (`2026-09-30`) at noon UTC — a
174
- * day, not an instant, so any zone reads the same date back — or an ISO
175
- * instant as itself. `null` when it is neither.
176
- */ export function parseImportDate(value) {
177
- const text = String(value != null ? value : '').trim();
178
- const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
179
- if (day) {
180
- const ms = Date.UTC(Number(day[1]), Number(day[2]) - 1, Number(day[3]), 12);
181
- // `Date.UTC` rolls February 30 into March; a typed day that moved is not a day.
182
- const back = new Date(ms);
183
- return back.getUTCMonth() === Number(day[2]) - 1 && back.getUTCDate() === Number(day[3]) ? ms : null;
184
- }
185
- if (!/^\d{4}-\d{2}-\d{2}T/.test(text)) return null;
186
- const ms = Date.parse(text);
187
- return Number.isFinite(ms) ? ms : null;
188
- }
189
- /**
190
- * One raw row as the values that will be written, or the reason it cannot
191
- * be. Refused here only for a missing title; the pipeline and the stage
192
- * are refused by the server, which alone can look them up; every other
193
- * unreadable cell is dropped and named.
194
- */ export function normalizeDealImportRow(raw) {
195
- var _importTextValue;
196
- const title = (_importTextValue = importTextValue(raw.title, DEAL_IMPORT_TITLE_MAX)) == null ? void 0 : _importTextValue.replace(/\s+/g, ' ');
197
- if (!title) {
198
- return {
199
- ok: false,
200
- reason: 'missing-title',
201
- input: ''
202
- };
203
- }
204
- const dropped = [];
205
- const drop = (field, value)=>{
206
- dropped.push({
207
- field,
208
- value: String(value != null ? value : '').trim()
209
- });
210
- };
211
- const row = {
212
- title,
213
- dropped
214
- };
215
- const pipeline = importTextValue(raw.pipeline, 120);
216
- if (pipeline) row.pipeline = pipeline;
217
- const stage = importTextValue(raw.stage, 120);
218
- if (stage) row.stage = stage;
219
- const amountText = importTextValue(raw.amount, 64);
220
- if (amountText) {
221
- const cents = parseImportAmountCents(amountText);
222
- if (cents !== null) row.amountCents = cents;
223
- else drop('amount', amountText);
224
- }
225
- const currencyText = importTextValue(raw.currency, 16);
226
- if (currencyText) {
227
- const code = currencyText.toLowerCase();
228
- if (/^[a-z]{3}$/.test(code)) row.currency = code;
229
- else drop('currency', currencyText);
230
- }
231
- const ownerText = importTextValue(raw.ownerEmail, 320);
232
- if (ownerText) {
233
- const owner = normalizeContactEmail(ownerText);
234
- if (owner) row.ownerEmail = owner;
235
- else drop('ownerEmail', ownerText);
236
- }
237
- const closeText = importTextValue(raw.expectedClose, 64);
238
- if (closeText) {
239
- const ms = parseImportDate(closeText);
240
- if (ms !== null) row.expectedCloseAtMs = ms;
241
- else drop('expectedClose', closeText);
242
- }
243
- const notes = importTextValue(raw.notes, DEAL_IMPORT_NOTES_MAX);
244
- if (notes) row.notes = notes;
245
- return {
246
- ok: true,
247
- row
248
- };
249
- }
250
- /** A name as the key two spellings of one pipeline or stage meet at. */ export function dealImportNameKey(name) {
251
- return name.trim().replace(/\s+/g, ' ').toLowerCase();
252
- }
253
- export function emptyDealImportResult() {
254
- return emptyImportResult();
255
- }
256
- export function mergeDealImportResults(total, chunk, offset = 0) {
257
- return mergeImportResults(total, chunk, offset);
258
- }
259
- /** The skipped rows as a file the operator can fix and re-import. */ export function dealImportSkippedCsv(columns, entries) {
260
- return importSkippedCsv(columns, entries, DEAL_IMPORT_SKIP_LABELS);
261
- }
262
-
263
- //# sourceMappingURL=crm-deal-import.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-deal-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 DEALS INTO THE CRM — the pure half (AGL-2662).\n *\n * The contact import's three stages (`crm-import.ts`) over the deal\n * vocabulary: a header row is matched to a proposed mapping, one line is\n * mapped to a raw row of verbatim strings, and the server normalizes each\n * row here before it resolves the two names a deal cannot be filed without.\n *\n * ## A deal names its pipeline and its stage by NAME\n *\n * A spreadsheet says \"Sales\" and \"Proposal sent\", never a document id, so\n * the file carries names and the server resolves them against the org's\n * own pipelines — case-insensitively, trimmed — and REFUSES the row, by\n * name, when it cannot: an unknown pipeline is `unknown-pipeline`, an\n * unknown stage in a known pipeline `unknown-stage`. A row with no\n * pipeline cell lands in the default pipeline, and one with no stage cell\n * in that pipeline's first open stage, the way the deal drawer opens.\n *\n * ## A deal has no key, so nothing is merged\n *\n * A contact is one address and a company one domain, but two deals titled\n * \"Renewal\" are two deals. Every row CREATES; importing a file twice files\n * it twice. What is refused is refused before any write.\n *\n * ## A bad cell is dropped and named; a bad row is skipped and named\n *\n * The contact import's rule: an amount that is not a number, a currency\n * that is not a code, a close date that is not a date, an owner address\n * that is not an address — each is left off the record and REPORTED under\n * {@link DealImportRow.dropped}, never silently discarded.\n */\n\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 emptyImportResult,\n guessImportMapping,\n importAliasKeys,\n type ImportChunkResult,\n type ImportDroppedValue,\n importSkippedCsv,\n importTextValue,\n mapImportRow,\n mergeImportResults,\n} from '@aglyn/aglyn/app-utils/csv-import'\n\n/** The shared ceilings, under this collection's names. */\nexport const DEAL_IMPORT_MAX_ROWS = CSV_IMPORT_MAX_ROWS\nexport const DEAL_IMPORT_CHUNK_SIZE = CSV_IMPORT_CHUNK_SIZE\nexport const DEAL_IMPORT_MAX_BODY_BYTES = CSV_IMPORT_MAX_BODY_BYTES\nexport const DEAL_IMPORT_PREVIEW_ROWS = CSV_IMPORT_PREVIEW_ROWS\n\n/** The same caps the deal drawer holds a typed deal to. */\nexport const DEAL_IMPORT_TITLE_MAX = 120\nexport const DEAL_IMPORT_NOTES_MAX = 4000\n/** The most cents one row may carry — past this the number is a slip. */\nexport const DEAL_IMPORT_AMOUNT_CENTS_MAX = 1_000_000_000_000\n\n/** The fields a column may be mapped to, in the order the mapping menu lists them. */\nexport const DEAL_IMPORT_FIELDS = [\n 'title',\n 'pipeline',\n 'stage',\n 'amount',\n 'currency',\n 'ownerEmail',\n 'expectedClose',\n 'notes',\n] as const\n\nexport type DealImportField = (typeof DEAL_IMPORT_FIELDS)[number]\n\n/** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */\nexport const DEAL_IMPORT_FIELD_LABELS: Record<DealImportField, string> = {\n title: 'Title (required)',\n pipeline: 'Pipeline (by name)',\n stage: 'Stage (by name)',\n amount: 'Amount (major units, 1250.00)',\n currency: 'Currency (three-letter code)',\n ownerEmail: 'Owner (team member email)',\n expectedClose: 'Expected close (YYYY-MM-DD)',\n notes: 'Notes',\n}\n\n/**\n * Header aliases per field, matched after the shared header normalization.\n *\n * First in each list is the header this CRM's own deals export writes, so\n * an export re-imports without a hand mapping; the export's Status,\n * Contact, Company, Closed and Lost reason columns are deliberately\n * absent, because the stage decides the status and a link is made on the\n * record, not from a file.\n */\nconst FIELD_ALIASES: Record<DealImportField, readonly string[]> = {\n title: ['title', 'deal', 'deal name', 'deal title', 'name', 'opportunity', 'opportunity name'],\n pipeline: ['pipeline', 'pipeline name', 'board'],\n stage: ['stage', 'stage name', 'deal stage', 'step'],\n amount: ['amount', 'value', 'deal value', 'deal amount', 'total', 'price'],\n currency: ['currency', 'currency code'],\n ownerEmail: ['owner', 'owner email', 'deal owner', 'assigned to', 'rep'],\n expectedClose: ['expected close', 'close date', 'expected close date', 'closing date', 'expected closing'],\n notes: ['notes', 'note', 'description', 'comments'],\n}\n\nconst FIELD_ALIAS_KEYS = importAliasKeys(DEAL_IMPORT_FIELDS, FIELD_ALIASES)\n\n/** Column index → field. A column absent from the map is not imported. */\nexport type DealImportMapping = Record<number, DealImportField>\n\n/** A proposed mapping from a file's header row, each field taken at most once. */\nexport function guessDealImportMapping(columns: readonly string[]): DealImportMapping {\n return guessImportMapping(columns, DEAL_IMPORT_FIELDS, FIELD_ALIAS_KEYS)\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. `unknown` because the\n * server reads this off an untrusted body.\n */\nexport type DealImportRawRow = Partial<Record<DealImportField, unknown>>\n\n/**\n * One parsed line under the mapping. Empty cells are left absent. A deal\n * has no custom fields yet, so a custom target the shared drawer could\n * name is dropped here rather than refused at the type.\n */\nexport function mapDealImportRow(\n cells: readonly string[],\n mapping: Record<number, DealImportField | `custom:${string}`>,\n): DealImportRawRow {\n const { custom: _custom, ...row } = mapImportRow(cells, mapping)\n return row\n}\n\nexport type DealImportSkipReason =\n | 'missing-title'\n | 'unknown-pipeline'\n | 'unknown-stage'\n | 'records-band'\n | 'write-failed'\n\n/** How a skip reason reads on screen and in the downloaded file. */\nexport const DEAL_IMPORT_SKIP_LABELS: Record<DealImportSkipReason, string> = {\n 'missing-title': 'No title',\n 'unknown-pipeline': 'No pipeline by that name',\n 'unknown-stage': 'No stage by that name in that pipeline',\n 'records-band': 'CRM records limit reached',\n 'write-failed': 'Could not be saved',\n}\n\n/** One row, ready for the server to resolve and write. */\nexport interface DealImportRow {\n title: string\n /** The pipeline's name as typed, trimmed; absent means the default pipeline. */\n pipeline?: string\n /** The stage's name as typed, trimmed; absent means the pipeline's first open stage. */\n stage?: string\n amountCents?: number\n /** Lowercase ISO 4217. */\n currency?: string\n /** Normalized, for the server to resolve against the org's members. */\n ownerEmail?: string\n /** Epoch ms at noon UTC of the typed calendar day, or the typed instant. */\n expectedCloseAtMs?: number\n notes?: string\n dropped: ImportDroppedValue[]\n}\n\nexport type DealImportRowVerdict =\n | { ok: true; row: DealImportRow }\n | { ok: false; reason: 'missing-title'; input: string }\n\n/**\n * A money cell as cents — `1,250.00`, `$1250`, `1250` → 125000 — or\n * `null` when it is not a number. Rounded to the cent: a spreadsheet\n * that computed `12.345` meant a price, not a third of a cent.\n */\nexport function parseImportAmountCents(value: unknown): number | null {\n if (typeof value === 'number') {\n return Number.isFinite(value) && value >= 0 ? Math.round(value * 100) : null\n }\n const text = String(value ?? '')\n .trim()\n .replace(/[,\\s]/g, '')\n .replace(/^[^\\d.-]+/, '')\n if (!/^\\d+(\\.\\d+)?$/.test(text)) return null\n const cents = Math.round(Number(text) * 100)\n return Number.isFinite(cents) && cents <= DEAL_IMPORT_AMOUNT_CENTS_MAX ? cents : null\n}\n\n/**\n * A date cell as epoch ms: a calendar day (`2026-09-30`) at noon UTC — a\n * day, not an instant, so any zone reads the same date back — or an ISO\n * instant as itself. `null` when it is neither.\n */\nexport function parseImportDate(value: unknown): number | null {\n const text = String(value ?? '').trim()\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(text)\n if (day) {\n const ms = Date.UTC(Number(day[1]), Number(day[2]) - 1, Number(day[3]), 12)\n // `Date.UTC` rolls February 30 into March; a typed day that moved is not a day.\n const back = new Date(ms)\n return back.getUTCMonth() === Number(day[2]) - 1 && back.getUTCDate() === Number(day[3])\n ? ms\n : null\n }\n if (!/^\\d{4}-\\d{2}-\\d{2}T/.test(text)) return null\n const ms = Date.parse(text)\n return Number.isFinite(ms) ? ms : null\n}\n\n/**\n * One raw row as the values that will be written, or the reason it cannot\n * be. Refused here only for a missing title; the pipeline and the stage\n * are refused by the server, which alone can look them up; every other\n * unreadable cell is dropped and named.\n */\nexport function normalizeDealImportRow(raw: DealImportRawRow): DealImportRowVerdict {\n const title = importTextValue(raw.title, DEAL_IMPORT_TITLE_MAX)?.replace(/\\s+/g, ' ')\n if (!title) {\n return { ok: false, reason: 'missing-title', input: '' }\n }\n const dropped: ImportDroppedValue[] = []\n const drop = (field: DealImportField, value: unknown) => {\n dropped.push({ field, value: String(value ?? '').trim() })\n }\n const row: DealImportRow = { title, dropped }\n\n const pipeline = importTextValue(raw.pipeline, 120)\n if (pipeline) row.pipeline = pipeline\n const stage = importTextValue(raw.stage, 120)\n if (stage) row.stage = stage\n\n const amountText = importTextValue(raw.amount, 64)\n if (amountText) {\n const cents = parseImportAmountCents(amountText)\n if (cents !== null) row.amountCents = cents\n else drop('amount', amountText)\n }\n\n const currencyText = importTextValue(raw.currency, 16)\n if (currencyText) {\n const code = currencyText.toLowerCase()\n if (/^[a-z]{3}$/.test(code)) row.currency = code\n else drop('currency', currencyText)\n }\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 closeText = importTextValue(raw.expectedClose, 64)\n if (closeText) {\n const ms = parseImportDate(closeText)\n if (ms !== null) row.expectedCloseAtMs = ms\n else drop('expectedClose', closeText)\n }\n\n const notes = importTextValue(raw.notes, DEAL_IMPORT_NOTES_MAX)\n if (notes) row.notes = notes\n\n return { ok: true, row }\n}\n\n/** A name as the key two spellings of one pipeline or stage meet at. */\nexport function dealImportNameKey(name: string): string {\n return name.trim().replace(/\\s+/g, ' ').toLowerCase()\n}\n\n/** One row the server did not store, by its index in the request, named by the deal. */\nexport interface DealImportSkippedRow {\n index: number\n title: string\n reason: DealImportSkipReason\n}\n\n/** What one request did. The drawer sums these across a file. */\nexport type DealImportChunkResult = ImportChunkResult<DealImportSkippedRow>\n\nexport function emptyDealImportResult(): DealImportChunkResult {\n return emptyImportResult<DealImportSkippedRow>()\n}\n\nexport function mergeDealImportResults(\n total: DealImportChunkResult,\n chunk: DealImportChunkResult,\n offset = 0,\n): DealImportChunkResult {\n return mergeImportResults(total, chunk, offset)\n}\n\n/** The skipped rows as a file the operator can fix and re-import. */\nexport function dealImportSkippedCsv(\n columns: readonly string[],\n entries: readonly { cells: readonly string[]; reason: DealImportSkipReason }[],\n): string {\n return importSkippedCsv(columns, entries, DEAL_IMPORT_SKIP_LABELS)\n}\n"],"names":["normalizeContactEmail","CSV_IMPORT_CHUNK_SIZE","CSV_IMPORT_MAX_BODY_BYTES","CSV_IMPORT_MAX_ROWS","CSV_IMPORT_PREVIEW_ROWS","emptyImportResult","guessImportMapping","importAliasKeys","importSkippedCsv","importTextValue","mapImportRow","mergeImportResults","DEAL_IMPORT_MAX_ROWS","DEAL_IMPORT_CHUNK_SIZE","DEAL_IMPORT_MAX_BODY_BYTES","DEAL_IMPORT_PREVIEW_ROWS","DEAL_IMPORT_TITLE_MAX","DEAL_IMPORT_NOTES_MAX","DEAL_IMPORT_AMOUNT_CENTS_MAX","DEAL_IMPORT_FIELDS","DEAL_IMPORT_FIELD_LABELS","title","pipeline","stage","amount","currency","ownerEmail","expectedClose","notes","FIELD_ALIASES","FIELD_ALIAS_KEYS","guessDealImportMapping","columns","mapDealImportRow","cells","mapping","custom","_custom","row","DEAL_IMPORT_SKIP_LABELS","parseImportAmountCents","value","Number","isFinite","Math","round","text","String","trim","replace","test","cents","parseImportDate","day","exec","ms","Date","UTC","back","getUTCMonth","getUTCDate","parse","normalizeDealImportRow","raw","ok","reason","input","dropped","drop","field","push","amountText","amountCents","currencyText","code","toLowerCase","ownerText","owner","closeText","expectedCloseAtMs","dealImportNameKey","name","emptyDealImportResult","mergeDealImportResults","total","chunk","offset","dealImportSkippedCsv","entries"],"mappings":"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"}
@@ -1,250 +0,0 @@
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
- * BRINGING A SPREADSHEET OF PEOPLE INTO THE CRM — the pure half (AGL-2602).
19
- *
20
- * A merchant arriving from another CRM has a CSV: a header row naming
21
- * columns in that product's vocabulary, and one person per line. Nothing
22
- * about that file is in our shape. This module is every decision about the
23
- * file that needs no Firestore and no React — which columns mean what, how a
24
- * cell becomes a stored value, and what to say about a row that cannot be
25
- * stored — so that the console drawer and the server route read the same
26
- * rules rather than two copies of them.
27
- *
28
- * ## Three stages, and only the last one touches a record
29
- *
30
- * 1. {@link guessContactImportMapping} reads the header and proposes a
31
- * column → field mapping from a table of aliases. It is a PROPOSAL: the
32
- * drawer shows it and the operator corrects it, because an export's
33
- * "Company" column may hold a job title and no alias table can know.
34
- * 2. {@link mapContactImportRow} applies the mapping to one line, producing
35
- * the raw row the browser posts. Strings only — the browser trims nothing
36
- * and validates nothing, so the server is the one place the file is
37
- * judged and a stale drawer cannot judge it differently.
38
- * 3. {@link normalizeContactImportRow} turns a raw row into the values that
39
- * will be written, through the SAME normalizers every other door uses:
40
- * `normalizeContactEmail` for the dedupe key, `normalizePhone` for E.164,
41
- * `normalizeAddress` for the postal shape, `isContactLifecycleStage` for
42
- * the stage. An importer with its own idea of a valid phone number is how
43
- * one collection ends up storing a value three ways.
44
- *
45
- * ## A bad cell is dropped and named; a bad row is skipped and named
46
- *
47
- * The only thing that makes a row unstorable is an unusable address, because
48
- * the address is the identity the shared row is keyed by. Everything else is
49
- * a value on the row: a phone that cannot be read as a number is left off
50
- * the contact and REPORTED under {@link ContactImportRow.dropped}, so the
51
- * operator learns that forty rows had a phone in a format we could not read
52
- * rather than discovering, weeks later, that the phone column silently went
53
- * nowhere. `list-import.ts` applies the same rule to a line that is not an
54
- * address: reported, never quietly discarded.
55
- *
56
- * ## Ceilings are on the work, never on the audience
57
- *
58
- * {@link CONTACT_IMPORT_MAX_ROWS} bounds one FILE, and the drawer says so
59
- * before anything is sent. {@link CONTACT_IMPORT_CHUNK_SIZE} bounds one
60
- * REQUEST, so a five-thousand-row file is twenty-five requests with a
61
- * progress bar between them rather than one that times out halfway with no
62
- * record of what it did. Neither one ever trims a person to fit: a row past
63
- * the file ceiling is refused with the file, and a row is never dropped to
64
- * make a chunk smaller. The audience band is enforced where every capture
65
- * enforces it — inside `upsertHostContact` — and an import reports that
66
- * refusal per row rather than pre-empting it with a count of its own.
67
- */
68
- import type { AglynPostalAddress } from '@aglyn/aglyn/foundation/definitions/contact.types';
69
- import { type ImportChunkResult, type ImportDroppedValue } from '@aglyn/aglyn/app-utils/csv-import';
70
- import { type ContactCustomValue, type ContactFieldDefinition, type ContactLifecycleStage } from '@aglyn/aglyn/app-utils/crm';
71
- export { customImportTarget, customImportTargetKey } from '@aglyn/aglyn/app-utils/csv-import';
72
- /**
73
- * The ceilings are the shared ones (`csv-import.ts`), under the names this
74
- * file has always exported: one file, one request and one preview are
75
- * bounded the same way for every collection, because the bounds are about
76
- * the browser's memory and a request's budget rather than about people.
77
- */
78
- export declare const CONTACT_IMPORT_MAX_ROWS = 5000;
79
- export declare const CONTACT_IMPORT_CHUNK_SIZE = 200;
80
- export declare const CONTACT_IMPORT_MAX_BODY_BYTES = 2000000;
81
- export declare const CONTACT_IMPORT_PREVIEW_ROWS = 10;
82
- /**
83
- * The most tags one row may carry — the profile drawer's own cap, so an
84
- * imported person cannot hold more tags than a hand-edited one.
85
- */
86
- export declare const CONTACT_IMPORT_TAGS_MAX = 20;
87
- /**
88
- * The standard fields a column may be mapped to, in the order the mapping
89
- * menu lists them. A custom field is mapped by its key — see
90
- * {@link ContactImportTargetId}.
91
- */
92
- export declare const CONTACT_IMPORT_FIELDS: readonly ["email", "name", "phone", "jobTitle", "companyName", "addressLine1", "addressLine2", "addressCity", "addressState", "addressPostalCode", "addressCountry", "tags", "ownerEmail", "lifecycleStage", "marketingConsent"];
93
- export type ContactImportField = (typeof CONTACT_IMPORT_FIELDS)[number];
94
- /** How each field reads in the mapping menu. Typed so a field cannot ship unlabeled. */
95
- export declare const CONTACT_IMPORT_FIELD_LABELS: Record<ContactImportField, string>;
96
- /**
97
- * What a column is mapped to: a standard field by name, or a custom field
98
- * as `custom:<key>` — see `customImportTarget`.
99
- */
100
- export type ContactImportTargetId = ContactImportField | `custom:${string}`;
101
- /** Column index → target. A column absent from the map is not imported. */
102
- export type ContactImportMapping = Record<number, ContactImportTargetId>;
103
- /**
104
- * A proposed mapping from a file's header row — the shared matcher over the
105
- * contact vocabulary. Custom fields win over standard aliases when a header
106
- * matches a definition's label or key exactly: a merchant who defined a
107
- * field called "Status" meant THEIR status, not our lifecycle stage.
108
- */
109
- export declare function guessContactImportMapping(columns: readonly string[], fields?: readonly Pick<ContactFieldDefinition, 'key' | 'label'>[]): ContactImportMapping;
110
- /**
111
- * What the browser posts for one line: the cells the mapping selected,
112
- * under the field they were mapped to, verbatim.
113
- *
114
- * Values are `unknown` because the server reads this off an untrusted body;
115
- * the mapper below only ever writes strings into it.
116
- */
117
- export interface ContactImportRawRow {
118
- email?: unknown;
119
- name?: unknown;
120
- phone?: unknown;
121
- jobTitle?: unknown;
122
- companyName?: unknown;
123
- addressLine1?: unknown;
124
- addressLine2?: unknown;
125
- addressCity?: unknown;
126
- addressState?: unknown;
127
- addressPostalCode?: unknown;
128
- addressCountry?: unknown;
129
- tags?: unknown;
130
- ownerEmail?: unknown;
131
- lifecycleStage?: unknown;
132
- marketingConsent?: unknown;
133
- /** Custom values keyed by definition key. */
134
- custom?: unknown;
135
- }
136
- /** One parsed line under the mapping. Empty cells are left absent. */
137
- export declare function mapContactImportRow(cells: readonly string[], mapping: ContactImportMapping): ContactImportRawRow;
138
- /** Why one row was not stored. */
139
- export type ContactImportSkipReason = 'invalid-email' | 'duplicate' | 'audience-band'
140
- /** The person was erased from this workspace at their request (AGL-2623). */
141
- | 'erased' | 'write-failed'
142
- /**
143
- * The request ran out of time before it reached the row (AGL-3423). Nothing
144
- * was written for it, and importing the skipped file again is safe: a row
145
- * that did land merges into its record rather than creating a second one.
146
- */
147
- | 'not-reached';
148
- /** How a skip reason reads on screen and in the downloaded file. */
149
- export declare const CONTACT_IMPORT_SKIP_LABELS: Record<ContactImportSkipReason, string>;
150
- /** A cell the file carried that could not be read as the field it was mapped to. */
151
- export type ContactImportDroppedValue = ImportDroppedValue;
152
- /** One row, ready to be written. */
153
- export interface ContactImportRow {
154
- email: string;
155
- name?: string;
156
- /** E.164. */
157
- phone?: string;
158
- jobTitle?: string;
159
- companyName?: string;
160
- address?: AglynPostalAddress;
161
- /** Lowercased, deduplicated, capped at {@link CONTACT_IMPORT_TAGS_MAX}. */
162
- tags: string[];
163
- /** Normalized, for the server to resolve against the org's members. */
164
- ownerEmail?: string;
165
- lifecycleStage?: ContactLifecycleStage;
166
- marketingConsent: boolean;
167
- /** Only the keys whose definition the caller supplied and whose value read. */
168
- custom: Record<string, ContactCustomValue>;
169
- dropped: ContactImportDroppedValue[];
170
- }
171
- export type ContactImportRowVerdict = {
172
- ok: true;
173
- row: ContactImportRow;
174
- } | {
175
- ok: false;
176
- reason: 'invalid-email';
177
- input: string;
178
- };
179
- /**
180
- * A tag cell as the tags it names.
181
- *
182
- * `|` or `,` separated — the CSV export writes `|`, most other products
183
- * write `,` — lowercased and trimmed like the profile drawer's own tag
184
- * field, so an imported `VIP` and a typed `vip` are one tag and not two.
185
- */
186
- export declare function parseContactImportTags(value: unknown): string[];
187
- /**
188
- * A yes/no cell as a boolean, or `null` when it is neither.
189
- *
190
- * The affirmatives are the ones consent and checkbox columns actually
191
- * carry; the negatives are listed so that an explicit `no` is a `false`
192
- * rather than an unreadable value that gets reported as dropped.
193
- */
194
- export declare function parseContactImportFlag(value: unknown): boolean | null;
195
- /**
196
- * A stage cell as a stage, accepting the stored id (`sales-qualified`), its
197
- * label ("Sales qualified") and the spellings between them
198
- * (`Sales_Qualified`), or `null` when it names none of them.
199
- */
200
- export declare function parseContactImportLifecycleStage(value: unknown): ContactLifecycleStage | null;
201
- /**
202
- * A cell as the value a custom field of this type stores.
203
- *
204
- * `{ value }` when it read, `{ value: undefined }` for a blank cell (nothing
205
- * to write and nothing to report), and `null` when the cell held something
206
- * the type cannot hold — a word in a number field, a choice a select does
207
- * not offer. A date is stored as epoch milliseconds, the shape every other
208
- * timestamp on a CRM record takes (`dueAtMs`, `expectedCloseAtMs`).
209
- */
210
- export declare function parseContactImportCustomValue(definition: Pick<ContactFieldDefinition, 'type' | 'options'>, value: unknown): {
211
- value: ContactCustomValue | undefined;
212
- } | null;
213
- /**
214
- * One raw row as the values that will be written, or the reason it cannot
215
- * be.
216
- *
217
- * `fields` is the holder's live definitions: a custom value under a key
218
- * with no definition is dropped and reported, because a value nobody
219
- * defined a field for is a value no form will ever show.
220
- */
221
- export declare function normalizeContactImportRow(raw: ContactImportRawRow, fields?: readonly Pick<ContactFieldDefinition, 'key' | 'type' | 'options'>[]): ContactImportRowVerdict;
222
- /** One row the server did not store, by its index in the request, named by address. */
223
- export interface ContactImportSkippedRow {
224
- index: number;
225
- email: string;
226
- reason: ContactImportSkipReason;
227
- }
228
- /**
229
- * What one request did — the shared tally plus how many companies the
230
- * company column brought into being. The drawer sums these across a file.
231
- */
232
- export interface ContactImportChunkResult extends ImportChunkResult<ContactImportSkippedRow> {
233
- companiesCreated: number;
234
- }
235
- /** An empty tally, for the drawer to fold chunk results into. */
236
- export declare function emptyContactImportResult(): ContactImportChunkResult;
237
- /**
238
- * Two results as one — the shared fold, with the company tally beside it.
239
- * `offset` is where the chunk started in the file, so a skipped row's index
240
- * comes back as its position in the FILE rather than in the request.
241
- */
242
- export declare function mergeContactImportResults(total: ContactImportChunkResult, chunk: ContactImportChunkResult, offset?: number): ContactImportChunkResult;
243
- /**
244
- * The skipped rows as a file the operator can fix and re-import: the
245
- * original columns verbatim plus a trailing `Skipped because` column.
246
- */
247
- export declare function contactImportSkippedCsv(columns: readonly string[], entries: readonly {
248
- cells: readonly string[];
249
- reason: ContactImportSkipReason;
250
- }[]): string;