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

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 (514) 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-record-picker.d.ts +15 -0
  34. package/src/lib/components/crm-record-picker.js +16 -10
  35. package/src/lib/components/crm-record-picker.js.map +1 -1
  36. package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
  37. package/src/lib/components/crm-transfer-buttons.js +167 -0
  38. package/src/lib/components/crm-transfer-buttons.js.map +1 -0
  39. package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
  40. package/src/lib/components/deal-contact-roles-card.js +368 -0
  41. package/src/lib/components/deal-contact-roles-card.js.map +1 -0
  42. package/src/lib/components/deal-detail-page.d.ts +3 -2
  43. package/src/lib/components/deal-detail-page.js +25 -6
  44. package/src/lib/components/deal-detail-page.js.map +1 -1
  45. package/src/lib/components/deal-edit-drawer.d.ts +10 -0
  46. package/src/lib/components/deal-edit-drawer.js +219 -10
  47. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  48. package/src/lib/components/deal-properties-card.d.ts +7 -0
  49. package/src/lib/components/deal-properties-card.js +34 -3
  50. package/src/lib/components/deal-properties-card.js.map +1 -1
  51. package/src/lib/components/deal-stage-card.d.ts +4 -0
  52. package/src/lib/components/deal-stage-card.js +10 -2
  53. package/src/lib/components/deal-stage-card.js.map +1 -1
  54. package/src/lib/components/deals-bulk-bar.d.ts +0 -3
  55. package/src/lib/components/deals-bulk-bar.js +7 -20
  56. package/src/lib/components/deals-bulk-bar.js.map +1 -1
  57. package/src/lib/components/deals-section.d.ts +3 -3
  58. package/src/lib/components/deals-section.js +123 -63
  59. package/src/lib/components/deals-section.js.map +1 -1
  60. package/src/lib/components/fields-section.js +31 -17
  61. package/src/lib/components/fields-section.js.map +1 -1
  62. package/src/lib/components/lead-convert-dialog.d.ts +4 -0
  63. package/src/lib/components/lead-convert-dialog.js +23 -1
  64. package/src/lib/components/lead-convert-dialog.js.map +1 -1
  65. package/src/lib/components/lead-detail-page.js +8 -2
  66. package/src/lib/components/lead-detail-page.js.map +1 -1
  67. package/src/lib/components/lead-profile-fields.d.ts +71 -0
  68. package/src/lib/components/lead-profile-fields.js +386 -0
  69. package/src/lib/components/lead-profile-fields.js.map +1 -0
  70. package/src/lib/components/lead-properties-card.d.ts +2 -1
  71. package/src/lib/components/lead-properties-card.js +85 -176
  72. package/src/lib/components/lead-properties-card.js.map +1 -1
  73. package/src/lib/components/lead-source-select.d.ts +4 -23
  74. package/src/lib/components/lead-source-select.js +9 -73
  75. package/src/lib/components/lead-source-select.js.map +1 -1
  76. package/src/lib/components/lead-status-chip.d.ts +9 -3
  77. package/src/lib/components/lead-status-chip.js +8 -4
  78. package/src/lib/components/lead-status-chip.js.map +1 -1
  79. package/src/lib/components/lead-status-options.d.ts +20 -0
  80. package/src/lib/components/lead-status-options.js +51 -0
  81. package/src/lib/components/lead-status-options.js.map +1 -0
  82. package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
  83. package/src/lib/components/lead-unqualify-dialog.js +50 -18
  84. package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
  85. package/src/lib/components/leads-bulk-bar.d.ts +0 -3
  86. package/src/lib/components/leads-bulk-bar.js +29 -29
  87. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  88. package/src/lib/components/leads-section.js +120 -68
  89. package/src/lib/components/leads-section.js.map +1 -1
  90. package/src/lib/components/linked-deals-card.d.ts +4 -0
  91. package/src/lib/components/linked-deals-card.js +47 -3
  92. package/src/lib/components/linked-deals-card.js.map +1 -1
  93. package/src/lib/components/log-activity-dialog.js +43 -3
  94. package/src/lib/components/log-activity-dialog.js.map +1 -1
  95. package/src/lib/components/new-contact-drawer.d.ts +8 -0
  96. package/src/lib/components/new-contact-drawer.js +108 -6
  97. package/src/lib/components/new-contact-drawer.js.map +1 -1
  98. package/src/lib/components/new-lead-drawer.d.ts +9 -2
  99. package/src/lib/components/new-lead-drawer.js +88 -121
  100. package/src/lib/components/new-lead-drawer.js.map +1 -1
  101. package/src/lib/components/picklist-select.d.ts +36 -0
  102. package/src/lib/components/picklist-select.js +114 -0
  103. package/src/lib/components/picklist-select.js.map +1 -0
  104. package/src/lib/components/picklist-values-card.d.ts +34 -0
  105. package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
  106. package/src/lib/components/picklist-values-card.js.map +1 -0
  107. package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
  108. package/src/lib/components/pipeline-stages-dialog.js +26 -4
  109. package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
  110. package/src/lib/components/pipelines-dialog.js +15 -6
  111. package/src/lib/components/pipelines-dialog.js.map +1 -1
  112. package/src/lib/components/recent-activity-feed.js +20 -5
  113. package/src/lib/components/recent-activity-feed.js.map +1 -1
  114. package/src/lib/components/recipes-card.js +4 -2
  115. package/src/lib/components/recipes-card.js.map +1 -1
  116. package/src/lib/components/record-tasks-card.js +15 -8
  117. package/src/lib/components/record-tasks-card.js.map +1 -1
  118. package/src/lib/components/reports/forecast-card.d.ts +6 -0
  119. package/src/lib/components/reports/forecast-card.js +101 -3
  120. package/src/lib/components/reports/forecast-card.js.map +1 -1
  121. package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
  122. package/src/lib/components/reports/lead-funnel-card.js +9 -5
  123. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  124. package/src/lib/components/reports/lead-source-card.d.ts +23 -0
  125. package/src/lib/components/reports/lead-source-card.js +318 -0
  126. package/src/lib/components/reports/lead-source-card.js.map +1 -0
  127. package/src/lib/components/reports/report-export.js +1 -1
  128. package/src/lib/components/reports/report-export.js.map +1 -1
  129. package/src/lib/components/reports-section.js +8 -0
  130. package/src/lib/components/reports-section.js.map +1 -1
  131. package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
  132. package/src/lib/components/sharing-rule-drawer.js +108 -19
  133. package/src/lib/components/sharing-rule-drawer.js.map +1 -1
  134. package/src/lib/components/sharing-rules-card.js +11 -3
  135. package/src/lib/components/sharing-rules-card.js.map +1 -1
  136. package/src/lib/components/task-cells.d.ts +9 -1
  137. package/src/lib/components/task-cells.js +9 -4
  138. package/src/lib/components/task-cells.js.map +1 -1
  139. package/src/lib/components/task-edit-drawer.js +111 -43
  140. package/src/lib/components/task-edit-drawer.js.map +1 -1
  141. package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
  142. package/src/lib/components/tasks-bulk-bar.js +7 -20
  143. package/src/lib/components/tasks-bulk-bar.js.map +1 -1
  144. package/src/lib/components/tasks-calendar.d.ts +3 -0
  145. package/src/lib/components/tasks-calendar.js +8 -1
  146. package/src/lib/components/tasks-calendar.js.map +1 -1
  147. package/src/lib/components/tasks-section.d.ts +3 -3
  148. package/src/lib/components/tasks-section.js +58 -43
  149. package/src/lib/components/tasks-section.js.map +1 -1
  150. package/src/lib/constants/api-routes.d.ts +2 -9
  151. package/src/lib/constants/api-routes.js +1 -7
  152. package/src/lib/constants/api-routes.js.map +1 -1
  153. package/src/lib/constants/bundle-common.d.ts +6 -0
  154. package/src/lib/constants/bundle-common.js +11 -0
  155. package/src/lib/constants/bundle-common.js.map +1 -1
  156. package/src/lib/constants/company-filters.d.ts +14 -0
  157. package/src/lib/constants/company-filters.js +51 -1
  158. package/src/lib/constants/company-filters.js.map +1 -1
  159. package/src/lib/constants/contact-filters.d.ts +2 -0
  160. package/src/lib/constants/contact-filters.js +18 -1
  161. package/src/lib/constants/contact-filters.js.map +1 -1
  162. package/src/lib/constants/deal-filters.d.ts +22 -1
  163. package/src/lib/constants/deal-filters.js +67 -4
  164. package/src/lib/constants/deal-filters.js.map +1 -1
  165. package/src/lib/declarations.console-server.d.ts +3 -0
  166. package/src/lib/declarations.console-server.js +35 -0
  167. package/src/lib/declarations.console-server.js.map +1 -1
  168. package/src/lib/declarations.d.ts +26 -0
  169. package/src/lib/declarations.js +35 -0
  170. package/src/lib/declarations.js.map +1 -0
  171. package/src/lib/declarations.server.d.ts +11 -0
  172. package/src/lib/declarations.server.js +92 -1
  173. package/src/lib/declarations.server.js.map +1 -1
  174. package/src/lib/hooks/use-company-picklists.d.ts +15 -0
  175. package/src/lib/hooks/use-company-picklists.js +55 -0
  176. package/src/lib/hooks/use-company-picklists.js.map +1 -0
  177. package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
  178. package/src/lib/hooks/use-crm-picklist.js +53 -0
  179. package/src/lib/hooks/use-crm-picklist.js.map +1 -0
  180. package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
  181. package/src/lib/hooks/use-crm-record-names.js +45 -19
  182. package/src/lib/hooks/use-crm-record-names.js.map +1 -1
  183. package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
  184. package/src/lib/hooks/use-crm-task-picklists.js +45 -0
  185. package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
  186. package/src/lib/hooks/use-deals.d.ts +14 -0
  187. package/src/lib/hooks/use-deals.js +29 -0
  188. package/src/lib/hooks/use-deals.js.map +1 -1
  189. package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
  190. package/src/lib/hooks/use-lead-picklists.js +46 -0
  191. package/src/lib/hooks/use-lead-picklists.js.map +1 -0
  192. package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
  193. package/src/lib/hooks/use-lead-source-picklist.js +12 -22
  194. package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
  195. package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
  196. package/src/lib/hooks/use-lead-status-picklist.js +40 -0
  197. package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
  198. package/src/lib/model/companies.d.ts +32 -3
  199. package/src/lib/model/companies.js +133 -16
  200. package/src/lib/model/companies.js.map +1 -1
  201. package/src/lib/model/contact-merge.d.ts +27 -3
  202. package/src/lib/model/contact-merge.js +81 -7
  203. package/src/lib/model/contact-merge.js.map +1 -1
  204. package/src/lib/model/contact-record.d.ts +17 -0
  205. package/src/lib/model/contact-record.js +15 -1
  206. package/src/lib/model/contact-record.js.map +1 -1
  207. package/src/lib/model/contact-update.d.ts +31 -2
  208. package/src/lib/model/contact-update.js +14 -0
  209. package/src/lib/model/contact-update.js.map +1 -1
  210. package/src/lib/model/crm-list-query.d.ts +5 -0
  211. package/src/lib/model/crm-list-query.js +8 -0
  212. package/src/lib/model/crm-list-query.js.map +1 -1
  213. package/src/lib/model/crm-recipes.d.ts +40 -0
  214. package/src/lib/model/crm-recipes.js +244 -0
  215. package/src/lib/model/crm-recipes.js.map +1 -0
  216. package/src/lib/model/crm-record-counts.d.ts +36 -0
  217. package/src/lib/model/crm-record-counts.js +54 -0
  218. package/src/lib/model/crm-record-counts.js.map +1 -0
  219. package/src/lib/model/crm-record-lists.d.ts +23 -0
  220. package/src/lib/model/crm-record-lists.js +161 -0
  221. package/src/lib/model/crm-record-lists.js.map +1 -0
  222. package/src/lib/model/crm-reports.d.ts +73 -3
  223. package/src/lib/model/crm-reports.js +120 -1
  224. package/src/lib/model/crm-reports.js.map +1 -1
  225. package/src/lib/model/crm-sharing.d.ts +21 -3
  226. package/src/lib/model/crm-sharing.js +27 -6
  227. package/src/lib/model/crm-sharing.js.map +1 -1
  228. package/src/lib/model/deal-board-model.d.ts +8 -2
  229. package/src/lib/model/deal-board-model.js +15 -2
  230. package/src/lib/model/deal-board-model.js.map +1 -1
  231. package/src/lib/model/deal-contact-roles.d.ts +45 -0
  232. package/src/lib/model/deal-contact-roles.js +73 -0
  233. package/src/lib/model/deal-contact-roles.js.map +1 -0
  234. package/src/lib/model/deal-form-model.d.ts +56 -0
  235. package/src/lib/model/deal-form-model.js +79 -7
  236. package/src/lib/model/deal-form-model.js.map +1 -1
  237. package/src/lib/model/download-text-file.d.ts +23 -0
  238. package/src/lib/model/download-text-file.js +34 -0
  239. package/src/lib/model/download-text-file.js.map +1 -0
  240. package/src/lib/model/lead-filters.d.ts +36 -2
  241. package/src/lib/model/lead-filters.js +123 -2
  242. package/src/lib/model/lead-filters.js.map +1 -1
  243. package/src/lib/model/lead-source-direction.d.ts +38 -0
  244. package/src/lib/model/lead-source-direction.js +52 -0
  245. package/src/lib/model/lead-source-direction.js.map +1 -0
  246. package/src/lib/model/picklist-values.d.ts +119 -0
  247. package/src/lib/model/picklist-values.js +256 -0
  248. package/src/lib/model/picklist-values.js.map +1 -0
  249. package/src/lib/model/record-facts-disclosed.d.ts +81 -0
  250. package/src/lib/model/record-facts-disclosed.js +281 -0
  251. package/src/lib/model/record-facts-disclosed.js.map +1 -0
  252. package/src/lib/model/record-facts.d.ts +215 -34
  253. package/src/lib/model/record-facts.js +307 -128
  254. package/src/lib/model/record-facts.js.map +1 -1
  255. package/src/lib/model/task-picklists.d.ts +52 -0
  256. package/src/lib/model/task-picklists.js +83 -0
  257. package/src/lib/model/task-picklists.js.map +1 -0
  258. package/src/lib/model/task-routes.d.ts +13 -0
  259. package/src/lib/model/task-routes.js +23 -4
  260. package/src/lib/model/task-routes.js.map +1 -1
  261. package/src/lib/plan-entitlements.js +6 -4
  262. package/src/lib/plan-entitlements.js.map +1 -1
  263. package/src/lib/plugin.js +17 -0
  264. package/src/lib/plugin.js.map +1 -1
  265. package/src/lib/server/api-v1/contacts.js +220 -14
  266. package/src/lib/server/api-v1/contacts.js.map +1 -1
  267. package/src/lib/server/api-v1/crm-activities.js +14 -1
  268. package/src/lib/server/api-v1/crm-activities.js.map +1 -1
  269. package/src/lib/server/api-v1/crm-companies.js +123 -14
  270. package/src/lib/server/api-v1/crm-companies.js.map +1 -1
  271. package/src/lib/server/api-v1/crm-deals.js +291 -26
  272. package/src/lib/server/api-v1/crm-deals.js.map +1 -1
  273. package/src/lib/server/api-v1/crm-leads.js +144 -38
  274. package/src/lib/server/api-v1/crm-leads.js.map +1 -1
  275. package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
  276. package/src/lib/server/api-v1/crm-pipelines.js +8 -2
  277. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
  278. package/src/lib/server/api-v1/crm-tasks.js +75 -33
  279. package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
  280. package/src/lib/server/api-v1/openapi.d.ts +0 -11
  281. package/src/lib/server/api-v1/openapi.js +171 -16
  282. package/src/lib/server/api-v1/openapi.js.map +1 -1
  283. package/src/lib/server/assign-contact-owner.d.ts +162 -0
  284. package/src/lib/server/assign-contact-owner.js +340 -0
  285. package/src/lib/server/assign-contact-owner.js.map +1 -0
  286. package/src/lib/server/associate-company-by-domain.d.ts +70 -0
  287. package/src/lib/server/associate-company-by-domain.js +153 -0
  288. package/src/lib/server/associate-company-by-domain.js.map +1 -0
  289. package/src/lib/server/automation-steps.d.ts +139 -0
  290. package/src/lib/server/automation-steps.js +472 -0
  291. package/src/lib/server/automation-steps.js.map +1 -0
  292. package/src/lib/server/capture-contact.js +65 -21
  293. package/src/lib/server/capture-contact.js.map +1 -1
  294. package/src/lib/server/capture-host-contact.d.ts +104 -0
  295. package/src/lib/server/capture-host-contact.js +151 -0
  296. package/src/lib/server/capture-host-contact.js.map +1 -0
  297. package/src/lib/server/company-children.d.ts +25 -0
  298. package/src/lib/server/company-children.js +42 -0
  299. package/src/lib/server/company-children.js.map +1 -0
  300. package/src/lib/server/company-delete.d.ts +18 -0
  301. package/src/lib/server/company-delete.js +44 -21
  302. package/src/lib/server/company-delete.js.map +1 -1
  303. package/src/lib/server/contact-email-history.js +21 -19
  304. package/src/lib/server/contact-email-history.js.map +1 -1
  305. package/src/lib/server/contact-remove.js +27 -2
  306. package/src/lib/server/contact-remove.js.map +1 -1
  307. package/src/lib/server/contact-reports-to.d.ts +61 -0
  308. package/src/lib/server/contact-reports-to.js +114 -0
  309. package/src/lib/server/contact-reports-to.js.map +1 -0
  310. package/src/lib/server/contact-update.d.ts +42 -1
  311. package/src/lib/server/contact-update.js +204 -23
  312. package/src/lib/server/contact-update.js.map +1 -1
  313. package/src/lib/server/convert-host-lead.d.ts +46 -1
  314. package/src/lib/server/convert-host-lead.js +173 -15
  315. package/src/lib/server/convert-host-lead.js.map +1 -1
  316. package/src/lib/server/convert-open-lead.js +12 -5
  317. package/src/lib/server/convert-open-lead.js.map +1 -1
  318. package/src/lib/server/crm-record-indexes.d.ts +45 -0
  319. package/src/lib/server/crm-record-indexes.js +78 -0
  320. package/src/lib/server/crm-record-indexes.js.map +1 -0
  321. package/src/lib/server/crm-sharing.d.ts +9 -1
  322. package/src/lib/server/crm-sharing.js +23 -3
  323. package/src/lib/server/crm-sharing.js.map +1 -1
  324. package/src/lib/server/deal-contact-roles.d.ts +27 -0
  325. package/src/lib/server/deal-contact-roles.js +89 -0
  326. package/src/lib/server/deal-contact-roles.js.map +1 -0
  327. package/src/lib/server/lead-convert.d.ts +5 -0
  328. package/src/lib/server/lead-convert.js +19 -3
  329. package/src/lib/server/lead-convert.js.map +1 -1
  330. package/src/lib/server/lead-create.d.ts +17 -2
  331. package/src/lib/server/lead-create.js +46 -14
  332. package/src/lib/server/lead-create.js.map +1 -1
  333. package/src/lib/server/lead-nurturing.d.ts +6 -0
  334. package/src/lib/server/lead-nurturing.js +57 -20
  335. package/src/lib/server/lead-nurturing.js.map +1 -1
  336. package/src/lib/server/lead-picklists.d.ts +35 -0
  337. package/src/lib/server/lead-picklists.js +52 -0
  338. package/src/lib/server/lead-picklists.js.map +1 -0
  339. package/src/lib/server/lead-source-picklist.d.ts +1 -13
  340. package/src/lib/server/lead-source-picklist.js +6 -33
  341. package/src/lib/server/lead-source-picklist.js.map +1 -1
  342. package/src/lib/server/merge-contacts.js +22 -4
  343. package/src/lib/server/merge-contacts.js.map +1 -1
  344. package/src/lib/server/person-eraser.d.ts +53 -0
  345. package/src/lib/server/person-eraser.js +149 -0
  346. package/src/lib/server/person-eraser.js.map +1 -0
  347. package/src/lib/server/person-records.d.ts +69 -0
  348. package/src/lib/server/person-records.js +317 -0
  349. package/src/lib/server/person-records.js.map +1 -0
  350. package/src/lib/server/person-refund.d.ts +97 -0
  351. package/src/lib/server/person-refund.js +221 -0
  352. package/src/lib/server/person-refund.js.map +1 -0
  353. package/src/lib/server/picklist-values.d.ts +21 -0
  354. package/src/lib/server/picklist-values.js +308 -0
  355. package/src/lib/server/picklist-values.js.map +1 -0
  356. package/src/lib/server/read-picklist.d.ts +44 -0
  357. package/src/lib/server/read-picklist.js +65 -0
  358. package/src/lib/server/read-picklist.js.map +1 -0
  359. package/src/lib/server/recipe-routes.js +15 -7
  360. package/src/lib/server/recipe-routes.js.map +1 -1
  361. package/src/lib/server/record-email-state.js +7 -1
  362. package/src/lib/server/record-email-state.js.map +1 -1
  363. package/src/lib/server/record-facts.d.ts +3 -0
  364. package/src/lib/server/record-facts.js +233 -31
  365. package/src/lib/server/record-facts.js.map +1 -1
  366. package/src/lib/server/record-origin.d.ts +27 -0
  367. package/src/lib/server/record-origin.js +104 -0
  368. package/src/lib/server/record-origin.js.map +1 -0
  369. package/src/lib/server/record-timeline.js +15 -2
  370. package/src/lib/server/record-timeline.js.map +1 -1
  371. package/src/lib/server/suite-gate.js +4 -3
  372. package/src/lib/server/suite-gate.js.map +1 -1
  373. package/src/lib/server/task-routes.js +30 -16
  374. package/src/lib/server/task-routes.js.map +1 -1
  375. package/src/lib/server-deal-stage.d.ts +5 -1
  376. package/src/lib/server-deal-stage.js +10 -5
  377. package/src/lib/server-deal-stage.js.map +1 -1
  378. package/src/lib/server.d.ts +8 -3
  379. package/src/lib/server.js +47 -43
  380. package/src/lib/server.js.map +1 -1
  381. package/src/lib/testing/memory-firestore.d.ts +55 -0
  382. package/src/lib/testing/memory-firestore.js +335 -0
  383. package/src/lib/testing/memory-firestore.js.map +1 -0
  384. package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
  385. package/src/lib/testing/stand-in-email-send-index.js +49 -0
  386. package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
  387. package/src/lib/transfer/activities.d.ts +30 -0
  388. package/src/lib/transfer/activities.js +132 -0
  389. package/src/lib/transfer/activities.js.map +1 -0
  390. package/src/lib/transfer/aliases.d.ts +22 -0
  391. package/src/lib/transfer/aliases.js +1342 -0
  392. package/src/lib/transfer/aliases.js.map +1 -0
  393. package/src/lib/transfer/common.d.ts +222 -0
  394. package/src/lib/transfer/common.js +832 -0
  395. package/src/lib/transfer/common.js.map +1 -0
  396. package/src/lib/transfer/companies.d.ts +43 -0
  397. package/src/lib/transfer/companies.js +549 -0
  398. package/src/lib/transfer/companies.js.map +1 -0
  399. package/src/lib/transfer/contacts.d.ts +31 -0
  400. package/src/lib/transfer/contacts.js +727 -0
  401. package/src/lib/transfer/contacts.js.map +1 -0
  402. package/src/lib/transfer/deals.d.ts +66 -0
  403. package/src/lib/transfer/deals.js +698 -0
  404. package/src/lib/transfer/deals.js.map +1 -0
  405. package/src/lib/transfer/email-templates-package.d.ts +40 -0
  406. package/src/lib/transfer/email-templates-package.js +76 -0
  407. package/src/lib/transfer/email-templates-package.js.map +1 -0
  408. package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
  409. package/src/lib/transfer/email-templates-package.server.js +176 -0
  410. package/src/lib/transfer/email-templates-package.server.js.map +1 -0
  411. package/src/lib/transfer/fields.d.ts +102 -0
  412. package/src/lib/transfer/fields.js +1755 -0
  413. package/src/lib/transfer/fields.js.map +1 -0
  414. package/src/lib/transfer/leads.d.ts +30 -0
  415. package/src/lib/transfer/leads.js +582 -0
  416. package/src/lib/transfer/leads.js.map +1 -0
  417. package/src/lib/transfer/pipelines.d.ts +21 -0
  418. package/src/lib/transfer/pipelines.js +172 -0
  419. package/src/lib/transfer/pipelines.js.map +1 -0
  420. package/src/lib/transfer/register.d.ts +47 -0
  421. package/src/lib/transfer/register.js +277 -0
  422. package/src/lib/transfer/register.js.map +1 -0
  423. package/src/lib/transfer/tasks.d.ts +30 -0
  424. package/src/lib/transfer/tasks.js +418 -0
  425. package/src/lib/transfer/tasks.js.map +1 -0
  426. package/src/lib/transfer/ui.d.ts +20 -0
  427. package/src/lib/transfer/ui.js +42 -0
  428. package/src/lib/transfer/ui.js.map +1 -0
  429. package/src/lib/components/company-import-drawer.d.ts +0 -42
  430. package/src/lib/components/company-import-drawer.js +0 -99
  431. package/src/lib/components/company-import-drawer.js.map +0 -1
  432. package/src/lib/components/contact-import-drawer.d.ts +0 -46
  433. package/src/lib/components/contact-import-drawer.js +0 -149
  434. package/src/lib/components/contact-import-drawer.js.map +0 -1
  435. package/src/lib/components/crm-export-all-button.d.ts +0 -39
  436. package/src/lib/components/crm-export-all-button.js +0 -98
  437. package/src/lib/components/crm-export-all-button.js.map +0 -1
  438. package/src/lib/components/csv-import-drawer.d.ts +0 -139
  439. package/src/lib/components/csv-import-drawer.js +0 -757
  440. package/src/lib/components/csv-import-drawer.js.map +0 -1
  441. package/src/lib/components/deal-import-drawer.d.ts +0 -24
  442. package/src/lib/components/deal-import-drawer.js +0 -83
  443. package/src/lib/components/deal-import-drawer.js.map +0 -1
  444. package/src/lib/components/lead-import-drawer.d.ts +0 -27
  445. package/src/lib/components/lead-import-drawer.js +0 -118
  446. package/src/lib/components/lead-import-drawer.js.map +0 -1
  447. package/src/lib/components/lead-source-values-card.d.ts +0 -27
  448. package/src/lib/components/lead-source-values-card.js.map +0 -1
  449. package/src/lib/components/task-import-drawer.d.ts +0 -24
  450. package/src/lib/components/task-import-drawer.js +0 -82
  451. package/src/lib/components/task-import-drawer.js.map +0 -1
  452. package/src/lib/model/companies-csv.d.ts +0 -36
  453. package/src/lib/model/companies-csv.js +0 -38
  454. package/src/lib/model/companies-csv.js.map +0 -1
  455. package/src/lib/model/contacts-csv.d.ts +0 -54
  456. package/src/lib/model/contacts-csv.js +0 -67
  457. package/src/lib/model/contacts-csv.js.map +0 -1
  458. package/src/lib/model/crm-company-import.d.ts +0 -154
  459. package/src/lib/model/crm-company-import.js +0 -331
  460. package/src/lib/model/crm-company-import.js.map +0 -1
  461. package/src/lib/model/crm-csv.d.ts +0 -239
  462. package/src/lib/model/crm-csv.js +0 -467
  463. package/src/lib/model/crm-csv.js.map +0 -1
  464. package/src/lib/model/crm-deal-import.d.ts +0 -112
  465. package/src/lib/model/crm-deal-import.js +0 -263
  466. package/src/lib/model/crm-deal-import.js.map +0 -1
  467. package/src/lib/model/crm-import.d.ts +0 -250
  468. package/src/lib/model/crm-import.js +0 -467
  469. package/src/lib/model/crm-import.js.map +0 -1
  470. package/src/lib/model/crm-lead-import.d.ts +0 -138
  471. package/src/lib/model/crm-lead-import.js +0 -446
  472. package/src/lib/model/crm-lead-import.js.map +0 -1
  473. package/src/lib/model/crm-task-import.d.ts +0 -94
  474. package/src/lib/model/crm-task-import.js +0 -275
  475. package/src/lib/model/crm-task-import.js.map +0 -1
  476. package/src/lib/model/deals-csv.d.ts +0 -32
  477. package/src/lib/model/deals-csv.js +0 -36
  478. package/src/lib/model/deals-csv.js.map +0 -1
  479. package/src/lib/model/import-column-shapes.d.ts +0 -36
  480. package/src/lib/model/import-column-shapes.js +0 -76
  481. package/src/lib/model/import-column-shapes.js.map +0 -1
  482. package/src/lib/model/lead-source-values.d.ts +0 -82
  483. package/src/lib/model/lead-source-values.js +0 -149
  484. package/src/lib/model/lead-source-values.js.map +0 -1
  485. package/src/lib/model/leads-csv.d.ts +0 -40
  486. package/src/lib/model/leads-csv.js +0 -40
  487. package/src/lib/model/leads-csv.js.map +0 -1
  488. package/src/lib/model/tasks-csv.d.ts +0 -28
  489. package/src/lib/model/tasks-csv.js +0 -28
  490. package/src/lib/model/tasks-csv.js.map +0 -1
  491. package/src/lib/server/companies-import.d.ts +0 -57
  492. package/src/lib/server/companies-import.js +0 -242
  493. package/src/lib/server/companies-import.js.map +0 -1
  494. package/src/lib/server/contacts-import.d.ts +0 -109
  495. package/src/lib/server/contacts-import.js +0 -393
  496. package/src/lib/server/contacts-import.js.map +0 -1
  497. package/src/lib/server/deals-import.d.ts +0 -76
  498. package/src/lib/server/deals-import.js +0 -248
  499. package/src/lib/server/deals-import.js.map +0 -1
  500. package/src/lib/server/export-route.d.ts +0 -60
  501. package/src/lib/server/export-route.js +0 -447
  502. package/src/lib/server/export-route.js.map +0 -1
  503. package/src/lib/server/import-context.d.ts +0 -87
  504. package/src/lib/server/import-context.js +0 -182
  505. package/src/lib/server/import-context.js.map +0 -1
  506. package/src/lib/server/lead-source-values.d.ts +0 -50
  507. package/src/lib/server/lead-source-values.js +0 -191
  508. package/src/lib/server/lead-source-values.js.map +0 -1
  509. package/src/lib/server/leads-import.d.ts +0 -84
  510. package/src/lib/server/leads-import.js +0 -367
  511. package/src/lib/server/leads-import.js.map +0 -1
  512. package/src/lib/server/tasks-import.d.ts +0 -54
  513. package/src/lib/server/tasks-import.js +0 -160
  514. package/src/lib/server/tasks-import.js.map +0 -1
