@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
@@ -17,7 +17,12 @@
17
17
  // registry, not the whole server surface.
18
18
  import { registerApiV1Resource, registerApiV1UsageFigures } from "@aglyn/tenant-data-admin/server/api-v1-resources";
19
19
  import { listPluginMembershipDetachers, registerPluginMembershipDetacher } from "@aglyn/aglyn/plugin-manager/plugin-membership-detach";
20
+ import { registerPluginPersonRecordsEraser } from "@aglyn/aglyn/plugin-manager/plugin-person-erasure";
21
+ import { registerPluginTransferResource } from "@aglyn/aglyn/plugin-manager/plugin-transfer-resources";
20
22
  import { BUNDLE_ID } from "./constants/bundle-common.js";
23
+ import { crmTransferPlanGate, registerCrmTransferResources } from "./transfer/register.js";
24
+ import { CRM_EMAIL_TEMPLATE_PACKAGE_RULES, CRM_EMAIL_TEMPLATES_TRANSFER_KEY, crmEmailTemplateDependencies, remapCrmEmailTemplateIds } from "./transfer/email-templates-package.js";
25
+ /** The email templates package's server half (AGL-3535), loaded when an import or export first asks. */ const templatesPackage = async ()=>(await import("./transfer/email-templates-package.server.js")).createCrmEmailTemplatesPackage();
21
26
  /**
22
27
  * The plan feature every CRM resource of `/v1` needs, and the sentence its
23
28
  * refusal says (AGL-2611, AGL-2851): the whole CRM is included from
@@ -81,6 +86,9 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
81
86
  * records band and collection sizes join `GET /v1/usage`. The API is the
82
87
  * console's alone, so the tenant runtime does not register them.
83
88
  *
89
+ * It registers the server half of the CRM's import and export resources
90
+ * (`transfer/register.ts`).
91
+ *
84
92
  * It also clears a removed container off the CRM's records: a campaign is
85
93
  * deleted from the console, and its owner asks every plugin's membership
86
94
  * detacher first (`server/container-detach.ts`).
@@ -91,6 +99,30 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
91
99
  * Registering again replaces this plugin's own entries, so a second call (a
92
100
  * hot reload, a spec) is harmless.
93
101
  */ export function registerCrmConsoleServerDeclarations() {
102
+ // Email templates in a workspace package (AGL-3535).
103
+ registerPluginTransferResource(CRM_EMAIL_TEMPLATES_TRANSFER_KEY, {
104
+ items: async (ctx)=>(await templatesPackage()).items(ctx),
105
+ dependencies: (item)=>crmEmailTemplateDependencies(item),
106
+ remapIds: (item, idMap)=>remapCrmEmailTemplateIds(item, idMap),
107
+ readItems: async (ctx, ids)=>(await templatesPackage()).readItems(ctx, ids),
108
+ writeItems: async (ctx, items, writer)=>(await templatesPackage()).writeItems(ctx, items, writer),
109
+ revertItems: async (ctx, steps)=>(await templatesPackage()).revertItems(ctx, steps),
110
+ problems: async (ctx, write)=>(await templatesPackage()).problems(ctx, write),
111
+ rules: CRM_EMAIL_TEMPLATE_PACKAGE_RULES,
112
+ planGate: crmTransferPlanGate('email templates')
113
+ }, {
114
+ pluginId: BUNDLE_ID
115
+ });
116
+ // The record system's share of a person erasure (AGL-2623, AGL-3080): it
117
+ // names the person's contacts before anybody erases, and erases them, their
118
+ // satellites and their lead after everybody else. Required, and loaded with
119
+ // the first erasure.
120
+ registerPluginPersonRecordsEraser({
121
+ locate: async (target)=>(await import("./server/person-eraser.js")).crmPersonEraser().locate(target),
122
+ erase: async (request)=>(await import("./server/person-eraser.js")).crmPersonEraser().erase(request)
123
+ }, {
124
+ pluginId: BUNDLE_ID
125
+ });
94
126
  for (const [resource, handle] of CRM_API_V1_RESOURCES){
95
127
  registerApiV1Resource(resource, {
96
128
  handle,
@@ -103,6 +135,9 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
103
135
  registerApiV1UsageFigures(async (ctx)=>(await import("./server/api-v1/usage.js")).crmUsageFigures(ctx), {
104
136
  pluginId: BUNDLE_ID
105
137
  });
138
+ // What the CRM imports and exports (AGL-3527): each resource's module
139
+ // loads with the first transfer that asks for it.
140
+ registerCrmTransferResources(BUNDLE_ID);
106
141
  // A removed container — a deleted campaign — comes off every lead and every
107
142
  // contact facet naming it, before its owner removes it (AGL-3080).
108
143
  if (!listPluginMembershipDetachers().includes(BUNDLE_ID)) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/crm/src/lib/declarations.console-server.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// The registry's own module, not the data layer's barrel: boot needs one\n// registry, not the whole server surface.\nimport {\n type ApiV1ResourceHandler,\n registerApiV1Resource,\n registerApiV1UsageFigures,\n} from '@aglyn/tenant-data-admin/server/api-v1-resources'\nimport {\n listPluginMembershipDetachers,\n registerPluginMembershipDetacher,\n} from '@aglyn/aglyn/plugin-manager/plugin-membership-detach'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/**\n * The plan feature every CRM resource of `/v1` needs, and the sentence its\n * refusal says (AGL-2611, AGL-2851): the whole CRM is included from\n * Starter, so a Free workspace reads and changes none of it over the API. A\n * capture still records people on every plan; working them is the CRM.\n */\nconst CRM_SUITE = {\n feature: 'crm',\n message:\n 'The CRM — contacts, leads, companies, deals, tasks, pipelines, ' +\n 'activities and email templates — is not included in this organization’s plan',\n} as const\n\n/**\n * The CRM's resources on the customer REST API, each handler loaded with the\n * first request for it. In the order the API root lists them: the people\n * first, then the records a team keeps about them, then a site's leads\n * (`/v1/leads?siteId=`, a top-level path with the site as a parameter), then\n * the letters sent from a record (AGL-2658).\n */\nconst CRM_API_V1_RESOURCES: ReadonlyArray<readonly [string, ApiV1ResourceHandler]> = [\n ['contacts', async (...args) => (await import('./server/api-v1/contacts')).handleContacts(...args)],\n ['companies', async (...args) => (await import('./server/api-v1/crm-companies')).handleCompanies(...args)],\n ['pipelines', async (...args) => (await import('./server/api-v1/crm-pipelines')).handlePipelines(...args)],\n ['deals', async (...args) => (await import('./server/api-v1/crm-deals')).handleDeals(...args)],\n ['tasks', async (...args) => (await import('./server/api-v1/crm-tasks')).handleTasks(...args)],\n ['activities', async (...args) => (await import('./server/api-v1/crm-activities')).handleActivities(...args)],\n ['leads', async (...args) => (await import('./server/api-v1/crm-leads')).handleLeads(...args)],\n [\n 'email-templates',\n async (...args) => (await import('./server/api-v1/crm-email-templates')).handleEmailTemplates(...args),\n ],\n]\n\n/**\n * The CRM's CONSOLE-ONLY server declarations, named under\n * `consoleServerDeclarations` in `plugins.config.json` and run at the\n * console's boot.\n *\n * It serves the CRM's resources of `/v1` (AGL-2606): the console's router\n * owns the pipeline in front of them — the key, the plan's API access, the\n * quota, the rate limit, the error envelope — and hands every request under\n * `/v1/contacts`, `/v1/deals` and the rest to the CRM once the key is\n * authenticated and the organization's plan carries the CRM. Each resource\n * brings its description for the API's OpenAPI document, and the CRM's\n * records band and collection sizes join `GET /v1/usage`. The API is the\n * console's alone, so the tenant runtime does not register them.\n *\n * It also clears a removed container off the CRM's records: a campaign is\n * deleted from the console, and its owner asks every plugin's membership\n * detacher first (`server/container-detach.ts`).\n *\n * Light at boot: each resource's module is imported with its first request,\n * the descriptions when the document is first built, and the usage reader\n * with the first usage call.\n * Registering again replaces this plugin's own entries, so a second call (a\n * hot reload, a spec) is harmless.\n */\nexport function registerCrmConsoleServerDeclarations(): void {\n for (const [resource, handle] of CRM_API_V1_RESOURCES) {\n registerApiV1Resource(\n resource,\n {\n handle,\n entitlement: CRM_SUITE,\n describe: async () =>\n (await import('./server/api-v1/openapi')).CRM_API_V1_DESCRIPTIONS[resource],\n },\n { pluginId: BUNDLE_ID },\n )\n }\n registerApiV1UsageFigures(\n async (ctx) => (await import('./server/api-v1/usage')).crmUsageFigures(ctx),\n { pluginId: BUNDLE_ID },\n )\n // A removed container — a deleted campaign — comes off every lead and every\n // contact facet naming it, before its owner removes it (AGL-3080).\n if (!listPluginMembershipDetachers().includes(BUNDLE_ID)) {\n registerPluginMembershipDetacher(\n async (request) => (await import('./server/container-detach')).crmContainerDetacher(request),\n { pluginId: BUNDLE_ID },\n )\n }\n}\n"],"names":["registerApiV1Resource","registerApiV1UsageFigures","listPluginMembershipDetachers","registerPluginMembershipDetacher","BUNDLE_ID","CRM_SUITE","feature","message","CRM_API_V1_RESOURCES","args","handleContacts","handleCompanies","handlePipelines","handleDeals","handleTasks","handleActivities","handleLeads","handleEmailTemplates","registerCrmConsoleServerDeclarations","resource","handle","entitlement","describe","CRM_API_V1_DESCRIPTIONS","pluginId","ctx","crmUsageFigures","includes","request","crmContainerDetacher"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,yEAAyE;AACzE,0CAA0C;AAC1C,SAEEA,qBAAqB,EACrBC,yBAAyB,QACpB,mDAAkD;AACzD,SACEC,6BAA6B,EAC7BC,gCAAgC,QAC3B,uDAAsD;AAC7D,SAASC,SAAS,QAAQ,+BAA2B;AAErD;;;;;CAKC,GACD,MAAMC,YAAY;IAChBC,SAAS;IACTC,SACE,oEACA;AACJ;AAEA;;;;;;CAMC,GACD,MAAMC,uBAA+E;IACnF;QAAC;QAAY,OAAO,GAAGC,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,8BAA0B,EAAGC,cAAc,IAAID;KAAM;IACnG;QAAC;QAAa,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,mCAA+B,EAAGE,eAAe,IAAIF;KAAM;IAC1G;QAAC;QAAa,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,mCAA+B,EAAGG,eAAe,IAAIH;KAAM;IAC1G;QAAC;QAAS,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,+BAA2B,EAAGI,WAAW,IAAIJ;KAAM;IAC9F;QAAC;QAAS,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,+BAA2B,EAAGK,WAAW,IAAIL;KAAM;IAC9F;QAAC;QAAc,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,oCAAgC,EAAGM,gBAAgB,IAAIN;KAAM;IAC7G;QAAC;QAAS,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,+BAA2B,EAAGO,WAAW,IAAIP;KAAM;IAC9F;QACE;QACA,OAAO,GAAGA,OAAS,AAAC,CAAA,MAAM,MAAM,CAAC,yCAAqC,EAAGQ,oBAAoB,IAAIR;KAClG;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASS;IACd,KAAK,MAAM,CAACC,UAAUC,OAAO,IAAIZ,qBAAsB;QACrDR,sBACEmB,UACA;YACEC;YACAC,aAAahB;YACbiB,UAAU,UACR,AAAC,CAAA,MAAM,MAAM,CAAC,6BAAyB,EAAGC,uBAAuB,CAACJ,SAAS;QAC/E,GACA;YAAEK,UAAUpB;QAAU;IAE1B;IACAH,0BACE,OAAOwB,MAAQ,AAAC,CAAA,MAAM,MAAM,CAAC,2BAAuB,EAAGC,eAAe,CAACD,MACvE;QAAED,UAAUpB;IAAU;IAExB,4EAA4E;IAC5E,mEAAmE;IACnE,IAAI,CAACF,gCAAgCyB,QAAQ,CAACvB,YAAY;QACxDD,iCACE,OAAOyB,UAAY,AAAC,CAAA,MAAM,MAAM,CAAC,+BAA2B,EAAGC,oBAAoB,CAACD,UACpF;YAAEJ,UAAUpB;QAAU;IAE1B;AACF"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/crm/src/lib/declarations.console-server.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// The registry's own module, not the data layer's barrel: boot needs one\n// registry, not the whole server surface.\nimport {\n type ApiV1ResourceHandler,\n registerApiV1Resource,\n registerApiV1UsageFigures,\n} from '@aglyn/tenant-data-admin/server/api-v1-resources'\nimport {\n listPluginMembershipDetachers,\n registerPluginMembershipDetacher,\n} from '@aglyn/aglyn/plugin-manager/plugin-membership-detach'\nimport { registerPluginPersonRecordsEraser } from '@aglyn/aglyn/plugin-manager/plugin-person-erasure'\nimport { registerPluginTransferResource } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { crmTransferPlanGate, registerCrmTransferResources } from './transfer/register'\nimport {\n CRM_EMAIL_TEMPLATE_PACKAGE_RULES,\n CRM_EMAIL_TEMPLATES_TRANSFER_KEY,\n crmEmailTemplateDependencies,\n remapCrmEmailTemplateIds,\n type CrmEmailTemplatePackageContent,\n} from './transfer/email-templates-package'\n\n/** The email templates package's server half (AGL-3535), loaded when an import or export first asks. */\nconst templatesPackage = async () =>\n (await import('./transfer/email-templates-package.server')).createCrmEmailTemplatesPackage()\n\n/**\n * The plan feature every CRM resource of `/v1` needs, and the sentence its\n * refusal says (AGL-2611, AGL-2851): the whole CRM is included from\n * Starter, so a Free workspace reads and changes none of it over the API. A\n * capture still records people on every plan; working them is the CRM.\n */\nconst CRM_SUITE = {\n feature: 'crm',\n message:\n 'The CRM — contacts, leads, companies, deals, tasks, pipelines, ' +\n 'activities and email templates — is not included in this organization’s plan',\n} as const\n\n/**\n * The CRM's resources on the customer REST API, each handler loaded with the\n * first request for it. In the order the API root lists them: the people\n * first, then the records a team keeps about them, then a site's leads\n * (`/v1/leads?siteId=`, a top-level path with the site as a parameter), then\n * the letters sent from a record (AGL-2658).\n */\nconst CRM_API_V1_RESOURCES: ReadonlyArray<readonly [string, ApiV1ResourceHandler]> = [\n ['contacts', async (...args) => (await import('./server/api-v1/contacts')).handleContacts(...args)],\n ['companies', async (...args) => (await import('./server/api-v1/crm-companies')).handleCompanies(...args)],\n ['pipelines', async (...args) => (await import('./server/api-v1/crm-pipelines')).handlePipelines(...args)],\n ['deals', async (...args) => (await import('./server/api-v1/crm-deals')).handleDeals(...args)],\n ['tasks', async (...args) => (await import('./server/api-v1/crm-tasks')).handleTasks(...args)],\n ['activities', async (...args) => (await import('./server/api-v1/crm-activities')).handleActivities(...args)],\n ['leads', async (...args) => (await import('./server/api-v1/crm-leads')).handleLeads(...args)],\n [\n 'email-templates',\n async (...args) => (await import('./server/api-v1/crm-email-templates')).handleEmailTemplates(...args),\n ],\n]\n\n/**\n * The CRM's CONSOLE-ONLY server declarations, named under\n * `consoleServerDeclarations` in `plugins.config.json` and run at the\n * console's boot.\n *\n * It serves the CRM's resources of `/v1` (AGL-2606): the console's router\n * owns the pipeline in front of them — the key, the plan's API access, the\n * quota, the rate limit, the error envelope — and hands every request under\n * `/v1/contacts`, `/v1/deals` and the rest to the CRM once the key is\n * authenticated and the organization's plan carries the CRM. Each resource\n * brings its description for the API's OpenAPI document, and the CRM's\n * records band and collection sizes join `GET /v1/usage`. The API is the\n * console's alone, so the tenant runtime does not register them.\n *\n * It registers the server half of the CRM's import and export resources\n * (`transfer/register.ts`).\n *\n * It also clears a removed container off the CRM's records: a campaign is\n * deleted from the console, and its owner asks every plugin's membership\n * detacher first (`server/container-detach.ts`).\n *\n * Light at boot: each resource's module is imported with its first request,\n * the descriptions when the document is first built, and the usage reader\n * with the first usage call.\n * Registering again replaces this plugin's own entries, so a second call (a\n * hot reload, a spec) is harmless.\n */\nexport function registerCrmConsoleServerDeclarations(): void {\n // Email templates in a workspace package (AGL-3535).\n registerPluginTransferResource(\n CRM_EMAIL_TEMPLATES_TRANSFER_KEY,\n {\n items: async (ctx) => (await templatesPackage()).items(ctx),\n dependencies: (item) => crmEmailTemplateDependencies(item as CrmEmailTemplatePackageContent),\n remapIds: (item, idMap) => remapCrmEmailTemplateIds(item as CrmEmailTemplatePackageContent, idMap),\n readItems: async (ctx, ids) => (await templatesPackage()).readItems(ctx, ids),\n writeItems: async (ctx, items, writer) => (await templatesPackage()).writeItems(ctx, items as never, writer),\n revertItems: async (ctx, steps) => (await templatesPackage()).revertItems(ctx, steps as never),\n problems: async (ctx, write) => (await templatesPackage()).problems(ctx, write as never),\n rules: CRM_EMAIL_TEMPLATE_PACKAGE_RULES,\n planGate: crmTransferPlanGate('email templates'),\n },\n { pluginId: BUNDLE_ID },\n )\n // The record system's share of a person erasure (AGL-2623, AGL-3080): it\n // names the person's contacts before anybody erases, and erases them, their\n // satellites and their lead after everybody else. Required, and loaded with\n // the first erasure.\n registerPluginPersonRecordsEraser(\n {\n locate: async (target) => (await import('./server/person-eraser')).crmPersonEraser().locate(target),\n erase: async (request) => (await import('./server/person-eraser')).crmPersonEraser().erase(request),\n },\n { pluginId: BUNDLE_ID },\n )\n for (const [resource, handle] of CRM_API_V1_RESOURCES) {\n registerApiV1Resource(\n resource,\n {\n handle,\n entitlement: CRM_SUITE,\n describe: async () =>\n (await import('./server/api-v1/openapi')).CRM_API_V1_DESCRIPTIONS[resource],\n },\n { pluginId: BUNDLE_ID },\n )\n }\n registerApiV1UsageFigures(\n async (ctx) => (await import('./server/api-v1/usage')).crmUsageFigures(ctx),\n { pluginId: BUNDLE_ID },\n )\n // What the CRM imports and exports (AGL-3527): each resource's module\n // loads with the first transfer that asks for it.\n registerCrmTransferResources(BUNDLE_ID)\n // A removed container — a deleted campaign — comes off every lead and every\n // contact facet naming it, before its owner removes it (AGL-3080).\n if (!listPluginMembershipDetachers().includes(BUNDLE_ID)) {\n registerPluginMembershipDetacher(\n async (request) => (await import('./server/container-detach')).crmContainerDetacher(request),\n { pluginId: BUNDLE_ID },\n )\n }\n}\n"],"names":["registerApiV1Resource","registerApiV1UsageFigures","listPluginMembershipDetachers","registerPluginMembershipDetacher","registerPluginPersonRecordsEraser","registerPluginTransferResource","BUNDLE_ID","crmTransferPlanGate","registerCrmTransferResources","CRM_EMAIL_TEMPLATE_PACKAGE_RULES","CRM_EMAIL_TEMPLATES_TRANSFER_KEY","crmEmailTemplateDependencies","remapCrmEmailTemplateIds","templatesPackage","createCrmEmailTemplatesPackage","CRM_SUITE","feature","message","CRM_API_V1_RESOURCES","args","handleContacts","handleCompanies","handlePipelines","handleDeals","handleTasks","handleActivities","handleLeads","handleEmailTemplates","registerCrmConsoleServerDeclarations","items","ctx","dependencies","item","remapIds","idMap","readItems","ids","writeItems","writer","revertItems","steps","problems","write","rules","planGate","pluginId","locate","target","crmPersonEraser","erase","request","resource","handle","entitlement","describe","CRM_API_V1_DESCRIPTIONS","crmUsageFigures","includes","crmContainerDetacher"],"mappings":"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"}
@@ -0,0 +1,26 @@
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
+ * The CRM's DECLARATIONS: what another surface reads of this plugin before any
19
+ * of its own surfaces load, in both apps and in the console's browser.
20
+ *
21
+ * Its recipes (AGL-2626), so the automation editor's Recipes menu offers
22
+ * "Welcome a new lead" on a site whose CRM pages were never opened, and the
23
+ * automation it builds names the recipe it began as. Light by construction:
24
+ * the recipes are definitions, and nothing here reaches Firestore or React.
25
+ */
26
+ export declare function registerCrmDeclarations(): void;
@@ -0,0 +1,35 @@
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
+ */ // The seam from its own module, not the plugin-manager barrel: both apps load
17
+ // this at boot, and the barrel reaches the client contexts.
18
+ import { registerInteractionRecipes } from "@aglyn/aglyn/plugin-manager/interaction-recipes";
19
+ import { BUNDLE_ID } from "./constants/bundle-common.js";
20
+ import { CRM_ACTION_RECIPES } from "./model/crm-recipes.js";
21
+ /**
22
+ * The CRM's DECLARATIONS: what another surface reads of this plugin before any
23
+ * of its own surfaces load, in both apps and in the console's browser.
24
+ *
25
+ * Its recipes (AGL-2626), so the automation editor's Recipes menu offers
26
+ * "Welcome a new lead" on a site whose CRM pages were never opened, and the
27
+ * automation it builds names the recipe it began as. Light by construction:
28
+ * the recipes are definitions, and nothing here reaches Firestore or React.
29
+ */ export function registerCrmDeclarations() {
30
+ registerInteractionRecipes(CRM_ACTION_RECIPES, {
31
+ pluginId: BUNDLE_ID
32
+ });
33
+ }
34
+
35
+ //# sourceMappingURL=declarations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../libs/plugins/crm/src/lib/declarations.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// The seam from its own module, not the plugin-manager barrel: both apps load\n// this at boot, and the barrel reaches the client contexts.\nimport { registerInteractionRecipes } from '@aglyn/aglyn/plugin-manager/interaction-recipes'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { CRM_ACTION_RECIPES } from './model/crm-recipes'\n\n/**\n * The CRM's DECLARATIONS: what another surface reads of this plugin before any\n * of its own surfaces load, in both apps and in the console's browser.\n *\n * Its recipes (AGL-2626), so the automation editor's Recipes menu offers\n * \"Welcome a new lead\" on a site whose CRM pages were never opened, and the\n * automation it builds names the recipe it began as. Light by construction:\n * the recipes are definitions, and nothing here reaches Firestore or React.\n */\nexport function registerCrmDeclarations(): void {\n registerInteractionRecipes(CRM_ACTION_RECIPES, { pluginId: BUNDLE_ID })\n}\n"],"names":["registerInteractionRecipes","BUNDLE_ID","CRM_ACTION_RECIPES","registerCrmDeclarations","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E;AAC9E,4DAA4D;AAC5D,SAASA,0BAA0B,QAAQ,kDAAiD;AAC5F,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,kBAAkB,QAAQ,yBAAqB;AAExD;;;;;;;;CAQC,GACD,OAAO,SAASC;IACdH,2BAA2BE,oBAAoB;QAAEE,UAAUH;IAAU;AACvE"}
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import { type PluginContactCaptureWriter } from '@aglyn/aglyn/plugin-manager/plugin-contact-capture';
18
+ import { type PluginPersonRecords } from '@aglyn/aglyn/plugin-manager/plugin-person-records';
18
19
  import { type PluginRecordIndex } from '@aglyn/aglyn/plugin-manager/plugin-record-index';
19
20
  import { type PluginRecordTimelineWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-timeline';
20
21
  /**
@@ -27,11 +28,21 @@ import { type PluginRecordTimelineWriter } from '@aglyn/aglyn/plugin-manager/plu
27
28
  * including ones that will never touch the CRM.
28
29
  */
29
30
  export declare const crmContactCaptureWriter: PluginContactCaptureWriter;
31
+ /**
32
+ * The CRM as the plugin other plugins ask for people (AGL-3080), deferred
33
+ * like the capture: `server/person-records.ts` and the Admin SDK it brings
34
+ * load with the first question, not when the process starts.
35
+ */
36
+ export declare const crmPersonRecordsService: PluginPersonRecords;
30
37
  /**
31
38
  * The `pipeline` record index, its reads loaded with the first one — see
32
39
  * `server/pipeline-record-index.ts` for what it answers.
33
40
  */
34
41
  export declare const crmPipelineRecordIndex: PluginRecordIndex;
42
+ /** The companies a person works for, as another plugin reads them (AGL-3080). */
43
+ export declare const crmCompanyRecordIndex: PluginRecordIndex;
44
+ /** The email templates and snippets reps write, as another plugin reads them (AGL-3080). */
45
+ export declare const crmMessageTemplateRecordIndex: PluginRecordIndex;
35
46
  /**
36
47
  * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the
37
48
  * writer and the Admin SDK it brings load with the first entry filed.
@@ -19,12 +19,15 @@ import { registerPluginConsentGroupParticipant } from "@aglyn/aglyn/plugin-manag
19
19
  import { registerPluginContactCaptureWriter } from "@aglyn/aglyn/plugin-manager/plugin-contact-capture";
20
20
  import { registerPluginLeadConversionListener } from "@aglyn/aglyn/plugin-manager/plugin-lead-conversion";
21
21
  import { registerPluginPersonMatcher } from "@aglyn/aglyn/plugin-manager/plugin-person-matches";
22
+ import { registerPluginPersonRecords } from "@aglyn/aglyn/plugin-manager/plugin-person-records";
22
23
  import { registerPluginRecordIndex } from "@aglyn/aglyn/plugin-manager/plugin-record-index";
23
24
  import { registerPluginRecordEmailStateWriter } from "@aglyn/aglyn/plugin-manager/plugin-record-email-state";
25
+ import { registerPluginRecordOriginWriter } from "@aglyn/aglyn/plugin-manager/plugin-record-origin";
24
26
  import { registerPluginRecordTimelineWriter } from "@aglyn/aglyn/plugin-manager/plugin-record-timeline";
25
27
  import { registerPluginRecordWrittenListener } from "@aglyn/aglyn/plugin-manager/plugin-record-written";
28
+ import { registerServerStepExecutor } from "@aglyn/aglyn/plugin-manager/plugin-server-steps";
26
29
  import { registerPluginUsageMeter } from "@aglyn/aglyn/plugin-manager/plugin-usage-meters";
27
- import { BUNDLE_ID, CRM_RECORDS_METER_ID } from "./constants/bundle-common.js";
30
+ import { BUNDLE_ID, CRM_RECORDS_METER_ID, CRM_STEP_TYPES } from "./constants/bundle-common.js";
28
31
  import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
29
32
  /**
30
33
  * The CRM as the plugin that keeps people.
@@ -40,6 +43,36 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
40
43
  return await captureContactForCrm(request);
41
44
  }
42
45
  };
46
+ /**
47
+ * The CRM as the plugin other plugins ask for people (AGL-3080), deferred
48
+ * like the capture: `server/person-records.ts` and the Admin SDK it brings
49
+ * load with the first question, not when the process starts.
50
+ */ export const crmPersonRecordsService = {
51
+ async find (request) {
52
+ const { crmPersonRecords } = await import("./server/person-records.js");
53
+ return crmPersonRecords.find(request);
54
+ },
55
+ async read (request) {
56
+ const { crmPersonRecords } = await import("./server/person-records.js");
57
+ return crmPersonRecords.read(request);
58
+ },
59
+ async fileUnder (request) {
60
+ const { crmPersonRecords } = await import("./server/person-records.js");
61
+ return crmPersonRecords.fileUnder(request);
62
+ },
63
+ async recordRefund (request) {
64
+ const { crmPersonRecords } = await import("./server/person-records.js");
65
+ return crmPersonRecords.recordRefund(request);
66
+ },
67
+ async peopleInView (request) {
68
+ const { crmPersonRecords } = await import("./server/person-records.js");
69
+ return crmPersonRecords.peopleInView(request);
70
+ },
71
+ async wroteIn (request) {
72
+ const { crmPersonRecords } = await import("./server/person-records.js");
73
+ return crmPersonRecords.wroteIn(request);
74
+ }
75
+ };
43
76
  /**
44
77
  * The `pipeline` record index, its reads loaded with the first one — see
45
78
  * `server/pipeline-record-index.ts` for what it answers.
@@ -53,6 +86,20 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
53
86
  return pipelineRecordIndex.get(request);
54
87
  }
55
88
  };
89
+ /** One of `server/crm-record-indexes.ts`'s indexes, its reads loaded with the first one. */ function lazyCrmRecordIndex(kind) {
90
+ return {
91
+ async list (request) {
92
+ const { crmRecordIndexes } = await import("./server/crm-record-indexes.js");
93
+ return crmRecordIndexes()[kind].list(request);
94
+ },
95
+ async get (request) {
96
+ const { crmRecordIndexes } = await import("./server/crm-record-indexes.js");
97
+ return crmRecordIndexes()[kind].get(request);
98
+ }
99
+ };
100
+ }
101
+ /** The companies a person works for, as another plugin reads them (AGL-3080). */ export const crmCompanyRecordIndex = lazyCrmRecordIndex('company');
102
+ /** The email templates and snippets reps write, as another plugin reads them (AGL-3080). */ export const crmMessageTemplateRecordIndex = lazyCrmRecordIndex('messageTemplate');
56
103
  /**
57
104
  * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the
58
105
  * writer and the Admin SDK it brings load with the first entry filed.
@@ -68,6 +115,12 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
68
115
  async recordEmailDelivery (request) {
69
116
  const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } = await import("./server/record-timeline.js");
70
117
  return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).recordEmailDelivery(request);
118
+ },
119
+ // An automation's email to the person its event is about, filed on that
120
+ // person's timeline with its delivery state (AGL-2615, AGL-3080).
121
+ async prepareEmail (request) {
122
+ const { prepareCrmRecordEmail } = await import("./server/automation-steps.js");
123
+ return prepareCrmRecordEmail(request);
71
124
  }
72
125
  };
73
126
  /**
@@ -96,6 +149,13 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
96
149
  registerPluginContactCaptureWriter(crmContactCaptureWriter, {
97
150
  pluginId: BUNDLE_ID
98
151
  });
152
+ // The other half of keeping people (AGL-3080): another plugin that holds
153
+ // an address, or a record the CRM handed it, asks here for the person —
154
+ // a flow email's consent read, a refund, an automation filing somebody
155
+ // under a campaign — and never opens the CRM's collections itself.
156
+ registerPluginPersonRecords(crmPersonRecordsService, {
157
+ pluginId: BUNDLE_ID
158
+ });
99
159
  // The CRM's own share of a lead conversion (AGL-3254): the lead's
100
160
  // campaigns go onto the contact's facet. Through the seam every door
101
161
  // that converts a lead reaches, and deferred like the capture: the
@@ -146,6 +206,11 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
146
206
  async reached (request) {
147
207
  const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } = await import("./server/record-email-state.js");
148
208
  return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).reached(request);
209
+ },
210
+ // A lead that wrote back, moved to Working (AGL-3080).
211
+ async replied (request) {
212
+ const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } = await import("./server/record-email-state.js");
213
+ return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).replied(request);
149
214
  }
150
215
  }, {
151
216
  pluginId: BUNDLE_ID
@@ -158,6 +223,18 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
158
223
  registerPluginRecordTimelineWriter(crmRecordTimelineWriter, {
159
224
  pluginId: BUNDLE_ID
160
225
  });
226
+ // Where a person came from (AGL-3519): a door the CRM does not run — the
227
+ // platform's account sign-up, a sequence enrolling someone — names its
228
+ // origin, and the CRM stamps the built-in Lead source on a record holding
229
+ // none. Deferred like the rest.
230
+ registerPluginRecordOriginWriter({
231
+ async stamp (request) {
232
+ const { crmRecordOriginWriter } = await import("./server/record-origin.js");
233
+ return crmRecordOriginWriter.stamp(request);
234
+ }
235
+ }, {
236
+ pluginId: BUNDLE_ID
237
+ });
161
238
  // Sharing rules (AGL-3336), re-evaluated after every server write of a
162
239
  // lead, a contact, a company or a deal: the core tells its record-written
163
240
  // listeners from the list-field restamp every such writer ends with, in
@@ -176,6 +253,20 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
176
253
  registerPluginRecordIndex('pipeline', crmPipelineRecordIndex, {
177
254
  pluginId: BUNDLE_ID
178
255
  });
256
+ // The company a person works for, and the templates reps write, as a sales
257
+ // sequence reads them (AGL-3080). Deferred like the rest.
258
+ registerPluginRecordIndex('company', crmCompanyRecordIndex, {
259
+ pluginId: BUNDLE_ID
260
+ });
261
+ registerPluginRecordIndex('messageTemplate', crmMessageTemplateRecordIndex, {
262
+ pluginId: BUNDLE_ID
263
+ });
264
+ // The automation steps that write the CRM (AGL-2605, AGL-3080), run for the
265
+ // workflows engine through the server-step seam and declared under
266
+ // `serverSteps`. Deferred like the rest: the writes load with the first step.
267
+ registerServerStepExecutor(CRM_STEP_TYPES, async (request)=>(await import("./server/automation-steps.js")).runCrmAutomationStep(request), {
268
+ pluginId: BUNDLE_ID
269
+ });
179
270
  registerPluginConsentGroupParticipant({
180
271
  async preview (request) {
181
272
  const { consentGroupParticipant } = await import("./server/consent-group-participant.js");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/crm/src/lib/declarations.server.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// The contract from its own module, not the plugin-manager barrel: boot needs\n// the registry and nothing else, and the barrel reaches the client contexts.\nimport { registerPluginConsentGroupParticipant } from '@aglyn/aglyn/plugin-manager/plugin-consent-group-change'\nimport {\n registerPluginContactCaptureWriter,\n type PluginContactCaptureWriter,\n} from '@aglyn/aglyn/plugin-manager/plugin-contact-capture'\nimport { registerPluginLeadConversionListener } from '@aglyn/aglyn/plugin-manager/plugin-lead-conversion'\nimport { registerPluginPersonMatcher } from '@aglyn/aglyn/plugin-manager/plugin-person-matches'\nimport {\n registerPluginRecordIndex,\n type PluginRecordIndex,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { registerPluginRecordEmailStateWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-email-state'\nimport {\n registerPluginRecordTimelineWriter,\n type PluginRecordTimelineWriter,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-timeline'\nimport { registerPluginRecordWrittenListener } from '@aglyn/aglyn/plugin-manager/plugin-record-written'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { BUNDLE_ID, CRM_RECORDS_METER_ID } from './constants/bundle-common'\nimport { summarizeConsentGroupChange } from './model/consent-group-summary'\n\n/**\n * The CRM as the plugin that keeps people.\n *\n * Light by construction, the way the workflows listener is: the capture\n * itself is imported when the first one arrives, not when the process\n * starts, so a process that never captures anybody pays for this object and\n * nothing else. That matters because this registers in EVERY server process,\n * including ones that will never touch the CRM.\n */\nexport const crmContactCaptureWriter: PluginContactCaptureWriter = {\n async capture(request) {\n const { captureContactForCrm } = await import('./server/capture-contact')\n return await captureContactForCrm(request)\n },\n}\n\n/**\n * The `pipeline` record index, its reads loaded with the first one — see\n * `server/pipeline-record-index.ts` for what it answers.\n */\nexport const crmPipelineRecordIndex: PluginRecordIndex = {\n async list(request) {\n const { pipelineRecordIndex } = await import('./server/pipeline-record-index')\n return pipelineRecordIndex.list(request)\n },\n async get(request) {\n const { pipelineRecordIndex } = await import('./server/pipeline-record-index')\n return pipelineRecordIndex.get(request)\n },\n}\n\n/**\n * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the\n * writer and the Admin SDK it brings load with the first entry filed.\n */\nexport const crmRecordTimelineWriter: PluginRecordTimelineWriter = {\n async logActivity(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).logActivity(request)\n },\n async createTask(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).createTask(request)\n },\n async recordEmailDelivery(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).recordEmailDelivery!(request)\n },\n}\n\n/**\n * The plugin's SERVER declarations: what the server must know at boot, before\n * any door of the CRM has been called.\n *\n * ## Why a declaration and not a `tenantApi` registration\n *\n * The doors that meet a person mostly never load this plugin. A form\n * submission is a core route; an order and a booking are captured inside\n * STRIPE WEBHOOKS. None of them has a reason to load the CRM, and a registry\n * filled by a surface that did not load answers `null` — which\n * `capturePluginContact` defines as \"this workspace has no record system\", a\n * sentence that would be false and silent. Orders would stop creating\n * contacts with nothing red anywhere, which is the AGL-3025 shape.\n *\n * Running from both apps' generated server-declarations manifest at boot is\n * what makes the answer true in every process. It is also called from the\n * plugin's own API register functions, so a process whose boot did not run it\n * still registers the writer the first time a CRM door loads. Registering\n * twice replaces in place.\n *\n * ⚠️ The registry holds ONE writer: a workspace keeps one set of people. A\n * second plugin's is refused naming both, and the incumbent keeps serving.\n */\nexport function registerCrmServerDeclarations(): void {\n registerPluginContactCaptureWriter(crmContactCaptureWriter, {\n pluginId: BUNDLE_ID,\n })\n // The CRM's own share of a lead conversion (AGL-3254): the lead's\n // campaigns go onto the contact's facet. Through the seam every door\n // that converts a lead reaches, and deferred like the capture: the\n // module that writes is loaded when the first conversion arrives, and\n // it brings the Admin SDK with it — this file defers the plugin's OWN\n // module only. A library imported statically across the plugin cannot\n // also be lazy-loaded here: `enforce-module-boundaries` refuses every\n // static import of a library the project lazy-loads anywhere.\n registerPluginLeadConversionListener(\n async (request) => {\n const { carryLeadCampaignsOnConversion } =\n await import('./server/lead-campaign-carry')\n return carryLeadCampaignsOnConversion(request)\n },\n { pluginId: BUNDLE_ID },\n )\n // \"Did this workspace already know this person?\" (AGL-3289), asked by the\n // staff console's acquisition card. Deferred like the rest: the reads load\n // when a staff member first opens a card, not when the process starts.\n registerPluginPersonMatcher(\n async (request) => {\n const { matchCrmPeople } = await import('./server/person-matches')\n return matchCrmPeople(request)\n },\n { pluginId: BUNDLE_ID },\n )\n // The CRM's share of a consent group change (AGL-3320): a contact's\n // per-site refusal carried across a separation, and the records keyed by a\n // group re-homed after the flip. Registered whether or not a workspace has\n // the CRM switched on, because the contacts — and the refusals on them —\n // outlive the switch. Deferred like the rest; the summary is plain words\n // and answers synchronously.\n // The record email-state writer (AGL-3245), here as well as in the console\n // API so the tenant's doors reach it too: a form submission's capture is\n // checked for deliverability after its response (AGL-3328), and the \"Would\n // bounce\" that check finds is written through this seam. Deferred like the\n // rest; the console's own registration replaces this one with the same\n // writer, loaded eagerly.\n registerPluginRecordEmailStateWriter(\n {\n async stamp(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).stamp(request)\n },\n // A send's first opens and clicks, stamped on the contacts they name\n // (AGL-2616) — the campaign webhook's courtesy, deferred like the rest.\n async engaged(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).engaged!(request)\n },\n // A delivered campaign's leads, moved to Nurturing (AGL-3446).\n async reached(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).reached!(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n // The record timeline writer (AGL-2981), here as well as in the API\n // surfaces so a door in either app reaches it: a booking confirmed on the\n // tenant, or by the payment webhook, files its meeting and follow-up\n // through it (AGL-2660). Deferred like the rest; an API registration\n // replaces this one with the same writer, loaded eagerly.\n registerPluginRecordTimelineWriter(crmRecordTimelineWriter, { pluginId: BUNDLE_ID })\n // Sharing rules (AGL-3336), re-evaluated after every server write of a\n // lead, a contact, a company or a deal: the core tells its record-written\n // listeners from the list-field restamp every such writer ends with, in\n // both apps — a form's capture on the tenant, an edit in the console.\n // Deferred like the rest: an org with no rules pays one cached read.\n registerPluginRecordWrittenListener(\n async (event) => {\n const { crmSharingRecordWritten } = await import('./server/crm-sharing')\n await crmSharingRecordWritten(event)\n },\n { pluginId: BUNDLE_ID, key: 'sharing' },\n )\n // The organization's pipelines and their stages, as another plugin reads\n // them (AGL-3080): an automation the AI drafts names the stage a deal\n // moves to. Deferred like the rest: the reads load with the first one.\n registerPluginRecordIndex('pipeline', crmPipelineRecordIndex, { pluginId: BUNDLE_ID })\n registerPluginConsentGroupParticipant(\n {\n async preview(request) {\n const { consentGroupParticipant } = await import('./server/consent-group-participant')\n return consentGroupParticipant.preview(request)\n },\n async run(request) {\n const { consentGroupParticipant } = await import('./server/consent-group-participant')\n return consentGroupParticipant.run(request)\n },\n summarize: summarizeConsentGroupChange,\n },\n { pluginId: BUNDLE_ID },\n )\n // The records band in the monthly usage sweep, a core cron that never\n // loads a CRM door; declared in `usageAxes` so the sweep refuses to bill a\n // month without it. Deferred like the rest: the counts load with the\n // first sweep.\n registerPluginUsageMeter({\n pluginId: BUNDLE_ID,\n id: CRM_RECORDS_METER_ID,\n measure: async (context) => {\n const { measureCrmRecords } = await import('./server/crm-records-meter')\n return measureCrmRecords(context)\n },\n })\n}\n\n"],"names":["registerPluginConsentGroupParticipant","registerPluginContactCaptureWriter","registerPluginLeadConversionListener","registerPluginPersonMatcher","registerPluginRecordIndex","registerPluginRecordEmailStateWriter","registerPluginRecordTimelineWriter","registerPluginRecordWrittenListener","registerPluginUsageMeter","BUNDLE_ID","CRM_RECORDS_METER_ID","summarizeConsentGroupChange","crmContactCaptureWriter","capture","request","captureContactForCrm","crmPipelineRecordIndex","list","pipelineRecordIndex","get","crmRecordTimelineWriter","logActivity","createCrmRecordTimelineWriter","defaultCrmRecordTimelineDeps","createTask","recordEmailDelivery","registerCrmServerDeclarations","pluginId","carryLeadCampaignsOnConversion","matchCrmPeople","stamp","createCrmRecordEmailStateWriter","defaultCrmRecordEmailStateDeps","engaged","reached","event","crmSharingRecordWritten","key","preview","consentGroupParticipant","run","summarize","id","measure","context","measureCrmRecords"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,8EAA8E;AAC9E,6EAA6E;AAC7E,SAASA,qCAAqC,QAAQ,0DAAyD;AAC/G,SACEC,kCAAkC,QAE7B,qDAAoD;AAC3D,SAASC,oCAAoC,QAAQ,qDAAoD;AACzG,SAASC,2BAA2B,QAAQ,oDAAmD;AAC/F,SACEC,yBAAyB,QAEpB,kDAAiD;AACxD,SAASC,oCAAoC,QAAQ,wDAAuD;AAC5G,SACEC,kCAAkC,QAE7B,qDAAoD;AAC3D,SAASC,mCAAmC,QAAQ,oDAAmD;AACvG,SAASC,wBAAwB,QAAQ,kDAAiD;AAC1F,SAASC,SAAS,EAAEC,oBAAoB,QAAQ,+BAA2B;AAC3E,SAASC,2BAA2B,QAAQ,mCAA+B;AAE3E;;;;;;;;CAQC,GACD,OAAO,MAAMC,0BAAsD;IACjE,MAAMC,SAAQC,OAAO;QACnB,MAAM,EAAEC,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC;QAC9C,OAAO,MAAMA,qBAAqBD;IACpC;AACF,EAAC;AAED;;;CAGC,GACD,OAAO,MAAME,yBAA4C;IACvD,MAAMC,MAAKH,OAAO;QAChB,MAAM,EAAEI,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC;QAC7C,OAAOA,oBAAoBD,IAAI,CAACH;IAClC;IACA,MAAMK,KAAIL,OAAO;QACf,MAAM,EAAEI,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC;QAC7C,OAAOA,oBAAoBC,GAAG,CAACL;IACjC;AACF,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMM,0BAAsD;IACjE,MAAMC,aAAYP,OAAO;QACvB,MAAM,EAAEQ,6BAA6B,EAAEC,4BAA4B,EAAE,GACnE,MAAM,MAAM,CAAC;QACf,OAAOD,8BAA8BC,gCAAgCF,WAAW,CAACP;IACnF;IACA,MAAMU,YAAWV,OAAO;QACtB,MAAM,EAAEQ,6BAA6B,EAAEC,4BAA4B,EAAE,GACnE,MAAM,MAAM,CAAC;QACf,OAAOD,8BAA8BC,gCAAgCC,UAAU,CAACV;IAClF;IACA,MAAMW,qBAAoBX,OAAO;QAC/B,MAAM,EAAEQ,6BAA6B,EAAEC,4BAA4B,EAAE,GACnE,MAAM,MAAM,CAAC;QACf,OAAOD,8BAA8BC,gCAAgCE,mBAAmB,CAAEX;IAC5F;AACF,EAAC;AAED;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASY;IACdzB,mCAAmCW,yBAAyB;QAC1De,UAAUlB;IACZ;IACA,kEAAkE;IAClE,qEAAqE;IACrE,mEAAmE;IACnE,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,8DAA8D;IAC9DP,qCACE,OAAOY;QACL,MAAM,EAAEc,8BAA8B,EAAE,GACtC,MAAM,MAAM,CAAC;QACf,OAAOA,+BAA+Bd;IACxC,GACA;QAAEa,UAAUlB;IAAU;IAExB,0EAA0E;IAC1E,2EAA2E;IAC3E,uEAAuE;IACvEN,4BACE,OAAOW;QACL,MAAM,EAAEe,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC;QACxC,OAAOA,eAAef;IACxB,GACA;QAAEa,UAAUlB;IAAU;IAExB,oEAAoE;IACpE,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAyE;IACzE,6BAA6B;IAC7B,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,2EAA2E;IAC3E,uEAAuE;IACvE,0BAA0B;IAC1BJ,qCACE;QACE,MAAMyB,OAAMhB,OAAO;YACjB,MAAM,EAAEiB,+BAA+B,EAAEC,8BAA8B,EAAE,GACvE,MAAM,MAAM,CAAC;YACf,OAAOD,gCAAgCC,kCAAkCF,KAAK,CAAChB;QACjF;QACA,qEAAqE;QACrE,wEAAwE;QACxE,MAAMmB,SAAQnB,OAAO;YACnB,MAAM,EAAEiB,+BAA+B,EAAEC,8BAA8B,EAAE,GACvE,MAAM,MAAM,CAAC;YACf,OAAOD,gCAAgCC,kCAAkCC,OAAO,CAAEnB;QACpF;QACA,+DAA+D;QAC/D,MAAMoB,SAAQpB,OAAO;YACnB,MAAM,EAAEiB,+BAA+B,EAAEC,8BAA8B,EAAE,GACvE,MAAM,MAAM,CAAC;YACf,OAAOD,gCAAgCC,kCAAkCE,OAAO,CAAEpB;QACpF;IACF,GACA;QAAEa,UAAUlB;IAAU;IAExB,oEAAoE;IACpE,0EAA0E;IAC1E,qEAAqE;IACrE,qEAAqE;IACrE,0DAA0D;IAC1DH,mCAAmCc,yBAAyB;QAAEO,UAAUlB;IAAU;IAClF,uEAAuE;IACvE,0EAA0E;IAC1E,wEAAwE;IACxE,sEAAsE;IACtE,qEAAqE;IACrEF,oCACE,OAAO4B;QACL,MAAM,EAAEC,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC;QACjD,MAAMA,wBAAwBD;IAChC,GACA;QAAER,UAAUlB;QAAW4B,KAAK;IAAU;IAExC,yEAAyE;IACzE,sEAAsE;IACtE,uEAAuE;IACvEjC,0BAA0B,YAAYY,wBAAwB;QAAEW,UAAUlB;IAAU;IACpFT,sCACE;QACE,MAAMsC,SAAQxB,OAAO;YACnB,MAAM,EAAEyB,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC;YACjD,OAAOA,wBAAwBD,OAAO,CAACxB;QACzC;QACA,MAAM0B,KAAI1B,OAAO;YACf,MAAM,EAAEyB,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC;YACjD,OAAOA,wBAAwBC,GAAG,CAAC1B;QACrC;QACA2B,WAAW9B;IACb,GACA;QAAEgB,UAAUlB;IAAU;IAExB,sEAAsE;IACtE,2EAA2E;IAC3E,qEAAqE;IACrE,eAAe;IACfD,yBAAyB;QACvBmB,UAAUlB;QACViC,IAAIhC;QACJiC,SAAS,OAAOC;YACd,MAAM,EAAEC,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC;YAC3C,OAAOA,kBAAkBD;QAC3B;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/crm/src/lib/declarations.server.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// The contract from its own module, not the plugin-manager barrel: boot needs\n// the registry and nothing else, and the barrel reaches the client contexts.\nimport { registerPluginConsentGroupParticipant } from '@aglyn/aglyn/plugin-manager/plugin-consent-group-change'\nimport {\n registerPluginContactCaptureWriter,\n type PluginContactCaptureWriter,\n} from '@aglyn/aglyn/plugin-manager/plugin-contact-capture'\nimport { registerPluginLeadConversionListener } from '@aglyn/aglyn/plugin-manager/plugin-lead-conversion'\nimport { registerPluginPersonMatcher } from '@aglyn/aglyn/plugin-manager/plugin-person-matches'\nimport {\n registerPluginPersonRecords,\n type PluginPersonRecords,\n} from '@aglyn/aglyn/plugin-manager/plugin-person-records'\nimport {\n registerPluginRecordIndex,\n type PluginRecordIndex,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { registerPluginRecordEmailStateWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-email-state'\nimport { registerPluginRecordOriginWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-origin'\nimport {\n registerPluginRecordTimelineWriter,\n type PluginRecordTimelineWriter,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-timeline'\nimport { registerPluginRecordWrittenListener } from '@aglyn/aglyn/plugin-manager/plugin-record-written'\nimport { registerServerStepExecutor } from '@aglyn/aglyn/plugin-manager/plugin-server-steps'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { BUNDLE_ID, CRM_RECORDS_METER_ID, CRM_STEP_TYPES } from './constants/bundle-common'\nimport { summarizeConsentGroupChange } from './model/consent-group-summary'\n\n/**\n * The CRM as the plugin that keeps people.\n *\n * Light by construction, the way the workflows listener is: the capture\n * itself is imported when the first one arrives, not when the process\n * starts, so a process that never captures anybody pays for this object and\n * nothing else. That matters because this registers in EVERY server process,\n * including ones that will never touch the CRM.\n */\nexport const crmContactCaptureWriter: PluginContactCaptureWriter = {\n async capture(request) {\n const { captureContactForCrm } = await import('./server/capture-contact')\n return await captureContactForCrm(request)\n },\n}\n\n/**\n * The CRM as the plugin other plugins ask for people (AGL-3080), deferred\n * like the capture: `server/person-records.ts` and the Admin SDK it brings\n * load with the first question, not when the process starts.\n */\nexport const crmPersonRecordsService: PluginPersonRecords = {\n async find(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.find(request)\n },\n async read(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.read(request)\n },\n async fileUnder(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.fileUnder(request)\n },\n async recordRefund(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.recordRefund(request)\n },\n async peopleInView(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.peopleInView(request)\n },\n async wroteIn(request) {\n const { crmPersonRecords } = await import('./server/person-records')\n return crmPersonRecords.wroteIn(request)\n },\n}\n\n/**\n * The `pipeline` record index, its reads loaded with the first one — see\n * `server/pipeline-record-index.ts` for what it answers.\n */\nexport const crmPipelineRecordIndex: PluginRecordIndex = {\n async list(request) {\n const { pipelineRecordIndex } = await import('./server/pipeline-record-index')\n return pipelineRecordIndex.list(request)\n },\n async get(request) {\n const { pipelineRecordIndex } = await import('./server/pipeline-record-index')\n return pipelineRecordIndex.get(request)\n },\n}\n\n/** One of `server/crm-record-indexes.ts`'s indexes, its reads loaded with the first one. */\nfunction lazyCrmRecordIndex(kind: 'company' | 'messageTemplate'): PluginRecordIndex {\n return {\n async list(request) {\n const { crmRecordIndexes } = await import('./server/crm-record-indexes')\n return crmRecordIndexes()[kind].list(request)\n },\n async get(request) {\n const { crmRecordIndexes } = await import('./server/crm-record-indexes')\n return crmRecordIndexes()[kind].get(request)\n },\n }\n}\n\n/** The companies a person works for, as another plugin reads them (AGL-3080). */\nexport const crmCompanyRecordIndex = lazyCrmRecordIndex('company')\n\n/** The email templates and snippets reps write, as another plugin reads them (AGL-3080). */\nexport const crmMessageTemplateRecordIndex = lazyCrmRecordIndex('messageTemplate')\n\n/**\n * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the\n * writer and the Admin SDK it brings load with the first entry filed.\n */\nexport const crmRecordTimelineWriter: PluginRecordTimelineWriter = {\n async logActivity(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).logActivity(request)\n },\n async createTask(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).createTask(request)\n },\n async recordEmailDelivery(request) {\n const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } =\n await import('./server/record-timeline')\n return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).recordEmailDelivery!(request)\n },\n // An automation's email to the person its event is about, filed on that\n // person's timeline with its delivery state (AGL-2615, AGL-3080).\n async prepareEmail(request) {\n const { prepareCrmRecordEmail } = await import('./server/automation-steps')\n return prepareCrmRecordEmail(request)\n },\n}\n\n/**\n * The plugin's SERVER declarations: what the server must know at boot, before\n * any door of the CRM has been called.\n *\n * ## Why a declaration and not a `tenantApi` registration\n *\n * The doors that meet a person mostly never load this plugin. A form\n * submission is a core route; an order and a booking are captured inside\n * STRIPE WEBHOOKS. None of them has a reason to load the CRM, and a registry\n * filled by a surface that did not load answers `null` — which\n * `capturePluginContact` defines as \"this workspace has no record system\", a\n * sentence that would be false and silent. Orders would stop creating\n * contacts with nothing red anywhere, which is the AGL-3025 shape.\n *\n * Running from both apps' generated server-declarations manifest at boot is\n * what makes the answer true in every process. It is also called from the\n * plugin's own API register functions, so a process whose boot did not run it\n * still registers the writer the first time a CRM door loads. Registering\n * twice replaces in place.\n *\n * ⚠️ The registry holds ONE writer: a workspace keeps one set of people. A\n * second plugin's is refused naming both, and the incumbent keeps serving.\n */\nexport function registerCrmServerDeclarations(): void {\n registerPluginContactCaptureWriter(crmContactCaptureWriter, {\n pluginId: BUNDLE_ID,\n })\n // The other half of keeping people (AGL-3080): another plugin that holds\n // an address, or a record the CRM handed it, asks here for the person —\n // a flow email's consent read, a refund, an automation filing somebody\n // under a campaign — and never opens the CRM's collections itself.\n registerPluginPersonRecords(crmPersonRecordsService, { pluginId: BUNDLE_ID })\n // The CRM's own share of a lead conversion (AGL-3254): the lead's\n // campaigns go onto the contact's facet. Through the seam every door\n // that converts a lead reaches, and deferred like the capture: the\n // module that writes is loaded when the first conversion arrives, and\n // it brings the Admin SDK with it — this file defers the plugin's OWN\n // module only. A library imported statically across the plugin cannot\n // also be lazy-loaded here: `enforce-module-boundaries` refuses every\n // static import of a library the project lazy-loads anywhere.\n registerPluginLeadConversionListener(\n async (request) => {\n const { carryLeadCampaignsOnConversion } =\n await import('./server/lead-campaign-carry')\n return carryLeadCampaignsOnConversion(request)\n },\n { pluginId: BUNDLE_ID },\n )\n // \"Did this workspace already know this person?\" (AGL-3289), asked by the\n // staff console's acquisition card. Deferred like the rest: the reads load\n // when a staff member first opens a card, not when the process starts.\n registerPluginPersonMatcher(\n async (request) => {\n const { matchCrmPeople } = await import('./server/person-matches')\n return matchCrmPeople(request)\n },\n { pluginId: BUNDLE_ID },\n )\n // The CRM's share of a consent group change (AGL-3320): a contact's\n // per-site refusal carried across a separation, and the records keyed by a\n // group re-homed after the flip. Registered whether or not a workspace has\n // the CRM switched on, because the contacts — and the refusals on them —\n // outlive the switch. Deferred like the rest; the summary is plain words\n // and answers synchronously.\n // The record email-state writer (AGL-3245), here as well as in the console\n // API so the tenant's doors reach it too: a form submission's capture is\n // checked for deliverability after its response (AGL-3328), and the \"Would\n // bounce\" that check finds is written through this seam. Deferred like the\n // rest; the console's own registration replaces this one with the same\n // writer, loaded eagerly.\n registerPluginRecordEmailStateWriter(\n {\n async stamp(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).stamp(request)\n },\n // A send's first opens and clicks, stamped on the contacts they name\n // (AGL-2616) — the campaign webhook's courtesy, deferred like the rest.\n async engaged(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).engaged!(request)\n },\n // A delivered campaign's leads, moved to Nurturing (AGL-3446).\n async reached(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).reached!(request)\n },\n // A lead that wrote back, moved to Working (AGL-3080).\n async replied(request) {\n const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } =\n await import('./server/record-email-state')\n return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).replied!(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n // The record timeline writer (AGL-2981), here as well as in the API\n // surfaces so a door in either app reaches it: a booking confirmed on the\n // tenant, or by the payment webhook, files its meeting and follow-up\n // through it (AGL-2660). Deferred like the rest; an API registration\n // replaces this one with the same writer, loaded eagerly.\n registerPluginRecordTimelineWriter(crmRecordTimelineWriter, { pluginId: BUNDLE_ID })\n // Where a person came from (AGL-3519): a door the CRM does not run — the\n // platform's account sign-up, a sequence enrolling someone — names its\n // origin, and the CRM stamps the built-in Lead source on a record holding\n // none. Deferred like the rest.\n registerPluginRecordOriginWriter(\n {\n async stamp(request) {\n const { crmRecordOriginWriter } = await import('./server/record-origin')\n return crmRecordOriginWriter.stamp(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n // Sharing rules (AGL-3336), re-evaluated after every server write of a\n // lead, a contact, a company or a deal: the core tells its record-written\n // listeners from the list-field restamp every such writer ends with, in\n // both apps — a form's capture on the tenant, an edit in the console.\n // Deferred like the rest: an org with no rules pays one cached read.\n registerPluginRecordWrittenListener(\n async (event) => {\n const { crmSharingRecordWritten } = await import('./server/crm-sharing')\n await crmSharingRecordWritten(event)\n },\n { pluginId: BUNDLE_ID, key: 'sharing' },\n )\n // The organization's pipelines and their stages, as another plugin reads\n // them (AGL-3080): an automation the AI drafts names the stage a deal\n // moves to. Deferred like the rest: the reads load with the first one.\n registerPluginRecordIndex('pipeline', crmPipelineRecordIndex, { pluginId: BUNDLE_ID })\n // The company a person works for, and the templates reps write, as a sales\n // sequence reads them (AGL-3080). Deferred like the rest.\n registerPluginRecordIndex('company', crmCompanyRecordIndex, { pluginId: BUNDLE_ID })\n registerPluginRecordIndex('messageTemplate', crmMessageTemplateRecordIndex, { pluginId: BUNDLE_ID })\n // The automation steps that write the CRM (AGL-2605, AGL-3080), run for the\n // workflows engine through the server-step seam and declared under\n // `serverSteps`. Deferred like the rest: the writes load with the first step.\n registerServerStepExecutor(\n CRM_STEP_TYPES,\n async (request) => (await import('./server/automation-steps')).runCrmAutomationStep(request),\n { pluginId: BUNDLE_ID },\n )\n registerPluginConsentGroupParticipant(\n {\n async preview(request) {\n const { consentGroupParticipant } = await import('./server/consent-group-participant')\n return consentGroupParticipant.preview(request)\n },\n async run(request) {\n const { consentGroupParticipant } = await import('./server/consent-group-participant')\n return consentGroupParticipant.run(request)\n },\n summarize: summarizeConsentGroupChange,\n },\n { pluginId: BUNDLE_ID },\n )\n // The records band in the monthly usage sweep, a core cron that never\n // loads a CRM door; declared in `usageAxes` so the sweep refuses to bill a\n // month without it. Deferred like the rest: the counts load with the\n // first sweep.\n registerPluginUsageMeter({\n pluginId: BUNDLE_ID,\n id: CRM_RECORDS_METER_ID,\n measure: async (context) => {\n const { measureCrmRecords } = await import('./server/crm-records-meter')\n return measureCrmRecords(context)\n },\n })\n}\n\n"],"names":["registerPluginConsentGroupParticipant","registerPluginContactCaptureWriter","registerPluginLeadConversionListener","registerPluginPersonMatcher","registerPluginPersonRecords","registerPluginRecordIndex","registerPluginRecordEmailStateWriter","registerPluginRecordOriginWriter","registerPluginRecordTimelineWriter","registerPluginRecordWrittenListener","registerServerStepExecutor","registerPluginUsageMeter","BUNDLE_ID","CRM_RECORDS_METER_ID","CRM_STEP_TYPES","summarizeConsentGroupChange","crmContactCaptureWriter","capture","request","captureContactForCrm","crmPersonRecordsService","find","crmPersonRecords","read","fileUnder","recordRefund","peopleInView","wroteIn","crmPipelineRecordIndex","list","pipelineRecordIndex","get","lazyCrmRecordIndex","kind","crmRecordIndexes","crmCompanyRecordIndex","crmMessageTemplateRecordIndex","crmRecordTimelineWriter","logActivity","createCrmRecordTimelineWriter","defaultCrmRecordTimelineDeps","createTask","recordEmailDelivery","prepareEmail","prepareCrmRecordEmail","registerCrmServerDeclarations","pluginId","carryLeadCampaignsOnConversion","matchCrmPeople","stamp","createCrmRecordEmailStateWriter","defaultCrmRecordEmailStateDeps","engaged","reached","replied","crmRecordOriginWriter","event","crmSharingRecordWritten","key","runCrmAutomationStep","preview","consentGroupParticipant","run","summarize","id","measure","context","measureCrmRecords"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { CrmPicklist, CrmPicklistId } from '@aglyn/aglyn';
2
+ export interface CompanyPicklistsResult {
3
+ /** Each list a company field holds a value of, by picklist id. */
4
+ lists: Readonly<Partial<Record<CrmPicklistId, CrmPicklist>>>;
5
+ /** Every list has answered from the server. */
6
+ ready: boolean;
7
+ }
8
+ /**
9
+ * The org's lists behind a company's picklist fields (AGL-3514): Type,
10
+ * Industry, Rating and Ownership, and the lead source list Account Source
11
+ * holds a value of. One document listen each, shared with every other
12
+ * mount asking for the same list.
13
+ */
14
+ export declare function useCompanyPicklists(orgId: string | null | undefined): CompanyPicklistsResult;
15
+ export default useCompanyPicklists;
@@ -0,0 +1,55 @@
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
+ */ 'use client';
17
+ import { useMemo } from "react";
18
+ import { useCrmPicklist } from "./use-crm-picklist.js";
19
+ /**
20
+ * The org's lists behind a company's picklist fields (AGL-3514): Type,
21
+ * Industry, Rating and Ownership, and the lead source list Account Source
22
+ * holds a value of. One document listen each, shared with every other
23
+ * mount asking for the same list.
24
+ */ export function useCompanyPicklists(orgId) {
25
+ const accountType = useCrmPicklist('accountType', orgId);
26
+ const industry = useCrmPicklist('industry', orgId);
27
+ const rating = useCrmPicklist('rating', orgId);
28
+ const ownership = useCrmPicklist('ownership', orgId);
29
+ const leadSource = useCrmPicklist('leadSource', orgId);
30
+ return useMemo(()=>({
31
+ lists: {
32
+ accountType: accountType.picklist,
33
+ industry: industry.picklist,
34
+ rating: rating.picklist,
35
+ ownership: ownership.picklist,
36
+ leadSource: leadSource.picklist
37
+ },
38
+ ready: [
39
+ accountType,
40
+ industry,
41
+ rating,
42
+ ownership,
43
+ leadSource
44
+ ].every((list)=>list.ready)
45
+ }), [
46
+ accountType,
47
+ industry,
48
+ rating,
49
+ ownership,
50
+ leadSource
51
+ ]);
52
+ }
53
+ export default useCompanyPicklists;
54
+
55
+ //# sourceMappingURL=use-company-picklists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-company-picklists.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'use client'\n\nimport type { CrmPicklist, CrmPicklistId } from '@aglyn/aglyn'\nimport { useMemo } from 'react'\nimport { useCrmPicklist } from './use-crm-picklist'\n\nexport interface CompanyPicklistsResult {\n /** Each list a company field holds a value of, by picklist id. */\n lists: Readonly<Partial<Record<CrmPicklistId, CrmPicklist>>>\n /** Every list has answered from the server. */\n ready: boolean\n}\n\n/**\n * The org's lists behind a company's picklist fields (AGL-3514): Type,\n * Industry, Rating and Ownership, and the lead source list Account Source\n * holds a value of. One document listen each, shared with every other\n * mount asking for the same list.\n */\nexport function useCompanyPicklists(orgId: string | null | undefined): CompanyPicklistsResult {\n const accountType = useCrmPicklist('accountType', orgId)\n const industry = useCrmPicklist('industry', orgId)\n const rating = useCrmPicklist('rating', orgId)\n const ownership = useCrmPicklist('ownership', orgId)\n const leadSource = useCrmPicklist('leadSource', orgId)\n return useMemo(\n () => ({\n lists: {\n accountType: accountType.picklist,\n industry: industry.picklist,\n rating: rating.picklist,\n ownership: ownership.picklist,\n leadSource: leadSource.picklist,\n },\n ready: [accountType, industry, rating, ownership, leadSource].every((list) => list.ready),\n }),\n [accountType, industry, rating, ownership, leadSource],\n )\n}\n\nexport default useCompanyPicklists\n"],"names":["useMemo","useCrmPicklist","useCompanyPicklists","orgId","accountType","industry","rating","ownership","leadSource","lists","picklist","ready","every","list"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAGA,SAASA,OAAO,QAAQ,QAAO;AAC/B,SAASC,cAAc,QAAQ,wBAAoB;AASnD;;;;;CAKC,GACD,OAAO,SAASC,oBAAoBC,KAAgC;IAClE,MAAMC,cAAcH,eAAe,eAAeE;IAClD,MAAME,WAAWJ,eAAe,YAAYE;IAC5C,MAAMG,SAASL,eAAe,UAAUE;IACxC,MAAMI,YAAYN,eAAe,aAAaE;IAC9C,MAAMK,aAAaP,eAAe,cAAcE;IAChD,OAAOH,QACL,IAAO,CAAA;YACLS,OAAO;gBACLL,aAAaA,YAAYM,QAAQ;gBACjCL,UAAUA,SAASK,QAAQ;gBAC3BJ,QAAQA,OAAOI,QAAQ;gBACvBH,WAAWA,UAAUG,QAAQ;gBAC7BF,YAAYA,WAAWE,QAAQ;YACjC;YACAC,OAAO;gBAACP;gBAAaC;gBAAUC;gBAAQC;gBAAWC;aAAW,CAACI,KAAK,CAAC,CAACC,OAASA,KAAKF,KAAK;QAC1F,CAAA,GACA;QAACP;QAAaC;QAAUC;QAAQC;QAAWC;KAAW;AAE1D;AAEA,eAAeN,oBAAmB"}
@@ -0,0 +1,25 @@
1
+ import { type CrmPicklist, type CrmPicklistDefinition, type CrmPicklistId } from '@aglyn/aglyn';
2
+ export interface CrmPicklistResult {
3
+ /** The field the list belongs to — its standard values, groups and targets. */
4
+ definition: CrmPicklistDefinition;
5
+ /** The list every picker offers — the org's own values with every standard value. */
6
+ picklist: CrmPicklist;
7
+ /** The org has written its own list; false while it reads the standard values alone. */
8
+ stored: boolean;
9
+ /** The server has answered, so the list is the org's and not a placeholder. */
10
+ ready: boolean;
11
+ /** The document has not been confirmed by the server — `writeGuardedBySeed`'s input. */
12
+ fromCache: boolean;
13
+ }
14
+ /**
15
+ * An org's values for one of the CRM's standard picklists (AGL-3510), for
16
+ * every surface that offers or manages them: a record's select, a create
17
+ * drawer, a list's filter and the Fields page.
18
+ *
19
+ * One document listen, shared by the Firestore SDK across every mount that
20
+ * asks for the same org and picklist, so a page with the list and a drawer
21
+ * open pays for it once. `orgId` null issues no read and answers the
22
+ * standard values, unready.
23
+ */
24
+ export declare function useCrmPicklist(id: CrmPicklistId, orgId: string | null | undefined): CrmPicklistResult;
25
+ export default useCrmPicklist;
@@ -0,0 +1,53 @@
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
+ */ 'use client';
17
+ import { CRM_COLLECTIONS, crmPicklistDefinition, effectiveCrmPicklist, normalizeCrmPicklist } from "@aglyn/aglyn";
18
+ import { useFirestore, useFirestoreDoc } from "@aglyn/tenant-feature-instance";
19
+ import { doc } from "firebase/firestore";
20
+ import { useMemo } from "react";
21
+ /**
22
+ * An org's values for one of the CRM's standard picklists (AGL-3510), for
23
+ * every surface that offers or manages them: a record's select, a create
24
+ * drawer, a list's filter and the Fields page.
25
+ *
26
+ * One document listen, shared by the Firestore SDK across every mount that
27
+ * asks for the same org and picklist, so a page with the list and a drawer
28
+ * open pays for it once. `orgId` null issues no read and answers the
29
+ * standard values, unready.
30
+ */ export function useCrmPicklist(id, orgId) {
31
+ const firestore = useFirestore();
32
+ const { data, status, fromCache } = useFirestoreDoc(()=>orgId ? doc(firestore, 'orgs', orgId, CRM_COLLECTIONS.picklists, id) : null, [
33
+ firestore,
34
+ orgId,
35
+ id
36
+ ]);
37
+ return useMemo(()=>({
38
+ definition: crmPicklistDefinition(id),
39
+ picklist: effectiveCrmPicklist(id, data),
40
+ stored: normalizeCrmPicklist(data) !== null,
41
+ ready: Boolean(orgId) && status !== 'loading',
42
+ fromCache
43
+ }), [
44
+ id,
45
+ data,
46
+ orgId,
47
+ status,
48
+ fromCache
49
+ ]);
50
+ }
51
+ export default useCrmPicklist;
52
+
53
+ //# sourceMappingURL=use-crm-picklist.js.map