@aglyn/plugins-crm 1.0.0-beta.220 → 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 +69 -22
  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
@@ -0,0 +1,244 @@
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
+ */ import { CONTACT_TAG_MAX_LENGTH } from "@aglyn/aglyn/app-utils/crm-kinds";
17
+ /*
18
+ * THE CRM'S RECIPES (AGL-2626).
19
+ *
20
+ * A recipe is a ready-to-edit automation — a trigger, its conditions and an
21
+ * ordered step list — built from the vocabulary the automation editor already
22
+ * offers and handed to that editor as a draft. Nothing is written until the
23
+ * person saves, and every field is theirs to change first: the recipe decides
24
+ * where the editor starts, not what the site runs.
25
+ *
26
+ * The CRM's own, because what each one is FOR is the CRM's: who a new lead is,
27
+ * when a deal is won, when a lead has gone quiet. They reach the automation
28
+ * editor through the platform's recipe seam
29
+ * (`plugin-manager/interaction-recipes`, AGL-3080), registered from this
30
+ * plugin's declarations; the org hub's Recipes card and its install routes
31
+ * read them here. Their ids are declared in `plugins.config.json`
32
+ * (`interactionRecipes`) because a stored automation names one.
33
+ *
34
+ * Definitions only. Three of the four are complete as written. `tagByForm`
35
+ * needs a form, and a form belongs to a site, so the picker that supplies it
36
+ * is the editor's business and host-scoped by nature. That is the seam an
37
+ * org-level mount keeps: the recipes are the same at either level, and only
38
+ * the form picker knows where it is.
39
+ */ export const CRM_ACTION_RECIPE_IDS = [
40
+ 'welcomeNewLead',
41
+ 'followUpWonDeal',
42
+ 'reengageStaleLead',
43
+ 'tagByForm'
44
+ ];
45
+ /**
46
+ * The field a resumed wait carries in its scope when it ended on the CLOCK
47
+ * rather than on the event it watched for — the automation engine's word for
48
+ * it, written into the step guard the stale-lead recipe stores.
49
+ */ const WAIT_TIMED_OUT_FIELD = '_waitTimedOut';
50
+ /**
51
+ * How long the stale-lead recipe holds before it decides a lead has gone
52
+ * quiet. A week: long enough that a rep who is working the lead has had a
53
+ * chance to move its stage, short enough that a lead nobody touched is
54
+ * still warm when the reminder lands.
55
+ */ export const STALE_LEAD_WAIT_MINUTES = 7 * 24 * 60;
56
+ /**
57
+ * The tag a form's captures get: the form's own name, cut to the tag cap.
58
+ * The name is what the person calls the form, so it is the tag they would
59
+ * have typed; the editor is open to change it before anything is saved.
60
+ */ export function crmRecipeTagForForm(formName) {
61
+ return formName.trim().slice(0, CONTACT_TAG_MAX_LENGTH);
62
+ }
63
+ export const CRM_ACTION_RECIPES = [
64
+ {
65
+ id: 'welcomeNewLead',
66
+ title: 'Welcome a new lead',
67
+ description: 'When a form makes a new contact: rotate in an owner, book a call for ' + 'tomorrow, send a thank-you, and tag them website.',
68
+ /*
69
+ * The owner first, because the task that follows names no assignee and
70
+ * so goes to whoever owns the contact when it is created — the member
71
+ * the rotation just chose. Round robin rather than a named member: a
72
+ * recipe cannot know who is on the team, and the pool under CRM →
73
+ * Settings is the one place that does. On a workspace with no pool the
74
+ * step fails and the run continues, so the call, the email and the tag
75
+ * still land and the run history says who was not assigned.
76
+ *
77
+ * The email comes before any wait, which makes it an immediate reply to
78
+ * what the visitor just did — transactional, sent from the org's own
79
+ * identity, to the address the event carries.
80
+ *
81
+ * Its words promise no response time. The org hub installs this recipe
82
+ * into a site without its editor opening, so the business never reads
83
+ * the sentence it is sending, and a "within a day" written here would be
84
+ * a commitment made on its behalf that nothing in the run keeps.
85
+ */ build: ()=>({
86
+ recipe: 'welcomeNewLead',
87
+ name: 'Welcome a new lead',
88
+ trigger: {
89
+ event: 'contactCreated',
90
+ conditions: [
91
+ {
92
+ field: 'source',
93
+ op: 'equals',
94
+ value: 'form'
95
+ }
96
+ ],
97
+ combinator: 'and'
98
+ },
99
+ steps: [
100
+ {
101
+ type: 'assignContactOwner',
102
+ roundRobin: true
103
+ },
104
+ {
105
+ type: 'createCrmTask',
106
+ title: 'Call the new lead',
107
+ kind: 'call',
108
+ dueInDays: 1
109
+ },
110
+ {
111
+ type: 'sendEmail',
112
+ subject: 'Thanks for getting in touch',
113
+ body: 'Thanks for reaching out. We have your message and will reply ' + 'to this email address.'
114
+ },
115
+ {
116
+ type: 'addContactTag',
117
+ tag: 'website'
118
+ }
119
+ ],
120
+ enabled: true
121
+ })
122
+ },
123
+ {
124
+ id: 'followUpWonDeal',
125
+ title: 'Follow up a won deal',
126
+ description: 'When a deal is won — which makes the contact a Customer on its own — ' + 'book a check-in call a week out.',
127
+ /*
128
+ * No stage step (AGL-2641): the win itself floors the contact at
129
+ * `customer` before `dealWon` is announced, so a step setting the stage
130
+ * here would at best repeat the write and at worst move an evangelist
131
+ * back to customer — a SET, which is what the step is, and not the
132
+ * floor the win applies. The recipe books the follow-up and nothing
133
+ * else.
134
+ */ build: ()=>({
135
+ recipe: 'followUpWonDeal',
136
+ name: 'Follow up a won deal',
137
+ trigger: {
138
+ event: 'dealWon'
139
+ },
140
+ steps: [
141
+ {
142
+ type: 'createCrmTask',
143
+ title: 'Check in with the new customer',
144
+ kind: 'call',
145
+ dueInDays: 7
146
+ }
147
+ ],
148
+ enabled: true
149
+ })
150
+ },
151
+ {
152
+ id: 'reengageStaleLead',
153
+ title: 'Re-engage a stale lead',
154
+ description: 'When a contact becomes a lead: wait a week, and if their stage has ' + 'not moved, book a call to bring them back.',
155
+ /*
156
+ * "Unless the stage moved on" is the wait's own event: the flow watches
157
+ * for the next stage change on this person and gives up after a week.
158
+ * Resumed by the clock, the run carries `_waitTimedOut`, and the task
159
+ * step's guard reads it; resumed by the event, the field is absent and
160
+ * the task is skipped — the lead was worked, and nobody is told to
161
+ * re-engage somebody who just moved to Sales qualified.
162
+ */ build: ()=>({
163
+ recipe: 'reengageStaleLead',
164
+ name: 'Re-engage a stale lead',
165
+ trigger: {
166
+ event: 'contactStageChanged',
167
+ conditions: [
168
+ {
169
+ field: 'lifecycleStage',
170
+ op: 'equals',
171
+ value: 'lead'
172
+ }
173
+ ],
174
+ combinator: 'and'
175
+ },
176
+ steps: [
177
+ {
178
+ type: 'waitForEvent',
179
+ eventName: 'contactStageChanged',
180
+ timeoutMinutes: STALE_LEAD_WAIT_MINUTES
181
+ },
182
+ {
183
+ type: 'createCrmTask',
184
+ title: 'Re-engage a lead that has gone quiet',
185
+ kind: 'call',
186
+ dueInDays: 1,
187
+ when: {
188
+ conditions: [
189
+ {
190
+ field: WAIT_TIMED_OUT_FIELD,
191
+ op: 'notEmpty'
192
+ }
193
+ ]
194
+ }
195
+ }
196
+ ],
197
+ enabled: true
198
+ })
199
+ },
200
+ {
201
+ id: 'tagByForm',
202
+ title: 'Tag by form',
203
+ description: 'When a form you pick makes a new contact: tag them with the form’s ' + 'name.',
204
+ picks: {
205
+ kind: 'form',
206
+ label: 'Form',
207
+ plural: 'forms',
208
+ prompt: 'Pick the form whose new contacts get the tag.',
209
+ none: 'This site has no forms yet. Add one in the besigner, then come back.'
210
+ },
211
+ build: (input)=>{
212
+ var _ref;
213
+ const form = input == null ? void 0 : input.picked;
214
+ return {
215
+ recipe: 'tagByForm',
216
+ name: form ? `Tag ${form.name.trim()} submissions` : 'Tag by form',
217
+ trigger: {
218
+ event: 'contactCreated',
219
+ conditions: [
220
+ {
221
+ field: 'formId',
222
+ op: 'equals',
223
+ value: (_ref = form == null ? void 0 : form.id) != null ? _ref : ''
224
+ }
225
+ ],
226
+ combinator: 'and'
227
+ },
228
+ steps: [
229
+ {
230
+ type: 'addContactTag',
231
+ tag: form ? crmRecipeTagForForm(form.name) : ''
232
+ }
233
+ ],
234
+ enabled: true
235
+ };
236
+ }
237
+ }
238
+ ];
239
+ /** The recipe with this id, or null for a string that names none. */ export function crmActionRecipe(id) {
240
+ var _CRM_ACTION_RECIPES_find;
241
+ return (_CRM_ACTION_RECIPES_find = CRM_ACTION_RECIPES.find((recipe)=>recipe.id === id)) != null ? _CRM_ACTION_RECIPES_find : null;
242
+ }
243
+
244
+ //# sourceMappingURL=crm-recipes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-recipes.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CONTACT_TAG_MAX_LENGTH } from '@aglyn/aglyn/app-utils/crm-kinds'\nimport type {\n InteractionRecipe,\n InteractionRecipeInput,\n} from '@aglyn/aglyn/plugin-manager/interaction-recipes'\n\n/*\n * THE CRM'S RECIPES (AGL-2626).\n *\n * A recipe is a ready-to-edit automation — a trigger, its conditions and an\n * ordered step list — built from the vocabulary the automation editor already\n * offers and handed to that editor as a draft. Nothing is written until the\n * person saves, and every field is theirs to change first: the recipe decides\n * where the editor starts, not what the site runs.\n *\n * The CRM's own, because what each one is FOR is the CRM's: who a new lead is,\n * when a deal is won, when a lead has gone quiet. They reach the automation\n * editor through the platform's recipe seam\n * (`plugin-manager/interaction-recipes`, AGL-3080), registered from this\n * plugin's declarations; the org hub's Recipes card and its install routes\n * read them here. Their ids are declared in `plugins.config.json`\n * (`interactionRecipes`) because a stored automation names one.\n *\n * Definitions only. Three of the four are complete as written. `tagByForm`\n * needs a form, and a form belongs to a site, so the picker that supplies it\n * is the editor's business and host-scoped by nature. That is the seam an\n * org-level mount keeps: the recipes are the same at either level, and only\n * the form picker knows where it is.\n */\nexport const CRM_ACTION_RECIPE_IDS = [\n 'welcomeNewLead',\n 'followUpWonDeal',\n 'reengageStaleLead',\n 'tagByForm',\n] as const\n\nexport type CrmActionRecipeId = (typeof CRM_ACTION_RECIPE_IDS)[number]\n\n/** What a recipe is handed before it builds — today only the form `tagByForm` reads. */\nexport type CrmActionRecipeInput = InteractionRecipeInput\n\nexport interface CrmActionRecipe extends InteractionRecipe {\n id: CrmActionRecipeId\n}\n\n/**\n * The field a resumed wait carries in its scope when it ended on the CLOCK\n * rather than on the event it watched for — the automation engine's word for\n * it, written into the step guard the stale-lead recipe stores.\n */\nconst WAIT_TIMED_OUT_FIELD = '_waitTimedOut'\n\n/**\n * How long the stale-lead recipe holds before it decides a lead has gone\n * quiet. A week: long enough that a rep who is working the lead has had a\n * chance to move its stage, short enough that a lead nobody touched is\n * still warm when the reminder lands.\n */\nexport const STALE_LEAD_WAIT_MINUTES = 7 * 24 * 60\n\n/**\n * The tag a form's captures get: the form's own name, cut to the tag cap.\n * The name is what the person calls the form, so it is the tag they would\n * have typed; the editor is open to change it before anything is saved.\n */\nexport function crmRecipeTagForForm(formName: string): string {\n return formName.trim().slice(0, CONTACT_TAG_MAX_LENGTH)\n}\n\nexport const CRM_ACTION_RECIPES: readonly CrmActionRecipe[] = [\n {\n id: 'welcomeNewLead',\n title: 'Welcome a new lead',\n description:\n 'When a form makes a new contact: rotate in an owner, book a call for ' +\n 'tomorrow, send a thank-you, and tag them website.',\n /*\n * The owner first, because the task that follows names no assignee and\n * so goes to whoever owns the contact when it is created — the member\n * the rotation just chose. Round robin rather than a named member: a\n * recipe cannot know who is on the team, and the pool under CRM →\n * Settings is the one place that does. On a workspace with no pool the\n * step fails and the run continues, so the call, the email and the tag\n * still land and the run history says who was not assigned.\n *\n * The email comes before any wait, which makes it an immediate reply to\n * what the visitor just did — transactional, sent from the org's own\n * identity, to the address the event carries.\n *\n * Its words promise no response time. The org hub installs this recipe\n * into a site without its editor opening, so the business never reads\n * the sentence it is sending, and a \"within a day\" written here would be\n * a commitment made on its behalf that nothing in the run keeps.\n */\n build: () => ({\n recipe: 'welcomeNewLead',\n name: 'Welcome a new lead',\n trigger: {\n event: 'contactCreated',\n conditions: [{ field: 'source', op: 'equals', value: 'form' }],\n combinator: 'and',\n },\n steps: [\n { type: 'assignContactOwner', roundRobin: true },\n {\n type: 'createCrmTask',\n title: 'Call the new lead',\n kind: 'call',\n dueInDays: 1,\n },\n {\n type: 'sendEmail',\n subject: 'Thanks for getting in touch',\n body:\n 'Thanks for reaching out. We have your message and will reply ' +\n 'to this email address.',\n },\n { type: 'addContactTag', tag: 'website' },\n ],\n enabled: true,\n }),\n },\n {\n id: 'followUpWonDeal',\n title: 'Follow up a won deal',\n description:\n 'When a deal is won — which makes the contact a Customer on its own — ' +\n 'book a check-in call a week out.',\n /*\n * No stage step (AGL-2641): the win itself floors the contact at\n * `customer` before `dealWon` is announced, so a step setting the stage\n * here would at best repeat the write and at worst move an evangelist\n * back to customer — a SET, which is what the step is, and not the\n * floor the win applies. The recipe books the follow-up and nothing\n * else.\n */\n build: () => ({\n recipe: 'followUpWonDeal',\n name: 'Follow up a won deal',\n trigger: { event: 'dealWon' },\n steps: [\n {\n type: 'createCrmTask',\n title: 'Check in with the new customer',\n kind: 'call',\n dueInDays: 7,\n },\n ],\n enabled: true,\n }),\n },\n {\n id: 'reengageStaleLead',\n title: 'Re-engage a stale lead',\n description:\n 'When a contact becomes a lead: wait a week, and if their stage has ' +\n 'not moved, book a call to bring them back.',\n /*\n * \"Unless the stage moved on\" is the wait's own event: the flow watches\n * for the next stage change on this person and gives up after a week.\n * Resumed by the clock, the run carries `_waitTimedOut`, and the task\n * step's guard reads it; resumed by the event, the field is absent and\n * the task is skipped — the lead was worked, and nobody is told to\n * re-engage somebody who just moved to Sales qualified.\n */\n build: () => ({\n recipe: 'reengageStaleLead',\n name: 'Re-engage a stale lead',\n trigger: {\n event: 'contactStageChanged',\n conditions: [{ field: 'lifecycleStage', op: 'equals', value: 'lead' }],\n combinator: 'and',\n },\n steps: [\n {\n type: 'waitForEvent',\n eventName: 'contactStageChanged',\n timeoutMinutes: STALE_LEAD_WAIT_MINUTES,\n },\n {\n type: 'createCrmTask',\n title: 'Re-engage a lead that has gone quiet',\n kind: 'call',\n dueInDays: 1,\n when: {\n conditions: [{ field: WAIT_TIMED_OUT_FIELD, op: 'notEmpty' }],\n },\n },\n ],\n enabled: true,\n }),\n },\n {\n id: 'tagByForm',\n title: 'Tag by form',\n description:\n 'When a form you pick makes a new contact: tag them with the form’s ' +\n 'name.',\n picks: {\n kind: 'form',\n label: 'Form',\n plural: 'forms',\n prompt: 'Pick the form whose new contacts get the tag.',\n none: 'This site has no forms yet. Add one in the besigner, then come back.',\n },\n build: (input) => {\n const form = input?.picked\n return {\n recipe: 'tagByForm',\n name: form ? `Tag ${form.name.trim()} submissions` : 'Tag by form',\n trigger: {\n event: 'contactCreated',\n conditions: [{ field: 'formId', op: 'equals', value: form?.id ?? '' }],\n combinator: 'and',\n },\n steps: [{ type: 'addContactTag', tag: form ? crmRecipeTagForForm(form.name) : '' }],\n enabled: true,\n }\n },\n },\n]\n\n/** The recipe with this id, or null for a string that names none. */\nexport function crmActionRecipe(id: unknown): CrmActionRecipe | null {\n return CRM_ACTION_RECIPES.find((recipe) => recipe.id === id) ?? null\n}\n"],"names":["CONTACT_TAG_MAX_LENGTH","CRM_ACTION_RECIPE_IDS","WAIT_TIMED_OUT_FIELD","STALE_LEAD_WAIT_MINUTES","crmRecipeTagForForm","formName","trim","slice","CRM_ACTION_RECIPES","id","title","description","build","recipe","name","trigger","event","conditions","field","op","value","combinator","steps","type","roundRobin","kind","dueInDays","subject","body","tag","enabled","eventName","timeoutMinutes","when","picks","label","plural","prompt","none","input","form","picked","crmActionRecipe","find"],"mappings":"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"}
@@ -0,0 +1,36 @@
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 PluginRecordCountSource } from '@aglyn/aglyn/plugin-manager/plugin-record-counts';
18
+ /**
19
+ * The leads a site CAPTURED (AGL-3275), counted for another plugin's figure
20
+ * (AGL-3080). A lead is one document per person under the organization,
21
+ * stamped in `capturedByHostIds` with every site that met them — so this is
22
+ * exactly the population a site's own lead outcomes are drawn from.
23
+ *
24
+ * Not `visibleTo`: that also names the sites a consent group shares a person
25
+ * with. The price is that a collaborator scoped to one site cannot run the
26
+ * count — the rules prove a lead read by `visibleTo` — and the reader
27
+ * withholds the figure for them.
28
+ */
29
+ export declare const leadRecordCountSource: PluginRecordCountSource;
30
+ /**
31
+ * The organization's contacts — ONE row per person for every site in it, so
32
+ * the count crosses sites, which the reader is told.
33
+ */
34
+ export declare const contactRecordCountSource: PluginRecordCountSource;
35
+ /** Called from the console registrar, owner named for a spec that calls it directly. */
36
+ export declare function registerCrmRecordCounts(): void;
@@ -0,0 +1,54 @@
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
+ */ import { CAPTURED_BY_HOST_FIELD } from "@aglyn/aglyn/app-utils/marketing-consent";
17
+ import { registerPluginRecordCountSource } from "@aglyn/aglyn/plugin-manager/plugin-record-counts";
18
+ import { collection, query, where } from "firebase/firestore";
19
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
20
+ /**
21
+ * The leads a site CAPTURED (AGL-3275), counted for another plugin's figure
22
+ * (AGL-3080). A lead is one document per person under the organization,
23
+ * stamped in `capturedByHostIds` with every site that met them — so this is
24
+ * exactly the population a site's own lead outcomes are drawn from.
25
+ *
26
+ * Not `visibleTo`: that also names the sites a consent group shares a person
27
+ * with. The price is that a collaborator scoped to one site cannot run the
28
+ * count — the rules prove a lead read by `visibleTo` — and the reader
29
+ * withholds the figure for them.
30
+ */ export const leadRecordCountSource = {
31
+ query (firestore, request) {
32
+ if (!request.orgId || !request.hostId) return null;
33
+ return query(collection(firestore, 'orgs', request.orgId, 'leads'), where(CAPTURED_BY_HOST_FIELD, 'array-contains', request.hostId));
34
+ }
35
+ };
36
+ /**
37
+ * The organization's contacts — ONE row per person for every site in it, so
38
+ * the count crosses sites, which the reader is told.
39
+ */ export const contactRecordCountSource = {
40
+ query (firestore, request) {
41
+ return request.orgId ? collection(firestore, 'orgs', request.orgId, 'contacts') : null;
42
+ },
43
+ crossesSites: true
44
+ };
45
+ /** Called from the console registrar, owner named for a spec that calls it directly. */ export function registerCrmRecordCounts() {
46
+ registerPluginRecordCountSource('lead', leadRecordCountSource, {
47
+ pluginId: BUNDLE_ID
48
+ });
49
+ registerPluginRecordCountSource('contact', contactRecordCountSource, {
50
+ pluginId: BUNDLE_ID
51
+ });
52
+ }
53
+
54
+ //# sourceMappingURL=crm-record-counts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-record-counts.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CAPTURED_BY_HOST_FIELD } from '@aglyn/aglyn/app-utils/marketing-consent'\nimport {\n registerPluginRecordCountSource,\n type PluginRecordCountSource,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-counts'\nimport { collection, query, where } from 'firebase/firestore'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * The leads a site CAPTURED (AGL-3275), counted for another plugin's figure\n * (AGL-3080). A lead is one document per person under the organization,\n * stamped in `capturedByHostIds` with every site that met them — so this is\n * exactly the population a site's own lead outcomes are drawn from.\n *\n * Not `visibleTo`: that also names the sites a consent group shares a person\n * with. The price is that a collaborator scoped to one site cannot run the\n * count — the rules prove a lead read by `visibleTo` — and the reader\n * withholds the figure for them.\n */\nexport const leadRecordCountSource: PluginRecordCountSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, 'leads'),\n where(CAPTURED_BY_HOST_FIELD, 'array-contains', request.hostId),\n )\n },\n}\n\n/**\n * The organization's contacts — ONE row per person for every site in it, so\n * the count crosses sites, which the reader is told.\n */\nexport const contactRecordCountSource: PluginRecordCountSource = {\n query(firestore, request) {\n return request.orgId ? collection(firestore, 'orgs', request.orgId, 'contacts') : null\n },\n crossesSites: true,\n}\n\n/** Called from the console registrar, owner named for a spec that calls it directly. */\nexport function registerCrmRecordCounts(): void {\n registerPluginRecordCountSource('lead', leadRecordCountSource, { pluginId: BUNDLE_ID })\n registerPluginRecordCountSource('contact', contactRecordCountSource, { pluginId: BUNDLE_ID })\n}\n"],"names":["CAPTURED_BY_HOST_FIELD","registerPluginRecordCountSource","collection","query","where","BUNDLE_ID","leadRecordCountSource","firestore","request","orgId","hostId","contactRecordCountSource","crossesSites","registerCrmRecordCounts","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAAQ,2CAA0C;AACjF,SACEC,+BAA+B,QAE1B,mDAAkD;AACzD,SAASC,UAAU,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAC7D,SAASC,SAAS,QAAQ,gCAA4B;AAEtD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,wBAAiD;IAC5DH,OAAMI,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,IAAI,CAACD,QAAQE,MAAM,EAAE,OAAO;QAC9C,OAAOP,MACLD,WAAWK,WAAW,QAAQC,QAAQC,KAAK,EAAE,UAC7CL,MAAMJ,wBAAwB,kBAAkBQ,QAAQE,MAAM;IAElE;AACF,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,2BAAoD;IAC/DR,OAAMI,SAAS,EAAEC,OAAO;QACtB,OAAOA,QAAQC,KAAK,GAAGP,WAAWK,WAAW,QAAQC,QAAQC,KAAK,EAAE,cAAc;IACpF;IACAG,cAAc;AAChB,EAAC;AAED,sFAAsF,GACtF,OAAO,SAASC;IACdZ,gCAAgC,QAAQK,uBAAuB;QAAEQ,UAAUT;IAAU;IACrFJ,gCAAgC,WAAWU,0BAA0B;QAAEG,UAAUT;IAAU;AAC7F"}
@@ -0,0 +1,23 @@
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 PluginRecordListSource } from '@aglyn/aglyn/plugin-manager/plugin-record-lists';
18
+ export declare const savedViewRecordListSource: PluginRecordListSource;
19
+ export declare const messageTemplateRecordListSource: PluginRecordListSource;
20
+ export declare const contactRecordListSource: PluginRecordListSource;
21
+ export declare const leadRecordListSource: PluginRecordListSource;
22
+ /** Called from the console registrar, owner named for a spec that calls it directly. */
23
+ export declare function registerCrmRecordLists(): void;
@@ -0,0 +1,161 @@
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
+ */ import { contactDisplayName, normalizeContactEmail } from "@aglyn/aglyn/app-utils/contacts";
17
+ import { CRM_COLLECTIONS, crmLeadDisplayName, crmViewIsListed, isCrmLeadOpen, normalizeCrmViewFilters } from "@aglyn/aglyn/app-utils/crm";
18
+ import { CRM_EMAIL_TEMPLATES_LIMIT, crmEmailTemplateIsListed, normalizeCrmEmailTemplate } from "@aglyn/aglyn/app-utils/crm-email-templates";
19
+ import { dynamicListDimensionsForCrmView } from "@aglyn/aglyn/app-utils/dynamic-list-rule";
20
+ import { nameSearchToken } from "@aglyn/aglyn/app-utils/name-search";
21
+ import { scopeTokensForHost, visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
22
+ import { registerPluginRecordListSource } from "@aglyn/aglyn/plugin-manager/plugin-record-lists";
23
+ import { collection, limit, orderBy, query, where } from "firebase/firestore";
24
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
25
+ /**
26
+ * The CRM's records, FOUND in the console for another plugin's picker
27
+ * (AGL-3080) — a sales sequence choosing whom to enroll and what to send —
28
+ * through `plugin-record-lists`, so the reader never learns where the CRM
29
+ * keeps any of it or which rule its security rules hold a query to.
30
+ *
31
+ * Four kinds, each org-scoped (`orgId` required) and each the query the
32
+ * CRM's own console reads the same records by:
33
+ *
34
+ * `savedView` — the saved views of the Contacts and Leads lists this member
35
+ * may list: their own and the shared ones. Facts:
36
+ * `{ recordKind: 'contact' | 'lead', takeable: boolean }`. `takeable` is
37
+ * whether the view can be taken whole as an audience: a Leads view narrows by
38
+ * status alone, which is always applied; a Contacts view filtering on
39
+ * something only the list itself can apply is not, because dropping that
40
+ * filter would take more people than the view shows.
41
+ *
42
+ * `messageTemplate` — the email templates and snippets this member may list,
43
+ * written for the whole organization or for the named site. Facts:
44
+ * `{ kind: 'template' | 'snippet', subject, body }`.
45
+ *
46
+ * `contact` — a SEARCH of the site's contacts: by address when the text is
47
+ * one, otherwise by a word of the name. None with nothing typed. Named as the
48
+ * site's consent group knows them. Facts: `{ email }`.
49
+ *
50
+ * `lead` — the site's most recently seen leads, newest first. Facts:
51
+ * `{ email, open }`, `open` being a lead nobody has closed or converted.
52
+ */ const named = (value)=>typeof value === 'string' ? value.trim() : '';
53
+ export const savedViewRecordListSource = {
54
+ query (firestore, request) {
55
+ if (!request.orgId) return null;
56
+ return query(collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.views), where('section', 'in', [
57
+ 'contacts',
58
+ 'leads'
59
+ ]), orderBy('name'), limit(request.limit));
60
+ },
61
+ record (id, data, request) {
62
+ var _data_ownerUid, _ref;
63
+ const name = named(data['name']);
64
+ if (!name) return null;
65
+ // A colleague's private view is theirs.
66
+ if (!crmViewIsListed({
67
+ shared: data['shared'] === true,
68
+ ownerUid: String((_data_ownerUid = data['ownerUid']) != null ? _data_ownerUid : '')
69
+ }, (_ref = request == null ? void 0 : request.viewerUid) != null ? _ref : null)) {
70
+ return null;
71
+ }
72
+ const leads = data['section'] === 'leads';
73
+ const takeable = leads || dynamicListDimensionsForCrmView(normalizeCrmViewFilters(data['filters'])).unsupported.length === 0;
74
+ return {
75
+ id,
76
+ name,
77
+ facts: {
78
+ recordKind: leads ? 'lead' : 'contact',
79
+ takeable
80
+ }
81
+ };
82
+ }
83
+ };
84
+ export const messageTemplateRecordListSource = {
85
+ query (firestore, request) {
86
+ if (!request.orgId) return null;
87
+ return query(collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.emailTemplates), orderBy('name'), limit(Math.min(request.limit, CRM_EMAIL_TEMPLATES_LIMIT)));
88
+ },
89
+ record (id, data, request) {
90
+ var _ref;
91
+ const template = normalizeCrmEmailTemplate(data);
92
+ if (!template.name) return null;
93
+ // The team's and this member's own, written for the organization or the site.
94
+ if (!crmEmailTemplateIsListed(template, (_ref = request == null ? void 0 : request.viewerUid) != null ? _ref : null)) return null;
95
+ if ((request == null ? void 0 : request.hostId) && !visibleToHost(template.visibleTo, request.hostId)) return null;
96
+ return {
97
+ id,
98
+ name: template.name,
99
+ facts: {
100
+ kind: template.kind,
101
+ subject: template.subject,
102
+ body: template.body
103
+ }
104
+ };
105
+ }
106
+ };
107
+ export const contactRecordListSource = {
108
+ query (firestore, request) {
109
+ if (!request.orgId || !request.hostId) return null;
110
+ const email = normalizeContactEmail(request.search);
111
+ const token = email ? '' : nameSearchToken(request.search);
112
+ if (!email && !token) return null;
113
+ const contacts = collection(firestore, 'orgs', request.orgId, 'contacts');
114
+ return email ? query(contacts, where('email', '==', email), limit(request.limit)) : query(contacts, where('nameTokens', 'array-contains', token), orderBy('nameLower'), limit(request.limit));
115
+ },
116
+ record (id, data, request) {
117
+ const hostId = request == null ? void 0 : request.hostId;
118
+ if (hostId && !visibleToHost(data['visibleTo'], hostId)) return null;
119
+ const email = normalizeContactEmail(data['email']);
120
+ const name = contactDisplayName(data, (request == null ? void 0 : request.consentGroupId) || hostId || '').trim() || email || '';
121
+ if (!name) return null;
122
+ return {
123
+ id,
124
+ name,
125
+ facts: {
126
+ email
127
+ }
128
+ };
129
+ }
130
+ };
131
+ export const leadRecordListSource = {
132
+ query (firestore, request) {
133
+ if (!request.orgId || !request.hostId) return null;
134
+ // The org collection, narrowed to the site (AGL-3275) — unscoped it would
135
+ // offer one agency client another client's people.
136
+ return query(collection(firestore, 'orgs', request.orgId, 'leads'), where('visibleTo', 'array-contains-any', scopeTokensForHost(request.hostId)), orderBy('lastSeenAtMs', 'desc'), limit(request.limit));
137
+ },
138
+ record (id, data) {
139
+ const name = crmLeadDisplayName(data);
140
+ if (!name) return null;
141
+ return {
142
+ id,
143
+ name,
144
+ facts: {
145
+ email: normalizeContactEmail(data['email']),
146
+ open: isCrmLeadOpen(data) && !data['convertedContactId']
147
+ }
148
+ };
149
+ }
150
+ };
151
+ /** Called from the console registrar, owner named for a spec that calls it directly. */ export function registerCrmRecordLists() {
152
+ const owner = {
153
+ pluginId: BUNDLE_ID
154
+ };
155
+ registerPluginRecordListSource('savedView', savedViewRecordListSource, owner);
156
+ registerPluginRecordListSource('messageTemplate', messageTemplateRecordListSource, owner);
157
+ registerPluginRecordListSource('contact', contactRecordListSource, owner);
158
+ registerPluginRecordListSource('lead', leadRecordListSource, owner);
159
+ }
160
+
161
+ //# sourceMappingURL=crm-record-lists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/model/crm-record-lists.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { contactDisplayName, normalizeContactEmail } from '@aglyn/aglyn/app-utils/contacts'\nimport {\n CRM_COLLECTIONS,\n crmLeadDisplayName,\n crmViewIsListed,\n isCrmLeadOpen,\n normalizeCrmViewFilters,\n} from '@aglyn/aglyn/app-utils/crm'\nimport {\n CRM_EMAIL_TEMPLATES_LIMIT,\n crmEmailTemplateIsListed,\n normalizeCrmEmailTemplate,\n} from '@aglyn/aglyn/app-utils/crm-email-templates'\nimport { dynamicListDimensionsForCrmView } from '@aglyn/aglyn/app-utils/dynamic-list-rule'\nimport { nameSearchToken } from '@aglyn/aglyn/app-utils/name-search'\nimport { scopeTokensForHost, visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n registerPluginRecordListSource,\n type PluginRecordListSource,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-lists'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * The CRM's records, FOUND in the console for another plugin's picker\n * (AGL-3080) — a sales sequence choosing whom to enroll and what to send —\n * through `plugin-record-lists`, so the reader never learns where the CRM\n * keeps any of it or which rule its security rules hold a query to.\n *\n * Four kinds, each org-scoped (`orgId` required) and each the query the\n * CRM's own console reads the same records by:\n *\n * `savedView` — the saved views of the Contacts and Leads lists this member\n * may list: their own and the shared ones. Facts:\n * `{ recordKind: 'contact' | 'lead', takeable: boolean }`. `takeable` is\n * whether the view can be taken whole as an audience: a Leads view narrows by\n * status alone, which is always applied; a Contacts view filtering on\n * something only the list itself can apply is not, because dropping that\n * filter would take more people than the view shows.\n *\n * `messageTemplate` — the email templates and snippets this member may list,\n * written for the whole organization or for the named site. Facts:\n * `{ kind: 'template' | 'snippet', subject, body }`.\n *\n * `contact` — a SEARCH of the site's contacts: by address when the text is\n * one, otherwise by a word of the name. None with nothing typed. Named as the\n * site's consent group knows them. Facts: `{ email }`.\n *\n * `lead` — the site's most recently seen leads, newest first. Facts:\n * `{ email, open }`, `open` being a lead nobody has closed or converted.\n */\n\nconst named = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\nexport const savedViewRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.views),\n where('section', 'in', ['contacts', 'leads']),\n orderBy('name'),\n limit(request.limit),\n )\n },\n record(id, data, request) {\n const name = named(data['name'])\n if (!name) return null\n // A colleague's private view is theirs.\n if (\n !crmViewIsListed(\n { shared: data['shared'] === true, ownerUid: String(data['ownerUid'] ?? '') },\n request?.viewerUid ?? null,\n )\n ) {\n return null\n }\n const leads = data['section'] === 'leads'\n const takeable =\n leads || dynamicListDimensionsForCrmView(normalizeCrmViewFilters(data['filters'])).unsupported.length === 0\n return { id, name, facts: { recordKind: leads ? 'lead' : 'contact', takeable } }\n },\n}\n\nexport const messageTemplateRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId) return null\n return query(\n collection(firestore, 'orgs', request.orgId, CRM_COLLECTIONS.emailTemplates),\n orderBy('name'),\n limit(Math.min(request.limit, CRM_EMAIL_TEMPLATES_LIMIT)),\n )\n },\n record(id, data, request) {\n const template = normalizeCrmEmailTemplate(data)\n if (!template.name) return null\n // The team's and this member's own, written for the organization or the site.\n if (!crmEmailTemplateIsListed(template, request?.viewerUid ?? null)) return null\n if (request?.hostId && !visibleToHost(template.visibleTo, request.hostId)) return null\n return {\n id,\n name: template.name,\n facts: { kind: template.kind, subject: template.subject, body: template.body },\n }\n },\n}\n\nexport const contactRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n const email = normalizeContactEmail(request.search)\n const token = email ? '' : nameSearchToken(request.search)\n if (!email && !token) return null\n const contacts = collection(firestore, 'orgs', request.orgId, 'contacts')\n return email\n ? query(contacts, where('email', '==', email), limit(request.limit))\n : query(contacts, where('nameTokens', 'array-contains', token), orderBy('nameLower'), limit(request.limit))\n },\n record(id, data, request) {\n const hostId = request?.hostId\n if (hostId && !visibleToHost(data['visibleTo'] as string[] | undefined, hostId)) return null\n const email = normalizeContactEmail(data['email'])\n const name = contactDisplayName(data, request?.consentGroupId || hostId || '').trim() || email || ''\n if (!name) return null\n return { id, name, facts: { email } }\n },\n}\n\nexport const leadRecordListSource: PluginRecordListSource = {\n query(firestore, request) {\n if (!request.orgId || !request.hostId) return null\n // The org collection, narrowed to the site (AGL-3275) — unscoped it would\n // offer one agency client another client's people.\n return query(\n collection(firestore, 'orgs', request.orgId, 'leads'),\n where('visibleTo', 'array-contains-any', scopeTokensForHost(request.hostId)),\n orderBy('lastSeenAtMs', 'desc'),\n limit(request.limit),\n )\n },\n record(id, data) {\n const name = crmLeadDisplayName(data)\n if (!name) return null\n return {\n id,\n name,\n facts: {\n email: normalizeContactEmail(data['email']),\n open: isCrmLeadOpen(data as never) && !data['convertedContactId'],\n },\n }\n },\n}\n\n/** Called from the console registrar, owner named for a spec that calls it directly. */\nexport function registerCrmRecordLists(): void {\n const owner = { pluginId: BUNDLE_ID }\n registerPluginRecordListSource('savedView', savedViewRecordListSource, owner)\n registerPluginRecordListSource('messageTemplate', messageTemplateRecordListSource, owner)\n registerPluginRecordListSource('contact', contactRecordListSource, owner)\n registerPluginRecordListSource('lead', leadRecordListSource, owner)\n}\n"],"names":["contactDisplayName","normalizeContactEmail","CRM_COLLECTIONS","crmLeadDisplayName","crmViewIsListed","isCrmLeadOpen","normalizeCrmViewFilters","CRM_EMAIL_TEMPLATES_LIMIT","crmEmailTemplateIsListed","normalizeCrmEmailTemplate","dynamicListDimensionsForCrmView","nameSearchToken","scopeTokensForHost","visibleToHost","registerPluginRecordListSource","collection","limit","orderBy","query","where","BUNDLE_ID","named","value","trim","savedViewRecordListSource","firestore","request","orgId","views","record","id","data","name","shared","ownerUid","String","viewerUid","leads","takeable","unsupported","length","facts","recordKind","messageTemplateRecordListSource","emailTemplates","Math","min","template","hostId","visibleTo","kind","subject","body","contactRecordListSource","email","search","token","contacts","consentGroupId","leadRecordListSource","open","registerCrmRecordLists","owner","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,kBAAkB,EAAEC,qBAAqB,QAAQ,kCAAiC;AAC3F,SACEC,eAAe,EACfC,kBAAkB,EAClBC,eAAe,EACfC,aAAa,EACbC,uBAAuB,QAClB,6BAA4B;AACnC,SACEC,yBAAyB,EACzBC,wBAAwB,EACxBC,yBAAyB,QACpB,6CAA4C;AACnD,SAASC,+BAA+B,QAAQ,2CAA0C;AAC1F,SAASC,eAAe,QAAQ,qCAAoC;AACpE,SAASC,kBAAkB,EAAEC,aAAa,QAAQ,sCAAqC;AACvF,SACEC,8BAA8B,QAEzB,kDAAiD;AACxD,SAASC,UAAU,EAAEC,KAAK,EAAEC,OAAO,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAC7E,SAASC,SAAS,QAAQ,gCAA4B;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GAED,MAAMC,QAAQ,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AAEtF,OAAO,MAAMC,4BAAoD;IAC/DN,OAAMO,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,EAAE,OAAO;QAC3B,OAAOT,MACLH,WAAWU,WAAW,QAAQC,QAAQC,KAAK,EAAEzB,gBAAgB0B,KAAK,GAClET,MAAM,WAAW,MAAM;YAAC;YAAY;SAAQ,GAC5CF,QAAQ,SACRD,MAAMU,QAAQV,KAAK;IAEvB;IACAa,QAAOC,EAAE,EAAEC,IAAI,EAAEL,OAAO;YAMkCK;QALxD,MAAMC,OAAOX,MAAMU,IAAI,CAAC,OAAO;QAC/B,IAAI,CAACC,MAAM,OAAO;QAClB,wCAAwC;QACxC,IACE,CAAC5B,gBACC;YAAE6B,QAAQF,IAAI,CAAC,SAAS,KAAK;YAAMG,UAAUC,QAAOJ,iBAAAA,IAAI,CAAC,WAAW,YAAhBA,iBAAoB;QAAI,WAC5EL,2BAAAA,QAASU,SAAS,mBAAI,OAExB;YACA,OAAO;QACT;QACA,MAAMC,QAAQN,IAAI,CAAC,UAAU,KAAK;QAClC,MAAMO,WACJD,SAAS3B,gCAAgCJ,wBAAwByB,IAAI,CAAC,UAAU,GAAGQ,WAAW,CAACC,MAAM,KAAK;QAC5G,OAAO;YAAEV;YAAIE;YAAMS,OAAO;gBAAEC,YAAYL,QAAQ,SAAS;gBAAWC;YAAS;QAAE;IACjF;AACF,EAAC;AAED,OAAO,MAAMK,kCAA0D;IACrEzB,OAAMO,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,EAAE,OAAO;QAC3B,OAAOT,MACLH,WAAWU,WAAW,QAAQC,QAAQC,KAAK,EAAEzB,gBAAgB0C,cAAc,GAC3E3B,QAAQ,SACRD,MAAM6B,KAAKC,GAAG,CAACpB,QAAQV,KAAK,EAAET;IAElC;IACAsB,QAAOC,EAAE,EAAEC,IAAI,EAAEL,OAAO;;QACtB,MAAMqB,WAAWtC,0BAA0BsB;QAC3C,IAAI,CAACgB,SAASf,IAAI,EAAE,OAAO;QAC3B,8EAA8E;QAC9E,IAAI,CAACxB,yBAAyBuC,kBAAUrB,2BAAAA,QAASU,SAAS,mBAAI,OAAO,OAAO;QAC5E,IAAIV,CAAAA,2BAAAA,QAASsB,MAAM,KAAI,CAACnC,cAAckC,SAASE,SAAS,EAAEvB,QAAQsB,MAAM,GAAG,OAAO;QAClF,OAAO;YACLlB;YACAE,MAAMe,SAASf,IAAI;YACnBS,OAAO;gBAAES,MAAMH,SAASG,IAAI;gBAAEC,SAASJ,SAASI,OAAO;gBAAEC,MAAML,SAASK,IAAI;YAAC;QAC/E;IACF;AACF,EAAC;AAED,OAAO,MAAMC,0BAAkD;IAC7DnC,OAAMO,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,IAAI,CAACD,QAAQsB,MAAM,EAAE,OAAO;QAC9C,MAAMM,QAAQrD,sBAAsByB,QAAQ6B,MAAM;QAClD,MAAMC,QAAQF,QAAQ,KAAK3C,gBAAgBe,QAAQ6B,MAAM;QACzD,IAAI,CAACD,SAAS,CAACE,OAAO,OAAO;QAC7B,MAAMC,WAAW1C,WAAWU,WAAW,QAAQC,QAAQC,KAAK,EAAE;QAC9D,OAAO2B,QACHpC,MAAMuC,UAAUtC,MAAM,SAAS,MAAMmC,QAAQtC,MAAMU,QAAQV,KAAK,KAChEE,MAAMuC,UAAUtC,MAAM,cAAc,kBAAkBqC,QAAQvC,QAAQ,cAAcD,MAAMU,QAAQV,KAAK;IAC7G;IACAa,QAAOC,EAAE,EAAEC,IAAI,EAAEL,OAAO;QACtB,MAAMsB,SAAStB,2BAAAA,QAASsB,MAAM;QAC9B,IAAIA,UAAU,CAACnC,cAAckB,IAAI,CAAC,YAAY,EAA0BiB,SAAS,OAAO;QACxF,MAAMM,QAAQrD,sBAAsB8B,IAAI,CAAC,QAAQ;QACjD,MAAMC,OAAOhC,mBAAmB+B,MAAML,CAAAA,2BAAAA,QAASgC,cAAc,KAAIV,UAAU,IAAIzB,IAAI,MAAM+B,SAAS;QAClG,IAAI,CAACtB,MAAM,OAAO;QAClB,OAAO;YAAEF;YAAIE;YAAMS,OAAO;gBAAEa;YAAM;QAAE;IACtC;AACF,EAAC;AAED,OAAO,MAAMK,uBAA+C;IAC1DzC,OAAMO,SAAS,EAAEC,OAAO;QACtB,IAAI,CAACA,QAAQC,KAAK,IAAI,CAACD,QAAQsB,MAAM,EAAE,OAAO;QAC9C,0EAA0E;QAC1E,mDAAmD;QACnD,OAAO9B,MACLH,WAAWU,WAAW,QAAQC,QAAQC,KAAK,EAAE,UAC7CR,MAAM,aAAa,sBAAsBP,mBAAmBc,QAAQsB,MAAM,IAC1E/B,QAAQ,gBAAgB,SACxBD,MAAMU,QAAQV,KAAK;IAEvB;IACAa,QAAOC,EAAE,EAAEC,IAAI;QACb,MAAMC,OAAO7B,mBAAmB4B;QAChC,IAAI,CAACC,MAAM,OAAO;QAClB,OAAO;YACLF;YACAE;YACAS,OAAO;gBACLa,OAAOrD,sBAAsB8B,IAAI,CAAC,QAAQ;gBAC1C6B,MAAMvD,cAAc0B,SAAkB,CAACA,IAAI,CAAC,qBAAqB;YACnE;QACF;IACF;AACF,EAAC;AAED,sFAAsF,GACtF,OAAO,SAAS8B;IACd,MAAMC,QAAQ;QAAEC,UAAU3C;IAAU;IACpCN,+BAA+B,aAAaU,2BAA2BsC;IACvEhD,+BAA+B,mBAAmB6B,iCAAiCmB;IACnFhD,+BAA+B,WAAWuC,yBAAyBS;IACnEhD,+BAA+B,QAAQ6C,sBAAsBG;AAC/D"}