@@ -1,242 +0,0 @@
1
- import { _ as _extends } from "@swc/helpers/_/_extends";
2
- /**
3
- * @license
4
- * Copyright 2026 Aglyn LLC
5
- *
6
- * Licensed under the Apache License, Version 2.0 (the "License");
7
- * you may not use this file except in compliance with the License.
8
- * You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- * See the License for the specific language governing permissions and
16
- * limitations under the License.
17
- */ /**
18
- * `POST /api/crm/companies-import` — one chunk of a companies file, written
19
- * (AGL-2621).
20
- *
21
- * The browser has already read the file and applied the operator's column
22
- * mapping; what arrives here is up to {@link COMPANY_IMPORT_CHUNK_SIZE} raw
23
- * rows in the vocabulary `crm-company-import.ts` defines. This route judges
24
- * each one through the same normalizers the company drawer runs, and
25
- * writes it — the ONLY place either happens, so a stale tab cannot store
26
- * something the server would have refused.
27
- *
28
- * ## Matched by domain, then by name
29
- *
30
- * A row is one company the org may already have. The domain is a key and
31
- * the name a spelling, so a row with a domain is looked up by it first,
32
- * and by the name's search key when no company carries the domain or the
33
- * row has none — two files calling one business "Acme" and "Acme Inc" meet
34
- * at `acme.com`, and a file with no domain column still finds "Acme" by
35
- * name. Both lookups are narrowed to what the caller's scope can see: two
36
- * clients of one agency may each have an "Acme" and must each get their
37
- * own. A match is UPDATED with what the row carries, tags unioned; no
38
- * match is CREATED with the stamp every CRM creator writes.
39
- *
40
- * ## The band is counted once per request
41
- *
42
- * A created company is a CRM record and meets the records band (AGL-2611).
43
- * The aggregate is taken once at the first create and the verdict re-judged
44
- * locally as the request creates more — `checkCrmRecordsQuota` is pure over
45
- * a count — so two hundred rows cost three aggregate reads, not six
46
- * hundred. A metered plan never refuses; a hard band refuses the rows past
47
- * it as `records-band`, and updates to matched companies go through either
48
- * way, because an update adds no record.
49
- */ import { checkCrmRecordsQuota, CRM_COLLECTIONS, crmCompanyListFields, crmNewRecordListFields, fieldDefinitionsForObject, nameSearchFields, visibleToTokens } from "@aglyn/aglyn/server";
50
- import { COMPANY_IMPORT_CHUNK_SIZE, COMPANY_IMPORT_MAX_BODY_BYTES, companyImportMatchKey, normalizeCompanyImportRow } from "../model/crm-company-import.js";
51
- import { crmRecordsQuotaForOrg, firebaseAdmin } from "@aglyn/tenant-data-admin";
52
- import { FieldValue } from "firebase-admin/firestore";
53
- import { ownerDirectory, readImportRows, resolveImportContext } from "./import-context.js";
54
- /** The company a row refers to in this scope — by domain, then by name — or `null`. */ async function findCompany(companies, readTokens, row) {
55
- const seen = (snapshot)=>{
56
- var _snapshot_docs_find;
57
- return (_snapshot_docs_find = snapshot.docs.find((doc)=>visibleToTokens(doc.get('visibleTo'), readTokens))) != null ? _snapshot_docs_find : null;
58
- };
59
- if (row.domain) {
60
- const byDomain = seen(await companies.where('domain', '==', row.domain).limit(10).get());
61
- if (byDomain) return byDomain;
62
- }
63
- return seen(await companies.where('nameLower', '==', nameSearchFields(row.name).nameLower).limit(10).get());
64
- }
65
- /**
66
- * The fields a row writes — on a create and on an update alike. Only what
67
- * the row carries: an update must not clear a website the file did not
68
- * mention, so an absent optional is left absent here rather than deleted.
69
- */ function storedFields(row, ownerUid) {
70
- return _extends({}, nameSearchFields(row.name), row.domain ? {
71
- domain: row.domain
72
- } : {}, row.website ? {
73
- website: row.website
74
- } : {}, row.phone ? {
75
- phone: row.phone
76
- } : {}, row.industry ? {
77
- industry: row.industry
78
- } : {}, ownerUid ? {
79
- ownerUid
80
- } : {}, row.address ? {
81
- address: row.address
82
- } : {}, row.notes ? {
83
- notes: row.notes
84
- } : {});
85
- }
86
- /**
87
- * The row's custom values as a MERGE writes them: one dotted path per key,
88
- * so a company already filed keeps every value the file did not carry
89
- * (AGL-2661). A create spreads the map itself — see the loop below.
90
- */ function customUpdate(row) {
91
- return Object.fromEntries(Object.entries(row.custom).map(([key, value])=>[
92
- `custom.${key}`,
93
- value
94
- ]));
95
- }
96
- /**
97
- * The org's live COMPANY field definitions (AGL-2661) — the contact
98
- * import's read, narrowed to the object this import writes. Read in full
99
- * and filtered in memory: a holder has a handful of fields, and a `where`
100
- * on `object` would need an index for a collection that fits in one page.
101
- */ async function loadCompanyFieldDefinitions(orgId, readTokens) {
102
- const snapshot = await firebaseAdmin.app().firestore().collection('orgs').doc(orgId).collection(CRM_COLLECTIONS.contactFields).limit(200).get();
103
- return fieldDefinitionsForObject(snapshot.docs.map((doc)=>doc.data()), 'company').filter((field)=>!!field.key && !field.retiredAt && visibleToTokens(field.visibleTo, readTokens));
104
- }
105
- /**
106
- * `POST crm/companies-import` — `{ hostId, rows }` → a {@link CompanyImportChunkResult}.
107
- *
108
- * Rows are written one after another rather than in parallel: two rows
109
- * for one company racing each other would each miss the other's create.
110
- */ export const crmCompaniesImportHandler = async (req, res)=>{
111
- if (req.method !== 'POST') {
112
- res.setHeader('Allow', 'POST');
113
- return res.status(405).json({
114
- error: 'Method not allowed'
115
- });
116
- }
117
- const read = readImportRows(req, {
118
- maxBodyBytes: COMPANY_IMPORT_MAX_BODY_BYTES,
119
- chunkSize: COMPANY_IMPORT_CHUNK_SIZE
120
- });
121
- if ('error' in read) return res.status(read.status).json({
122
- error: read.error
123
- });
124
- try {
125
- const context = await resolveImportContext(req);
126
- if (context.ok === false) return res.status(context.status).json(context.body);
127
- const skipped = [];
128
- const dropped = {};
129
- const normalized = [];
130
- const fields = await loadCompanyFieldDefinitions(context.orgId, context.readTokens);
131
- /*
132
- * A duplicate WITHIN the request is skipped rather than merged: the
133
- * second row would update the first's record and the count would read
134
- * one created and one merged for one company in one file. Across
135
- * requests the lookup answers, and reports a merge.
136
- */ const seen = new Set();
137
- read.rows.forEach((raw, index)=>{
138
- const verdict = normalizeCompanyImportRow(raw, fields);
139
- if (verdict.ok === false) {
140
- skipped.push({
141
- index,
142
- name: verdict.input,
143
- reason: verdict.reason
144
- });
145
- return;
146
- }
147
- const key = companyImportMatchKey(verdict.row);
148
- if (seen.has(key)) {
149
- skipped.push({
150
- index,
151
- name: verdict.row.name,
152
- reason: 'duplicate'
153
- });
154
- return;
155
- }
156
- seen.add(key);
157
- for (const entry of verdict.row.dropped){
158
- var _dropped_entry_field;
159
- dropped[entry.field] = ((_dropped_entry_field = dropped[entry.field]) != null ? _dropped_entry_field : 0) + 1;
160
- }
161
- normalized.push({
162
- index,
163
- row: verdict.row
164
- });
165
- });
166
- const owners = await ownerDirectory(context.orgId, normalized.map((entry)=>entry.row));
167
- const ownersUnresolved = new Set();
168
- const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(context.orgId);
169
- const companies = orgRef.collection(CRM_COLLECTIONS.companies);
170
- const stamp = creationStamp(context);
171
- let counted = null;
172
- let createdHere = 0;
173
- let created = 0;
174
- let merged = 0;
175
- for (const { index, row } of normalized){
176
- let ownerUid;
177
- if (row.ownerEmail) {
178
- ownerUid = owners.get(row.ownerEmail);
179
- if (!ownerUid) ownersUnresolved.add(row.ownerEmail);
180
- }
181
- const existing = await findCompany(companies, context.readTokens, row);
182
- const stored = storedFields(row, ownerUid);
183
- if (existing) {
184
- await existing.ref.update(_extends({}, stored, crmCompanyListFields(_extends({}, existing.data(), stored)), row.tags.length ? {
185
- tags: FieldValue.arrayUnion(...row.tags)
186
- } : {}, customUpdate(row), {
187
- updatedAt: FieldValue.serverTimestamp()
188
- }));
189
- merged += 1;
190
- continue;
191
- }
192
- if (!counted) counted = await crmRecordsQuotaForOrg(context.org, orgRef);
193
- const room = checkCrmRecordsQuota(context.org, counted.crmRecordsCount + createdHere);
194
- if (!room.allowed) {
195
- skipped.push({
196
- index,
197
- name: row.name,
198
- reason: 'records-band'
199
- });
200
- continue;
201
- }
202
- await companies.add(_extends({}, stored, {
203
- tags: row.tags
204
- }, Object.keys(row.custom).length ? {
205
- custom: row.custom
206
- } : {}, stamp, crmNewRecordListFields('companies', _extends({}, stored, stamp))));
207
- createdHere += 1;
208
- created += 1;
209
- }
210
- const result = {
211
- received: read.rows.length,
212
- created,
213
- merged,
214
- skipped: skipped.sort((a, b)=>a.index - b.index),
215
- dropped,
216
- ownersUnresolved: [
217
- ...ownersUnresolved
218
- ]
219
- };
220
- return res.status(200).json(result);
221
- } catch (error) {
222
- console.error('crm/companies-import failed', error);
223
- return res.status(500).json({
224
- error: 'The import could not continue.'
225
- });
226
- }
227
- };
228
- /**
229
- * What every company this import CREATES carries beside its fields: the
230
- * scope every CRM creator stamps, the site as provenance, who imported it,
231
- * and the clocks. A record written without `visibleTo` is seen by nobody.
232
- */ function creationStamp(context) {
233
- return {
234
- hostId: context.hostId,
235
- visibleTo: context.scopeTokens,
236
- createdByUid: context.uid,
237
- createdAt: FieldValue.serverTimestamp(),
238
- updatedAt: FieldValue.serverTimestamp()
239
- };
240
- }
241
-
242
- //# sourceMappingURL=companies-import.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/server/companies-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 * `POST /api/crm/companies-import` — one chunk of a companies file, written\n * (AGL-2621).\n *\n * The browser has already read the file and applied the operator's column\n * mapping; what arrives here is up to {@link COMPANY_IMPORT_CHUNK_SIZE} raw\n * rows in the vocabulary `crm-company-import.ts` defines. This route judges\n * each one through the same normalizers the company drawer runs, and\n * writes it — the ONLY place either happens, so a stale tab cannot store\n * something the server would have refused.\n *\n * ## Matched by domain, then by name\n *\n * A row is one company the org may already have. The domain is a key and\n * the name a spelling, so a row with a domain is looked up by it first,\n * and by the name's search key when no company carries the domain or the\n * row has none — two files calling one business \"Acme\" and \"Acme Inc\" meet\n * at `acme.com`, and a file with no domain column still finds \"Acme\" by\n * name. Both lookups are narrowed to what the caller's scope can see: two\n * clients of one agency may each have an \"Acme\" and must each get their\n * own. A match is UPDATED with what the row carries, tags unioned; no\n * match is CREATED with the stamp every CRM creator writes.\n *\n * ## The band is counted once per request\n *\n * A created company is a CRM record and meets the records band (AGL-2611).\n * The aggregate is taken once at the first create and the verdict re-judged\n * locally as the request creates more — `checkCrmRecordsQuota` is pure over\n * a count — so two hundred rows cost three aggregate reads, not six\n * hundred. A metered plan never refuses; a hard band refuses the rows past\n * it as `records-band`, and updates to matched companies go through either\n * way, because an update adds no record.\n */\n\nimport {\n checkCrmRecordsQuota,\n type ContactFieldDefinition,\n CRM_COLLECTIONS,\n crmCompanyListFields,\n crmNewRecordListFields,\n fieldDefinitionsForObject,\n nameSearchFields,\n type PluginApiHandler,\n visibleToTokens,\n} from '@aglyn/aglyn/server'\nimport {\n COMPANY_IMPORT_CHUNK_SIZE,\n COMPANY_IMPORT_MAX_BODY_BYTES,\n type CompanyImportChunkResult,\n type CompanyImportRawRow,\n type CompanyImportRow,\n type CompanyImportSkippedRow,\n companyImportMatchKey,\n normalizeCompanyImportRow,\n} from '../model/crm-company-import'\nimport { crmRecordsQuotaForOrg, firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n type ImportContext,\n ownerDirectory,\n readImportRows,\n resolveImportContext,\n} from './import-context'\n\ntype Companies = FirebaseFirestore.CollectionReference\n\n/** The company a row refers to in this scope — by domain, then by name — or `null`. */\nasync function findCompany(\n companies: Companies,\n readTokens: readonly string[],\n row: Pick<CompanyImportRow, 'name' | 'domain'>,\n): Promise<FirebaseFirestore.QueryDocumentSnapshot | null> {\n const seen = (snapshot: FirebaseFirestore.QuerySnapshot) =>\n snapshot.docs.find((doc) => visibleToTokens(doc.get('visibleTo'), readTokens)) ?? null\n if (row.domain) {\n const byDomain = seen(\n await companies.where('domain', '==', row.domain).limit(10).get(),\n )\n if (byDomain) return byDomain\n }\n return seen(\n await companies\n .where('nameLower', '==', nameSearchFields(row.name).nameLower)\n .limit(10)\n .get(),\n )\n}\n\n/**\n * The fields a row writes — on a create and on an update alike. Only what\n * the row carries: an update must not clear a website the file did not\n * mention, so an absent optional is left absent here rather than deleted.\n */\nfunction storedFields(\n row: CompanyImportRow,\n ownerUid: string | undefined,\n): Record<string, unknown> {\n return {\n ...nameSearchFields(row.name),\n ...(row.domain ? { domain: row.domain } : {}),\n ...(row.website ? { website: row.website } : {}),\n ...(row.phone ? { phone: row.phone } : {}),\n ...(row.industry ? { industry: row.industry } : {}),\n ...(ownerUid ? { ownerUid } : {}),\n ...(row.address ? { address: row.address } : {}),\n ...(row.notes ? { notes: row.notes } : {}),\n }\n}\n\n/**\n * The row's custom values as a MERGE writes them: one dotted path per key,\n * so a company already filed keeps every value the file did not carry\n * (AGL-2661). A create spreads the map itself — see the loop below.\n */\nfunction customUpdate(row: CompanyImportRow): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(row.custom).map(([key, value]) => [`custom.${key}`, value]),\n )\n}\n\n/**\n * The org's live COMPANY field definitions (AGL-2661) — the contact\n * import's read, narrowed to the object this import writes. Read in full\n * and filtered in memory: a holder has a handful of fields, and a `where`\n * on `object` would need an index for a collection that fits in one page.\n */\nasync function loadCompanyFieldDefinitions(\n orgId: string,\n readTokens: readonly string[],\n): Promise<ContactFieldDefinition[]> {\n const snapshot = await firebaseAdmin\n .app()\n .firestore()\n .collection('orgs')\n .doc(orgId)\n .collection(CRM_COLLECTIONS.contactFields)\n .limit(200)\n .get()\n return fieldDefinitionsForObject(\n snapshot.docs.map((doc) => doc.data() as ContactFieldDefinition),\n 'company',\n ).filter(\n (field) =>\n !!field.key && !field.retiredAt && visibleToTokens(field.visibleTo, readTokens),\n )\n}\n\n/**\n * `POST crm/companies-import` — `{ hostId, rows }` → a {@link CompanyImportChunkResult}.\n *\n * Rows are written one after another rather than in parallel: two rows\n * for one company racing each other would each miss the other's create.\n */\nexport const crmCompaniesImportHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST')\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const read = readImportRows<CompanyImportRawRow>(req, {\n maxBodyBytes: COMPANY_IMPORT_MAX_BODY_BYTES,\n chunkSize: COMPANY_IMPORT_CHUNK_SIZE,\n })\n if ('error' in read) return res.status(read.status).json({ error: read.error })\n try {\n const context = await resolveImportContext(req)\n if (context.ok === false) return res.status(context.status).json(context.body)\n\n const skipped: CompanyImportSkippedRow[] = []\n const dropped: Record<string, number> = {}\n const normalized: { index: number; row: CompanyImportRow }[] = []\n const fields = await loadCompanyFieldDefinitions(context.orgId, context.readTokens)\n /*\n * A duplicate WITHIN the request is skipped rather than merged: the\n * second row would update the first's record and the count would read\n * one created and one merged for one company in one file. Across\n * requests the lookup answers, and reports a merge.\n */\n const seen = new Set<string>()\n read.rows.forEach((raw, index) => {\n const verdict = normalizeCompanyImportRow(raw, fields)\n if (verdict.ok === false) {\n skipped.push({ index, name: verdict.input, reason: verdict.reason })\n return\n }\n const key = companyImportMatchKey(verdict.row)\n if (seen.has(key)) {\n skipped.push({ index, name: verdict.row.name, reason: 'duplicate' })\n return\n }\n seen.add(key)\n for (const entry of verdict.row.dropped) {\n dropped[entry.field] = (dropped[entry.field] ?? 0) + 1\n }\n normalized.push({ index, row: verdict.row })\n })\n\n const owners = await ownerDirectory(\n context.orgId,\n normalized.map((entry) => entry.row),\n )\n const ownersUnresolved = new Set<string>()\n const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(context.orgId)\n const companies = orgRef.collection(CRM_COLLECTIONS.companies)\n const stamp = creationStamp(context)\n let counted: { crmRecordsCount: number } | null = null\n let createdHere = 0\n let created = 0\n let merged = 0\n\n for (const { index, row } of normalized) {\n let ownerUid: string | undefined\n if (row.ownerEmail) {\n ownerUid = owners.get(row.ownerEmail)\n if (!ownerUid) ownersUnresolved.add(row.ownerEmail)\n }\n const existing = await findCompany(companies, context.readTokens, row)\n const stored = storedFields(row, ownerUid)\n if (existing) {\n await existing.ref.update({\n ...stored,\n // The file may rename the company: what the list searches follows.\n ...crmCompanyListFields({ ...existing.data(), ...stored }),\n ...(row.tags.length ? { tags: FieldValue.arrayUnion(...row.tags) } : {}),\n ...customUpdate(row),\n updatedAt: FieldValue.serverTimestamp(),\n })\n merged += 1\n continue\n }\n if (!counted) counted = await crmRecordsQuotaForOrg(context.org as never, orgRef)\n const room = checkCrmRecordsQuota(\n context.org as never,\n counted.crmRecordsCount + createdHere,\n )\n if (!room.allowed) {\n skipped.push({ index, name: row.name, reason: 'records-band' })\n continue\n }\n await companies.add({\n ...stored,\n tags: row.tags,\n ...(Object.keys(row.custom).length ? { custom: row.custom } : {}),\n ...stamp,\n // What the Companies list searches and filters by (AGL-3321).\n ...crmNewRecordListFields('companies', { ...stored, ...stamp }),\n })\n createdHere += 1\n created += 1\n }\n\n const result: CompanyImportChunkResult = {\n received: read.rows.length,\n created,\n merged,\n skipped: skipped.sort((a, b) => a.index - b.index),\n dropped,\n ownersUnresolved: [...ownersUnresolved],\n }\n return res.status(200).json(result)\n } catch (error) {\n console.error('crm/companies-import failed', error)\n return res.status(500).json({ error: 'The import could not continue.' })\n }\n}\n\n/**\n * What every company this import CREATES carries beside its fields: the\n * scope every CRM creator stamps, the site as provenance, who imported it,\n * and the clocks. A record written without `visibleTo` is seen by nobody.\n */\nfunction creationStamp(\n context: Extract<ImportContext, { ok: true }>,\n): Record<string, unknown> {\n return {\n hostId: context.hostId,\n visibleTo: context.scopeTokens,\n createdByUid: context.uid,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n }\n}\n"],"names":["checkCrmRecordsQuota","CRM_COLLECTIONS","crmCompanyListFields","crmNewRecordListFields","fieldDefinitionsForObject","nameSearchFields","visibleToTokens","COMPANY_IMPORT_CHUNK_SIZE","COMPANY_IMPORT_MAX_BODY_BYTES","companyImportMatchKey","normalizeCompanyImportRow","crmRecordsQuotaForOrg","firebaseAdmin","FieldValue","ownerDirectory","readImportRows","resolveImportContext","findCompany","companies","readTokens","row","seen","snapshot","docs","find","doc","get","domain","byDomain","where","limit","name","nameLower","storedFields","ownerUid","website","phone","industry","address","notes","customUpdate","Object","fromEntries","entries","custom","map","key","value","loadCompanyFieldDefinitions","orgId","app","firestore","collection","contactFields","data","filter","field","retiredAt","visibleTo","crmCompaniesImportHandler","req","res","method","setHeader","status","json","error","read","maxBodyBytes","chunkSize","context","ok","body","skipped","dropped","normalized","fields","Set","rows","forEach","raw","index","verdict","push","input","reason","has","add","entry","owners","ownersUnresolved","orgRef","stamp","creationStamp","counted","createdHere","created","merged","ownerEmail","existing","stored","ref","update","tags","length","arrayUnion","updatedAt","serverTimestamp","org","room","crmRecordsCount","allowed","keys","result","received","sort","a","b","console","hostId","scopeTokens","createdByUid","uid","createdAt"],"mappings":"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"}
@@ -1,109 +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
- * `POST /api/crm/contacts-import` — one chunk of a contact file, written
19
- * (AGL-2602).
20
- *
21
- * The browser has already read the file and applied the operator's column
22
- * mapping; what arrives here is up to {@link CONTACT_IMPORT_CHUNK_SIZE} raw
23
- * rows in the field vocabulary `crm-import.ts` defines. This route judges
24
- * each one and writes it, and it is the ONLY place either happens: the
25
- * drawer shows a preview from the same mapper but stores nothing, so a
26
- * stale tab cannot store something the server would have refused.
27
- *
28
- * ## Every row goes through the door every capture goes through
29
- *
30
- * `captureHostContact` — the runtime's wrapper over `upsertHostContact`,
31
- * the one writer of the contacts collection for every door that is not the
32
- * v1 API: forms, checkout, bookings, the newsletter box — is the writer
33
- * here too, so a row this file creates raises `contactCreated` like any
34
- * other capture (AGL-2605). That is what makes an import
35
- * dedupe on the address the way a second form submission does, land in the
36
- * capturing group's facet the way a form capture does, record consent
37
- * against the capturing site, and stop at a hard band where a form
38
- * capture stops. A bulk path with its own `add()` would be the fastest way
39
- * to grow an unscoped, unbanded, unconsented copy of the address book.
40
- *
41
- * What the door did not know how to write until now — a phone, a title, a
42
- * company, an owner, a stage, custom values — it now takes as `facet`, and
43
- * what it did not say until now — created or merged or refused — it now
44
- * returns as a verdict. Both changes are the door's, so the v1 API and the
45
- * manual add can reach them next.
46
- *
47
- * ## Every lookup paid once per request, not once per row (AGL-3423)
48
- *
49
- * A request has sixty seconds, and a row that reads for itself spends them
50
- * a round trip at a time: the door alone was a dozen serial reads and three
51
- * aggregate counts per new person, and a two-hundred-row chunk of an
52
- * Apollo export ran out of time before it answered. So nothing here is
53
- * read per row:
54
- *
55
- * - The door's own lookups — the site, the consent group, who each address
56
- * already is, who the site erased, the room in the records band — come
57
- * from one `prepareContactCaptureBatch` for the whole chunk, which every
58
- * row's capture is handed. The door still makes every decision.
59
- * - An owner is named by email and stored by uid, so the org's roster is
60
- * read once and every row resolves against it.
61
- * - A company is named by name and stored by id, so the distinct names are
62
- * looked up together, thirty to an `in` query, and the missing ones are
63
- * created in one batched write — an Apollo file names a different company
64
- * on nearly every row, and that was a read, a count and a write each.
65
- *
66
- * What is left per row is the row's own writes and what a new person sets
67
- * off, and those run {@link CONTACT_IMPORT_CONCURRENCY} at a time. A row is
68
- * started only inside {@link CONTACT_IMPORT_TIME_BUDGET_MS}; the rest are
69
- * reported `not-reached`, so a slow chunk answers with what it did instead
70
- * of being cut off at the limit with no answer at all.
71
- *
72
- * ## A retry is a merge, never a second person
73
- *
74
- * The door dedupes on the address, through the index and then the `email`
75
- * query, so a row that landed before a request was cut off is found by the
76
- * next attempt and merged into — the one-person-one-record rule a second
77
- * form submission meets. A company is found by its `nameLower` the same way.
78
- *
79
- * ## Who may call it
80
- *
81
- * `resolveImportContext` (`import-context.ts`) — the two gates every CSV
82
- * import route asks, shared with the companies import so one permission
83
- * has one spelling.
84
- */
85
- import { type PluginApiHandler } from '@aglyn/aglyn/server';
86
- /** The one sentence every imported contact's timeline opens with. */
87
- export declare const CONTACT_IMPORT_INTERACTION_SUMMARY = "Imported from CSV";
88
- /**
89
- * How many rows are written at once. Enough to overlap the round trips a
90
- * row still pays; few enough that a chunk never has more writes in flight
91
- * than one client connection handles comfortably.
92
- */
93
- export declare const CONTACT_IMPORT_CONCURRENCY = 8;
94
- /**
95
- * How long after the request arrived a row may still be STARTED. The
96
- * function is stopped at sixty seconds; this leaves the rows already in
97
- * flight, and the mail-server check's grace, room to finish before then.
98
- */
99
- export declare const CONTACT_IMPORT_TIME_BUDGET_MS = 40000;
100
- /**
101
- * `POST crm/contacts-import` — `{ hostId, rows }` → a {@link ContactImportChunkResult}.
102
- *
103
- * Rows are written {@link CONTACT_IMPORT_CONCURRENCY} at a time, which the
104
- * band allows because it is no longer counted per row: the capture batch
105
- * counted once, and every create is admitted from its tally — reserved in
106
- * file order before any row is written, so which rows the band keeps does
107
- * not depend on which write happened to finish first.
108
- */
109
- export declare const crmContactsImportHandler: PluginApiHandler;