@aglyn/plugins-crm 1.0.0-beta.218 → 1.0.0-beta.220

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 (346) hide show
  1. package/README.md +2 -0
  2. package/package.json +14 -14
  3. package/src/index.d.ts +1 -0
  4. package/src/index.js.map +1 -1
  5. package/src/lib/components/companies-bulk-bar.js +12 -4
  6. package/src/lib/components/companies-bulk-bar.js.map +1 -1
  7. package/src/lib/components/company-detail-page.js +11 -0
  8. package/src/lib/components/company-detail-page.js.map +1 -1
  9. package/src/lib/components/company-edit-drawer.js +12 -2
  10. package/src/lib/components/company-edit-drawer.js.map +1 -1
  11. package/src/lib/components/company-import-drawer.d.ts +1 -1
  12. package/src/lib/components/company-picker.js +10 -3
  13. package/src/lib/components/company-picker.js.map +1 -1
  14. package/src/lib/components/contact-associations-card.js +4 -3
  15. package/src/lib/components/contact-associations-card.js.map +1 -1
  16. package/src/lib/components/contact-detail-page.d.ts +4 -4
  17. package/src/lib/components/contact-detail-page.js +50 -53
  18. package/src/lib/components/contact-detail-page.js.map +1 -1
  19. package/src/lib/components/contact-list-columns.d.ts +3 -0
  20. package/src/lib/components/contact-list-columns.js +21 -5
  21. package/src/lib/components/contact-list-columns.js.map +1 -1
  22. package/src/lib/components/contact-merge-dialog.js +2 -1
  23. package/src/lib/components/contact-merge-dialog.js.map +1 -1
  24. package/src/lib/components/contact-timeline-card.js +4 -3
  25. package/src/lib/components/contact-timeline-card.js.map +1 -1
  26. package/src/lib/components/contacts-bulk-bar.d.ts +3 -3
  27. package/src/lib/components/contacts-bulk-bar.js +24 -51
  28. package/src/lib/components/contacts-bulk-bar.js.map +1 -1
  29. package/src/lib/components/contacts-section.js +9 -3
  30. package/src/lib/components/contacts-section.js.map +1 -1
  31. package/src/lib/components/crm-booking-zone.d.ts +8 -2
  32. package/src/lib/components/crm-booking-zone.js.map +1 -1
  33. package/src/lib/components/crm-export-all-button.d.ts +1 -1
  34. package/src/lib/components/crm-export-all-button.js.map +1 -1
  35. package/src/lib/components/crm-glance-card.js +2 -1
  36. package/src/lib/components/crm-glance-card.js.map +1 -1
  37. package/src/lib/components/crm-send-email-dialog.js +9 -6
  38. package/src/lib/components/crm-send-email-dialog.js.map +1 -1
  39. package/src/lib/components/csv-import-drawer.js +2 -2
  40. package/src/lib/components/csv-import-drawer.js.map +1 -1
  41. package/src/lib/components/deal-detail-page.js +18 -2
  42. package/src/lib/components/deal-detail-page.js.map +1 -1
  43. package/src/lib/components/deal-edit-drawer.js +10 -0
  44. package/src/lib/components/deal-edit-drawer.js.map +1 -1
  45. package/src/lib/components/deal-products-card.js +27 -16
  46. package/src/lib/components/deal-products-card.js.map +1 -1
  47. package/src/lib/components/deals-bulk-bar.js +13 -5
  48. package/src/lib/components/deals-bulk-bar.js.map +1 -1
  49. package/src/lib/components/lead-campaigns-card.d.ts +4 -4
  50. package/src/lib/components/lead-campaigns-card.js +15 -8
  51. package/src/lib/components/lead-campaigns-card.js.map +1 -1
  52. package/src/lib/components/lead-detail-page.js +25 -5
  53. package/src/lib/components/lead-detail-page.js.map +1 -1
  54. package/src/lib/components/lead-properties-card.js +10 -0
  55. package/src/lib/components/lead-properties-card.js.map +1 -1
  56. package/src/lib/components/lead-status-chip.js +3 -1
  57. package/src/lib/components/lead-status-chip.js.map +1 -1
  58. package/src/lib/components/lead-surfaces-note.js +4 -5
  59. package/src/lib/components/lead-surfaces-note.js.map +1 -1
  60. package/src/lib/components/lead-unqualify-dialog.js +6 -0
  61. package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
  62. package/src/lib/components/leads-bulk-bar.js +34 -11
  63. package/src/lib/components/leads-bulk-bar.js.map +1 -1
  64. package/src/lib/components/leads-section.js +41 -8
  65. package/src/lib/components/leads-section.js.map +1 -1
  66. package/src/lib/components/new-lead-drawer.js +5 -4
  67. package/src/lib/components/new-lead-drawer.js.map +1 -1
  68. package/src/lib/components/org-lead-surfaces-note.js +6 -2
  69. package/src/lib/components/org-lead-surfaces-note.js.map +1 -1
  70. package/src/lib/components/recipes-card.js +9 -4
  71. package/src/lib/components/recipes-card.js.map +1 -1
  72. package/src/lib/components/record-sharing-card.d.ts +57 -0
  73. package/src/lib/components/record-sharing-card.js +244 -0
  74. package/src/lib/components/record-sharing-card.js.map +1 -0
  75. package/src/lib/components/reports/activity-card.js +4 -3
  76. package/src/lib/components/reports/activity-card.js.map +1 -1
  77. package/src/lib/components/reports/closed-deals-card.js +4 -3
  78. package/src/lib/components/reports/closed-deals-card.js.map +1 -1
  79. package/src/lib/components/reports/contacts-mix-card.js +3 -2
  80. package/src/lib/components/reports/contacts-mix-card.js.map +1 -1
  81. package/src/lib/components/reports/contacts-trend-card.js +2 -1
  82. package/src/lib/components/reports/contacts-trend-card.js.map +1 -1
  83. package/src/lib/components/reports/forecast-card.js +3 -2
  84. package/src/lib/components/reports/forecast-card.js.map +1 -1
  85. package/src/lib/components/reports/lead-funnel-card.js +8 -6
  86. package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
  87. package/src/lib/components/reports/pipeline-card.js +4 -3
  88. package/src/lib/components/reports/pipeline-card.js.map +1 -1
  89. package/src/lib/components/reports/report-format.d.ts +1 -1
  90. package/src/lib/components/reports/report-format.js.map +1 -1
  91. package/src/lib/components/reports/report-scope.d.ts +1 -1
  92. package/src/lib/components/reports/report-scope.js.map +1 -1
  93. package/src/lib/components/reports/source-conversion-card.js +2 -1
  94. package/src/lib/components/reports/source-conversion-card.js.map +1 -1
  95. package/src/lib/components/reports/tasks-card.js +2 -1
  96. package/src/lib/components/reports/tasks-card.js.map +1 -1
  97. package/src/lib/components/reports/won-lost-by-owner-card.js +3 -2
  98. package/src/lib/components/reports/won-lost-by-owner-card.js.map +1 -1
  99. package/src/lib/components/reports-section.js +4 -4
  100. package/src/lib/components/reports-section.js.map +1 -1
  101. package/src/lib/components/settings-section.js +7 -0
  102. package/src/lib/components/settings-section.js.map +1 -1
  103. package/src/lib/components/share-records-dialog.d.ts +28 -0
  104. package/src/lib/components/share-records-dialog.js +184 -0
  105. package/src/lib/components/share-records-dialog.js.map +1 -0
  106. package/src/lib/components/sharing-rule-drawer.d.ts +37 -0
  107. package/src/lib/components/sharing-rule-drawer.js +374 -0
  108. package/src/lib/components/sharing-rule-drawer.js.map +1 -0
  109. package/src/lib/components/sharing-rules-card.d.ts +24 -0
  110. package/src/lib/components/sharing-rules-card.js +287 -0
  111. package/src/lib/components/sharing-rules-card.js.map +1 -0
  112. package/src/lib/components/use-crm-api.d.ts +1 -1
  113. package/src/lib/components/use-crm-api.js.map +1 -1
  114. package/src/lib/components/use-site-route-context.d.ts +25 -0
  115. package/src/lib/components/use-site-route-context.js +58 -0
  116. package/src/lib/components/use-site-route-context.js.map +1 -0
  117. package/src/lib/constants/api-routes.d.ts +31 -0
  118. package/src/lib/constants/api-routes.js +27 -1
  119. package/src/lib/constants/api-routes.js.map +1 -1
  120. package/src/lib/constants/bundle-common.d.ts +2 -0
  121. package/src/lib/constants/bundle-common.js +1 -0
  122. package/src/lib/constants/bundle-common.js.map +1 -1
  123. package/src/lib/declarations.console-server.d.ts +41 -0
  124. package/src/lib/declarations.console-server.js +115 -0
  125. package/src/lib/declarations.console-server.js.map +1 -0
  126. package/src/lib/declarations.server.d.ts +12 -0
  127. package/src/lib/declarations.server.js +84 -1
  128. package/src/lib/declarations.server.js.map +1 -1
  129. package/src/lib/hooks/use-contact-remove.d.ts +35 -0
  130. package/src/lib/hooks/use-contact-remove.js +77 -0
  131. package/src/lib/hooks/use-contact-remove.js.map +1 -0
  132. package/src/lib/hooks/use-crm-campaigns.d.ts +2 -2
  133. package/src/lib/hooks/use-crm-campaigns.js +3 -3
  134. package/src/lib/hooks/use-crm-campaigns.js.map +1 -1
  135. package/src/lib/hooks/use-crm-sharing.d.ts +30 -0
  136. package/src/lib/hooks/use-crm-sharing.js +109 -0
  137. package/src/lib/hooks/use-crm-sharing.js.map +1 -0
  138. package/src/lib/model/campaign-filing-activity.d.ts +1 -1
  139. package/src/lib/model/campaign-filing-activity.js +1 -1
  140. package/src/lib/model/campaign-filing-activity.js.map +1 -1
  141. package/src/lib/model/companies-csv.d.ts +1 -1
  142. package/src/lib/model/companies-csv.js +2 -2
  143. package/src/lib/model/companies-csv.js.map +1 -1
  144. package/src/lib/model/contact-holder.d.ts +68 -0
  145. package/src/lib/model/contact-holder.js +129 -0
  146. package/src/lib/model/contact-holder.js.map +1 -0
  147. package/src/lib/model/contact-interaction-links.d.ts +46 -0
  148. package/src/lib/model/contact-interaction-links.js +65 -0
  149. package/src/lib/model/contact-interaction-links.js.map +1 -0
  150. package/src/lib/model/contact-merge.d.ts +136 -0
  151. package/src/lib/model/contact-merge.js +412 -0
  152. package/src/lib/model/contact-merge.js.map +1 -0
  153. package/src/lib/model/contact-record.d.ts +7 -1
  154. package/src/lib/model/contact-record.js +7 -6
  155. package/src/lib/model/contact-record.js.map +1 -1
  156. package/src/lib/model/contact-remove.d.ts +48 -0
  157. package/src/lib/model/contact-remove.js +22 -0
  158. package/src/lib/model/contact-remove.js.map +1 -0
  159. package/src/lib/model/contacts-bulk-writes.d.ts +2 -71
  160. package/src/lib/model/contacts-bulk-writes.js +2 -82
  161. package/src/lib/model/contacts-bulk-writes.js.map +1 -1
  162. package/src/lib/model/contacts-csv.d.ts +2 -2
  163. package/src/lib/model/contacts-csv.js +2 -2
  164. package/src/lib/model/contacts-csv.js.map +1 -1
  165. package/src/lib/model/crm-csv.d.ts +239 -0
  166. package/src/lib/model/crm-csv.js +467 -0
  167. package/src/lib/model/crm-csv.js.map +1 -0
  168. package/src/lib/model/crm-digest.d.ts +227 -0
  169. package/src/lib/model/crm-digest.js +336 -0
  170. package/src/lib/model/crm-digest.js.map +1 -0
  171. package/src/lib/model/crm-import.d.ts +7 -1
  172. package/src/lib/model/crm-import.js +2 -1
  173. package/src/lib/model/crm-import.js.map +1 -1
  174. package/src/lib/model/crm-inbound.d.ts +162 -0
  175. package/src/lib/model/crm-inbound.js +208 -0
  176. package/src/lib/model/crm-inbound.js.map +1 -0
  177. package/src/lib/model/crm-lead-import.d.ts +1 -1
  178. package/src/lib/model/crm-lead-import.js +4 -4
  179. package/src/lib/model/crm-lead-import.js.map +1 -1
  180. package/src/lib/model/crm-record-routes.d.ts +5 -0
  181. package/src/lib/model/crm-record-routes.js +7 -0
  182. package/src/lib/model/crm-record-routes.js.map +1 -1
  183. package/src/lib/model/crm-reports.d.ts +467 -0
  184. package/src/lib/model/crm-reports.js +667 -0
  185. package/src/lib/model/crm-reports.js.map +1 -0
  186. package/src/lib/model/crm-routes.d.ts +6 -5
  187. package/src/lib/model/crm-routes.js +7 -7
  188. package/src/lib/model/crm-routes.js.map +1 -1
  189. package/src/lib/model/crm-search-sources.d.ts +15 -0
  190. package/src/lib/model/crm-search-sources.js +162 -0
  191. package/src/lib/model/crm-search-sources.js.map +1 -0
  192. package/src/lib/model/crm-sharing-api.d.ts +32 -0
  193. package/src/lib/model/crm-sharing-api.js +59 -0
  194. package/src/lib/model/crm-sharing-api.js.map +1 -0
  195. package/src/lib/model/crm-sharing.d.ts +333 -0
  196. package/src/lib/model/crm-sharing.js +603 -0
  197. package/src/lib/model/crm-sharing.js.map +1 -0
  198. package/src/lib/model/deals-csv.d.ts +1 -1
  199. package/src/lib/model/deals-csv.js +4 -5
  200. package/src/lib/model/deals-csv.js.map +1 -1
  201. package/src/lib/model/lead-filters.d.ts +5 -4
  202. package/src/lib/model/lead-filters.js +7 -5
  203. package/src/lib/model/lead-filters.js.map +1 -1
  204. package/src/lib/model/leads-csv.d.ts +1 -1
  205. package/src/lib/model/leads-csv.js +1 -1
  206. package/src/lib/model/leads-csv.js.map +1 -1
  207. package/src/lib/model/tasks-csv.d.ts +1 -1
  208. package/src/lib/model/tasks-csv.js +1 -1
  209. package/src/lib/model/tasks-csv.js.map +1 -1
  210. package/src/lib/plan-entitlements.d.ts +75 -0
  211. package/src/lib/plan-entitlements.js +56 -0
  212. package/src/lib/plan-entitlements.js.map +1 -0
  213. package/src/lib/plugin.js +39 -0
  214. package/src/lib/plugin.js.map +1 -1
  215. package/src/lib/server/api-v1/contacts-merge.d.ts +20 -0
  216. package/src/lib/server/api-v1/contacts-merge.js +120 -0
  217. package/src/lib/server/api-v1/contacts-merge.js.map +1 -0
  218. package/src/lib/server/api-v1/contacts.d.ts +18 -0
  219. package/src/lib/server/api-v1/contacts.js +1076 -0
  220. package/src/lib/server/api-v1/contacts.js.map +1 -0
  221. package/src/lib/server/api-v1/crm-activities.d.ts +18 -0
  222. package/src/lib/server/api-v1/crm-activities.js +269 -0
  223. package/src/lib/server/api-v1/crm-activities.js.map +1 -0
  224. package/src/lib/server/api-v1/crm-companies.d.ts +18 -0
  225. package/src/lib/server/api-v1/crm-companies.js +391 -0
  226. package/src/lib/server/api-v1/crm-companies.js.map +1 -0
  227. package/src/lib/server/api-v1/crm-deals.d.ts +18 -0
  228. package/src/lib/server/api-v1/crm-deals.js +631 -0
  229. package/src/lib/server/api-v1/crm-deals.js.map +1 -0
  230. package/src/lib/server/api-v1/crm-email-templates.d.ts +18 -0
  231. package/src/lib/server/api-v1/crm-email-templates.js +336 -0
  232. package/src/lib/server/api-v1/crm-email-templates.js.map +1 -0
  233. package/src/lib/server/api-v1/crm-leads.d.ts +18 -0
  234. package/src/lib/server/api-v1/crm-leads.js +833 -0
  235. package/src/lib/server/api-v1/crm-leads.js.map +1 -0
  236. package/src/lib/server/api-v1/crm-pipelines.d.ts +76 -0
  237. package/src/lib/server/api-v1/crm-pipelines.js +146 -0
  238. package/src/lib/server/api-v1/crm-pipelines.js.map +1 -0
  239. package/src/lib/server/api-v1/crm-shared.d.ts +271 -0
  240. package/src/lib/server/api-v1/crm-shared.js +436 -0
  241. package/src/lib/server/api-v1/crm-shared.js.map +1 -0
  242. package/src/lib/server/api-v1/crm-tasks.d.ts +18 -0
  243. package/src/lib/server/api-v1/crm-tasks.js +398 -0
  244. package/src/lib/server/api-v1/crm-tasks.js.map +1 -0
  245. package/src/lib/server/api-v1/openapi.d.ts +29 -0
  246. package/src/lib/server/api-v1/openapi.js +985 -0
  247. package/src/lib/server/api-v1/openapi.js.map +1 -0
  248. package/src/lib/server/api-v1/usage.d.ts +26 -0
  249. package/src/lib/server/api-v1/usage.js +73 -0
  250. package/src/lib/server/api-v1/usage.js.map +1 -0
  251. package/src/lib/server/campaign-filing-activity.d.ts +1 -1
  252. package/src/lib/server/campaign-filing-activity.js +7 -11
  253. package/src/lib/server/campaign-filing-activity.js.map +1 -1
  254. package/src/lib/server/capture-contact.js +15 -4
  255. package/src/lib/server/capture-contact.js.map +1 -1
  256. package/src/lib/server/consent-group-participant.js +1 -1
  257. package/src/lib/server/consent-group-participant.js.map +1 -1
  258. package/src/lib/server/contact-email-engagement.d.ts +33 -0
  259. package/src/lib/server/contact-email-engagement.js +146 -0
  260. package/src/lib/server/contact-email-engagement.js.map +1 -0
  261. package/src/lib/server/contact-lifecycle-floor.d.ts +89 -0
  262. package/src/lib/server/contact-lifecycle-floor.js +91 -0
  263. package/src/lib/server/contact-lifecycle-floor.js.map +1 -0
  264. package/src/lib/server/contact-remove.d.ts +75 -0
  265. package/src/lib/server/contact-remove.js +244 -0
  266. package/src/lib/server/contact-remove.js.map +1 -0
  267. package/src/lib/server/contact-update.js +4 -3
  268. package/src/lib/server/contact-update.js.map +1 -1
  269. package/src/lib/server/contacts-import.d.ts +47 -11
  270. package/src/lib/server/contacts-import.js +171 -71
  271. package/src/lib/server/contacts-import.js.map +1 -1
  272. package/src/lib/server/contacts-merge.d.ts +1 -1
  273. package/src/lib/server/contacts-merge.js +3 -2
  274. package/src/lib/server/contacts-merge.js.map +1 -1
  275. package/src/lib/server/container-detach.d.ts +31 -0
  276. package/src/lib/server/container-detach.js +115 -0
  277. package/src/lib/server/container-detach.js.map +1 -0
  278. package/src/lib/server/convert-host-lead.d.ts +189 -0
  279. package/src/lib/server/convert-host-lead.js +518 -0
  280. package/src/lib/server/convert-host-lead.js.map +1 -0
  281. package/src/lib/server/crm-inbound-email.d.ts +162 -0
  282. package/src/lib/server/crm-inbound-email.js +259 -0
  283. package/src/lib/server/crm-inbound-email.js.map +1 -0
  284. package/src/lib/server/crm-records-meter.d.ts +50 -0
  285. package/src/lib/server/crm-records-meter.js +126 -0
  286. package/src/lib/server/crm-records-meter.js.map +1 -0
  287. package/src/lib/server/crm-sharing.d.ts +108 -0
  288. package/src/lib/server/crm-sharing.js +790 -0
  289. package/src/lib/server/crm-sharing.js.map +1 -0
  290. package/src/lib/server/daily-digest-route.d.ts +101 -0
  291. package/src/lib/server/daily-digest-route.js +578 -0
  292. package/src/lib/server/daily-digest-route.js.map +1 -0
  293. package/src/lib/server/export-route.d.ts +60 -0
  294. package/src/lib/server/export-route.js +447 -0
  295. package/src/lib/server/export-route.js.map +1 -0
  296. package/src/lib/server/inbound-address.js +5 -3
  297. package/src/lib/server/inbound-address.js.map +1 -1
  298. package/src/lib/server/inbound-route.d.ts +74 -0
  299. package/src/lib/server/inbound-route.js +260 -0
  300. package/src/lib/server/inbound-route.js.map +1 -0
  301. package/src/lib/server/lead-campaign-carry.js +3 -3
  302. package/src/lib/server/lead-campaign-carry.js.map +1 -1
  303. package/src/lib/server/lead-convert.d.ts +1 -1
  304. package/src/lib/server/lead-convert.js +2 -2
  305. package/src/lib/server/lead-convert.js.map +1 -1
  306. package/src/lib/server/lead-create.d.ts +1 -1
  307. package/src/lib/server/lead-create.js +10 -15
  308. package/src/lib/server/lead-create.js.map +1 -1
  309. package/src/lib/server/lead-nurturing.d.ts +23 -0
  310. package/src/lib/server/lead-nurturing.js +82 -0
  311. package/src/lib/server/lead-nurturing.js.map +1 -0
  312. package/src/lib/server/leads-import.js +7 -7
  313. package/src/lib/server/leads-import.js.map +1 -1
  314. package/src/lib/server/merge-contacts.d.ts +55 -0
  315. package/src/lib/server/merge-contacts.js +274 -0
  316. package/src/lib/server/merge-contacts.js.map +1 -0
  317. package/src/lib/server/pipeline-record-index.d.ts +36 -0
  318. package/src/lib/server/pipeline-record-index.js +87 -0
  319. package/src/lib/server/pipeline-record-index.js.map +1 -0
  320. package/src/lib/server/record-email-state.js +23 -0
  321. package/src/lib/server/record-email-state.js.map +1 -1
  322. package/src/lib/server/record-facts.js +2 -1
  323. package/src/lib/server/record-facts.js.map +1 -1
  324. package/src/lib/server/record-timeline.d.ts +12 -0
  325. package/src/lib/server/record-timeline.js +127 -15
  326. package/src/lib/server/record-timeline.js.map +1 -1
  327. package/src/lib/server/task-reminders-route.d.ts +82 -0
  328. package/src/lib/server/task-reminders-route.js +499 -0
  329. package/src/lib/server/task-reminders-route.js.map +1 -0
  330. package/src/lib/server/task-routes.d.ts +2 -0
  331. package/src/lib/server/task-routes.js +22 -3
  332. package/src/lib/server/task-routes.js.map +1 -1
  333. package/src/lib/server-deal-stage.js +2 -1
  334. package/src/lib/server-deal-stage.js.map +1 -1
  335. package/src/lib/server.d.ts +5 -2
  336. package/src/lib/server.js +47 -2
  337. package/src/lib/server.js.map +1 -1
  338. package/src/lib/testing/stand-in-site-record-routes.d.ts +26 -0
  339. package/src/lib/testing/stand-in-site-record-routes.js +55 -0
  340. package/src/lib/testing/stand-in-site-record-routes.js.map +1 -0
  341. package/src/lib/usage-axes.d.ts +35 -0
  342. package/src/lib/usage-axes.js +75 -0
  343. package/src/lib/usage-axes.js.map +1 -0
  344. package/src/lib/components/use-emails-hub-path.d.ts +0 -24
  345. package/src/lib/components/use-emails-hub-path.js +0 -59
  346. package/src/lib/components/use-emails-hub-path.js.map +0 -1
@@ -0,0 +1,41 @@
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 CONSOLE-ONLY server declarations, named under
19
+ * `consoleServerDeclarations` in `plugins.config.json` and run at the
20
+ * console's boot.
21
+ *
22
+ * It serves the CRM's resources of `/v1` (AGL-2606): the console's router
23
+ * owns the pipeline in front of them — the key, the plan's API access, the
24
+ * quota, the rate limit, the error envelope — and hands every request under
25
+ * `/v1/contacts`, `/v1/deals` and the rest to the CRM once the key is
26
+ * authenticated and the organization's plan carries the CRM. Each resource
27
+ * brings its description for the API's OpenAPI document, and the CRM's
28
+ * records band and collection sizes join `GET /v1/usage`. The API is the
29
+ * console's alone, so the tenant runtime does not register them.
30
+ *
31
+ * It also clears a removed container off the CRM's records: a campaign is
32
+ * deleted from the console, and its owner asks every plugin's membership
33
+ * detacher first (`server/container-detach.ts`).
34
+ *
35
+ * Light at boot: each resource's module is imported with its first request,
36
+ * the descriptions when the document is first built, and the usage reader
37
+ * with the first usage call.
38
+ * Registering again replaces this plugin's own entries, so a second call (a
39
+ * hot reload, a spec) is harmless.
40
+ */
41
+ export declare function registerCrmConsoleServerDeclarations(): void;
@@ -0,0 +1,115 @@
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 registry's own module, not the data layer's barrel: boot needs one
17
+ // registry, not the whole server surface.
18
+ import { registerApiV1Resource, registerApiV1UsageFigures } from "@aglyn/tenant-data-admin/server/api-v1-resources";
19
+ import { listPluginMembershipDetachers, registerPluginMembershipDetacher } from "@aglyn/aglyn/plugin-manager/plugin-membership-detach";
20
+ import { BUNDLE_ID } from "./constants/bundle-common.js";
21
+ /**
22
+ * The plan feature every CRM resource of `/v1` needs, and the sentence its
23
+ * refusal says (AGL-2611, AGL-2851): the whole CRM is included from
24
+ * Starter, so a Free workspace reads and changes none of it over the API. A
25
+ * capture still records people on every plan; working them is the CRM.
26
+ */ const CRM_SUITE = {
27
+ feature: 'crm',
28
+ message: 'The CRM — contacts, leads, companies, deals, tasks, pipelines, ' + 'activities and email templates — is not included in this organization’s plan'
29
+ };
30
+ /**
31
+ * The CRM's resources on the customer REST API, each handler loaded with the
32
+ * first request for it. In the order the API root lists them: the people
33
+ * first, then the records a team keeps about them, then a site's leads
34
+ * (`/v1/leads?siteId=`, a top-level path with the site as a parameter), then
35
+ * the letters sent from a record (AGL-2658).
36
+ */ const CRM_API_V1_RESOURCES = [
37
+ [
38
+ 'contacts',
39
+ async (...args)=>(await import("./server/api-v1/contacts.js")).handleContacts(...args)
40
+ ],
41
+ [
42
+ 'companies',
43
+ async (...args)=>(await import("./server/api-v1/crm-companies.js")).handleCompanies(...args)
44
+ ],
45
+ [
46
+ 'pipelines',
47
+ async (...args)=>(await import("./server/api-v1/crm-pipelines.js")).handlePipelines(...args)
48
+ ],
49
+ [
50
+ 'deals',
51
+ async (...args)=>(await import("./server/api-v1/crm-deals.js")).handleDeals(...args)
52
+ ],
53
+ [
54
+ 'tasks',
55
+ async (...args)=>(await import("./server/api-v1/crm-tasks.js")).handleTasks(...args)
56
+ ],
57
+ [
58
+ 'activities',
59
+ async (...args)=>(await import("./server/api-v1/crm-activities.js")).handleActivities(...args)
60
+ ],
61
+ [
62
+ 'leads',
63
+ async (...args)=>(await import("./server/api-v1/crm-leads.js")).handleLeads(...args)
64
+ ],
65
+ [
66
+ 'email-templates',
67
+ async (...args)=>(await import("./server/api-v1/crm-email-templates.js")).handleEmailTemplates(...args)
68
+ ]
69
+ ];
70
+ /**
71
+ * The CRM's CONSOLE-ONLY server declarations, named under
72
+ * `consoleServerDeclarations` in `plugins.config.json` and run at the
73
+ * console's boot.
74
+ *
75
+ * It serves the CRM's resources of `/v1` (AGL-2606): the console's router
76
+ * owns the pipeline in front of them — the key, the plan's API access, the
77
+ * quota, the rate limit, the error envelope — and hands every request under
78
+ * `/v1/contacts`, `/v1/deals` and the rest to the CRM once the key is
79
+ * authenticated and the organization's plan carries the CRM. Each resource
80
+ * brings its description for the API's OpenAPI document, and the CRM's
81
+ * records band and collection sizes join `GET /v1/usage`. The API is the
82
+ * console's alone, so the tenant runtime does not register them.
83
+ *
84
+ * It also clears a removed container off the CRM's records: a campaign is
85
+ * deleted from the console, and its owner asks every plugin's membership
86
+ * detacher first (`server/container-detach.ts`).
87
+ *
88
+ * Light at boot: each resource's module is imported with its first request,
89
+ * the descriptions when the document is first built, and the usage reader
90
+ * with the first usage call.
91
+ * Registering again replaces this plugin's own entries, so a second call (a
92
+ * hot reload, a spec) is harmless.
93
+ */ export function registerCrmConsoleServerDeclarations() {
94
+ for (const [resource, handle] of CRM_API_V1_RESOURCES){
95
+ registerApiV1Resource(resource, {
96
+ handle,
97
+ entitlement: CRM_SUITE,
98
+ describe: async ()=>(await import("./server/api-v1/openapi.js")).CRM_API_V1_DESCRIPTIONS[resource]
99
+ }, {
100
+ pluginId: BUNDLE_ID
101
+ });
102
+ }
103
+ registerApiV1UsageFigures(async (ctx)=>(await import("./server/api-v1/usage.js")).crmUsageFigures(ctx), {
104
+ pluginId: BUNDLE_ID
105
+ });
106
+ // A removed container — a deleted campaign — comes off every lead and every
107
+ // contact facet naming it, before its owner removes it (AGL-3080).
108
+ if (!listPluginMembershipDetachers().includes(BUNDLE_ID)) {
109
+ registerPluginMembershipDetacher(async (request)=>(await import("./server/container-detach.js")).crmContainerDetacher(request), {
110
+ pluginId: BUNDLE_ID
111
+ });
112
+ }
113
+ }
114
+
115
+ //# sourceMappingURL=declarations.console-server.js.map
@@ -0,0 +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"}
@@ -15,6 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import { type PluginContactCaptureWriter } from '@aglyn/aglyn/plugin-manager/plugin-contact-capture';
18
+ import { type PluginRecordIndex } from '@aglyn/aglyn/plugin-manager/plugin-record-index';
19
+ import { type PluginRecordTimelineWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-timeline';
18
20
  /**
19
21
  * The CRM as the plugin that keeps people.
20
22
  *
@@ -25,6 +27,16 @@ import { type PluginContactCaptureWriter } from '@aglyn/aglyn/plugin-manager/plu
25
27
  * including ones that will never touch the CRM.
26
28
  */
27
29
  export declare const crmContactCaptureWriter: PluginContactCaptureWriter;
30
+ /**
31
+ * The `pipeline` record index, its reads loaded with the first one — see
32
+ * `server/pipeline-record-index.ts` for what it answers.
33
+ */
34
+ export declare const crmPipelineRecordIndex: PluginRecordIndex;
35
+ /**
36
+ * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the
37
+ * writer and the Admin SDK it brings load with the first entry filed.
38
+ */
39
+ export declare const crmRecordTimelineWriter: PluginRecordTimelineWriter;
28
40
  /**
29
41
  * The plugin's SERVER declarations: what the server must know at boot, before
30
42
  * any door of the CRM has been called.
@@ -19,8 +19,12 @@ 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 { registerPluginRecordIndex } from "@aglyn/aglyn/plugin-manager/plugin-record-index";
22
23
  import { registerPluginRecordEmailStateWriter } from "@aglyn/aglyn/plugin-manager/plugin-record-email-state";
23
- import { BUNDLE_ID } from "./constants/bundle-common.js";
24
+ import { registerPluginRecordTimelineWriter } from "@aglyn/aglyn/plugin-manager/plugin-record-timeline";
25
+ import { registerPluginRecordWrittenListener } from "@aglyn/aglyn/plugin-manager/plugin-record-written";
26
+ import { registerPluginUsageMeter } from "@aglyn/aglyn/plugin-manager/plugin-usage-meters";
27
+ import { BUNDLE_ID, CRM_RECORDS_METER_ID } from "./constants/bundle-common.js";
24
28
  import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
25
29
  /**
26
30
  * The CRM as the plugin that keeps people.
@@ -36,6 +40,36 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
36
40
  return await captureContactForCrm(request);
37
41
  }
38
42
  };
43
+ /**
44
+ * The `pipeline` record index, its reads loaded with the first one — see
45
+ * `server/pipeline-record-index.ts` for what it answers.
46
+ */ export const crmPipelineRecordIndex = {
47
+ async list (request) {
48
+ const { pipelineRecordIndex } = await import("./server/pipeline-record-index.js");
49
+ return pipelineRecordIndex.list(request);
50
+ },
51
+ async get (request) {
52
+ const { pipelineRecordIndex } = await import("./server/pipeline-record-index.js");
53
+ return pipelineRecordIndex.get(request);
54
+ }
55
+ };
56
+ /**
57
+ * The CRM's writer on the record-timeline seam (AGL-2981), deferred: the
58
+ * writer and the Admin SDK it brings load with the first entry filed.
59
+ */ export const crmRecordTimelineWriter = {
60
+ async logActivity (request) {
61
+ const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } = await import("./server/record-timeline.js");
62
+ return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).logActivity(request);
63
+ },
64
+ async createTask (request) {
65
+ const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } = await import("./server/record-timeline.js");
66
+ return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).createTask(request);
67
+ },
68
+ async recordEmailDelivery (request) {
69
+ const { createCrmRecordTimelineWriter, defaultCrmRecordTimelineDeps } = await import("./server/record-timeline.js");
70
+ return createCrmRecordTimelineWriter(defaultCrmRecordTimelineDeps()).recordEmailDelivery(request);
71
+ }
72
+ };
39
73
  /**
40
74
  * The plugin's SERVER declarations: what the server must know at boot, before
41
75
  * any door of the CRM has been called.
@@ -101,10 +135,47 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
101
135
  async stamp (request) {
102
136
  const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } = await import("./server/record-email-state.js");
103
137
  return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).stamp(request);
138
+ },
139
+ // A send's first opens and clicks, stamped on the contacts they name
140
+ // (AGL-2616) — the campaign webhook's courtesy, deferred like the rest.
141
+ async engaged (request) {
142
+ const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } = await import("./server/record-email-state.js");
143
+ return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).engaged(request);
144
+ },
145
+ // A delivered campaign's leads, moved to Nurturing (AGL-3446).
146
+ async reached (request) {
147
+ const { createCrmRecordEmailStateWriter, defaultCrmRecordEmailStateDeps } = await import("./server/record-email-state.js");
148
+ return createCrmRecordEmailStateWriter(defaultCrmRecordEmailStateDeps()).reached(request);
104
149
  }
105
150
  }, {
106
151
  pluginId: BUNDLE_ID
107
152
  });
153
+ // The record timeline writer (AGL-2981), here as well as in the API
154
+ // surfaces so a door in either app reaches it: a booking confirmed on the
155
+ // tenant, or by the payment webhook, files its meeting and follow-up
156
+ // through it (AGL-2660). Deferred like the rest; an API registration
157
+ // replaces this one with the same writer, loaded eagerly.
158
+ registerPluginRecordTimelineWriter(crmRecordTimelineWriter, {
159
+ pluginId: BUNDLE_ID
160
+ });
161
+ // Sharing rules (AGL-3336), re-evaluated after every server write of a
162
+ // lead, a contact, a company or a deal: the core tells its record-written
163
+ // listeners from the list-field restamp every such writer ends with, in
164
+ // both apps — a form's capture on the tenant, an edit in the console.
165
+ // Deferred like the rest: an org with no rules pays one cached read.
166
+ registerPluginRecordWrittenListener(async (event)=>{
167
+ const { crmSharingRecordWritten } = await import("./server/crm-sharing.js");
168
+ await crmSharingRecordWritten(event);
169
+ }, {
170
+ pluginId: BUNDLE_ID,
171
+ key: 'sharing'
172
+ });
173
+ // The organization's pipelines and their stages, as another plugin reads
174
+ // them (AGL-3080): an automation the AI drafts names the stage a deal
175
+ // moves to. Deferred like the rest: the reads load with the first one.
176
+ registerPluginRecordIndex('pipeline', crmPipelineRecordIndex, {
177
+ pluginId: BUNDLE_ID
178
+ });
108
179
  registerPluginConsentGroupParticipant({
109
180
  async preview (request) {
110
181
  const { consentGroupParticipant } = await import("./server/consent-group-participant.js");
@@ -118,6 +189,18 @@ import { summarizeConsentGroupChange } from "./model/consent-group-summary.js";
118
189
  }, {
119
190
  pluginId: BUNDLE_ID
120
191
  });
192
+ // The records band in the monthly usage sweep, a core cron that never
193
+ // loads a CRM door; declared in `usageAxes` so the sweep refuses to bill a
194
+ // month without it. Deferred like the rest: the counts load with the
195
+ // first sweep.
196
+ registerPluginUsageMeter({
197
+ pluginId: BUNDLE_ID,
198
+ id: CRM_RECORDS_METER_ID,
199
+ measure: async (context)=>{
200
+ const { measureCrmRecords } = await import("./server/crm-records-meter.js");
201
+ return measureCrmRecords(context);
202
+ }
203
+ });
121
204
  }
122
205
 
123
206
  //# sourceMappingURL=declarations.server.js.map
@@ -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 { registerPluginRecordEmailStateWriter } from '@aglyn/aglyn/plugin-manager/plugin-record-email-state'\nimport { BUNDLE_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 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 },\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}\n\n"],"names":["registerPluginConsentGroupParticipant","registerPluginContactCaptureWriter","registerPluginLeadConversionListener","registerPluginPersonMatcher","registerPluginRecordEmailStateWriter","BUNDLE_ID","summarizeConsentGroupChange","crmContactCaptureWriter","capture","request","captureContactForCrm","registerCrmServerDeclarations","pluginId","carryLeadCampaignsOnConversion","matchCrmPeople","stamp","createCrmRecordEmailStateWriter","defaultCrmRecordEmailStateDeps","preview","consentGroupParticipant","run","summarize"],"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,SAASC,oCAAoC,QAAQ,wDAAuD;AAC5G,SAASC,SAAS,QAAQ,+BAA2B;AACrD,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;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASE;IACdV,mCAAmCM,yBAAyB;QAC1DK,UAAUP;IACZ;IACA,kEAAkE;IAClE,qEAAqE;IACrE,mEAAmE;IACnE,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,8DAA8D;IAC9DH,qCACE,OAAOO;QACL,MAAM,EAAEI,8BAA8B,EAAE,GACtC,MAAM,MAAM,CAAC;QACf,OAAOA,+BAA+BJ;IACxC,GACA;QAAEG,UAAUP;IAAU;IAExB,0EAA0E;IAC1E,2EAA2E;IAC3E,uEAAuE;IACvEF,4BACE,OAAOM;QACL,MAAM,EAAEK,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC;QACxC,OAAOA,eAAeL;IACxB,GACA;QAAEG,UAAUP;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;IAC1BD,qCACE;QACE,MAAMW,OAAMN,OAAO;YACjB,MAAM,EAAEO,+BAA+B,EAAEC,8BAA8B,EAAE,GACvE,MAAM,MAAM,CAAC;YACf,OAAOD,gCAAgCC,kCAAkCF,KAAK,CAACN;QACjF;IACF,GACA;QAAEG,UAAUP;IAAU;IAExBL,sCACE;QACE,MAAMkB,SAAQT,OAAO;YACnB,MAAM,EAAEU,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC;YACjD,OAAOA,wBAAwBD,OAAO,CAACT;QACzC;QACA,MAAMW,KAAIX,OAAO;YACf,MAAM,EAAEU,uBAAuB,EAAE,GAAG,MAAM,MAAM,CAAC;YACjD,OAAOA,wBAAwBC,GAAG,CAACX;QACrC;QACAY,WAAWf;IACb,GACA;QAAEM,UAAUP;IAAU;AAE1B"}
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"}
@@ -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
+ */
17
+ import type { CrmBulkAnswer } from '../model/crm-bulk-writes';
18
+ /**
19
+ * THE CONSOLE'S DOOR TO `crm/contact-remove` (AGL-3338).
20
+ *
21
+ * The record page's Delete and the contacts bar's Remove let contacts go
22
+ * through here rather than writing the document: the route decides detach
23
+ * or delete against the stored consent map, keeps every refusal, and the
24
+ * rules refuse a client the write.
25
+ *
26
+ * A request refused WHOLE — no session, no permission — throws with the
27
+ * route's sentence. `removeMany` answers per contact in the bulk runners'
28
+ * shape; `removeOne` throws that contact's refusal and otherwise says
29
+ * whether the document was deleted or only this site's half of it.
30
+ */
31
+ export declare function useContactRemove(hostId: string | null): {
32
+ removeMany: (contactIds: readonly string[]) => Promise<CrmBulkAnswer[]>;
33
+ removeOne: (contactId: string) => Promise<"deleted" | "detached">;
34
+ };
35
+ export default useContactRemove;
@@ -0,0 +1,77 @@
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 { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { useCallback, useMemo } from "react";
19
+ import { useCrmApi } from "../components/use-crm-api.js";
20
+ /**
21
+ * THE CONSOLE'S DOOR TO `crm/contact-remove` (AGL-3338).
22
+ *
23
+ * The record page's Delete and the contacts bar's Remove let contacts go
24
+ * through here rather than writing the document: the route decides detach
25
+ * or delete against the stored consent map, keeps every refusal, and the
26
+ * rules refuse a client the write.
27
+ *
28
+ * A request refused WHOLE — no session, no permission — throws with the
29
+ * route's sentence. `removeMany` answers per contact in the bulk runners'
30
+ * shape; `removeOne` throws that contact's refusal and otherwise says
31
+ * whether the document was deleted or only this site's half of it.
32
+ */ export function useContactRemove(hostId) {
33
+ const callCrm = useCrmApi(hostId);
34
+ const removeOutcomes = useCallback(async (contactIds)=>{
35
+ const { response, payload } = await callCrm('contact-remove', {
36
+ contactIds: [
37
+ ...contactIds
38
+ ]
39
+ });
40
+ if (!response.ok) {
41
+ const error = payload['error'];
42
+ throw new Error(typeof error === 'string' && error ? error : `The contact could not be removed (${response.status}).`);
43
+ }
44
+ return Array.isArray(payload['results']) ? payload['results'] : [];
45
+ }, [
46
+ callCrm
47
+ ]);
48
+ const removeMany = useCallback(async (contactIds)=>(await removeOutcomes(contactIds)).map((outcome)=>_extends({
49
+ id: outcome.contactId,
50
+ ok: outcome.ok
51
+ }, 'error' in outcome ? {
52
+ error: outcome.error
53
+ } : {})), [
54
+ removeOutcomes
55
+ ]);
56
+ const removeOne = useCallback(async (contactId)=>{
57
+ const [outcome] = await removeOutcomes([
58
+ contactId
59
+ ]);
60
+ if (!(outcome == null ? void 0 : outcome.ok)) {
61
+ throw new Error(outcome && 'error' in outcome && outcome.error || 'The contact could not be removed.');
62
+ }
63
+ return outcome.removed;
64
+ }, [
65
+ removeOutcomes
66
+ ]);
67
+ return useMemo(()=>({
68
+ removeMany,
69
+ removeOne
70
+ }), [
71
+ removeMany,
72
+ removeOne
73
+ ]);
74
+ }
75
+ export default useContactRemove;
76
+
77
+ //# sourceMappingURL=use-contact-remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-contact-remove.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'use client'\n\nimport { useCallback, useMemo } from 'react'\nimport { useCrmApi } from '../components/use-crm-api'\nimport type { ContactRemoveOutcome } from '../model/contact-remove'\nimport type { CrmBulkAnswer } from '../model/crm-bulk-writes'\n\n/**\n * THE CONSOLE'S DOOR TO `crm/contact-remove` (AGL-3338).\n *\n * The record page's Delete and the contacts bar's Remove let contacts go\n * through here rather than writing the document: the route decides detach\n * or delete against the stored consent map, keeps every refusal, and the\n * rules refuse a client the write.\n *\n * A request refused WHOLE — no session, no permission — throws with the\n * route's sentence. `removeMany` answers per contact in the bulk runners'\n * shape; `removeOne` throws that contact's refusal and otherwise says\n * whether the document was deleted or only this site's half of it.\n */\nexport function useContactRemove(hostId: string | null) {\n const callCrm = useCrmApi(hostId)\n\n const removeOutcomes = useCallback(\n async (contactIds: readonly string[]): Promise<ContactRemoveOutcome[]> => {\n const { response, payload } = await callCrm('contact-remove', {\n contactIds: [...contactIds],\n })\n if (!response.ok) {\n const error = payload['error']\n throw new Error(\n typeof error === 'string' && error\n ? error\n : `The contact could not be removed (${response.status}).`,\n )\n }\n return Array.isArray(payload['results']) ? payload['results'] : []\n },\n [callCrm],\n )\n\n const removeMany = useCallback(\n async (contactIds: readonly string[]): Promise<CrmBulkAnswer[]> =>\n (await removeOutcomes(contactIds)).map((outcome) => ({\n id: outcome.contactId,\n ok: outcome.ok,\n ...('error' in outcome ? { error: outcome.error } : {}),\n })),\n [removeOutcomes],\n )\n\n const removeOne = useCallback(\n async (contactId: string): Promise<'deleted' | 'detached'> => {\n const [outcome] = await removeOutcomes([contactId])\n if (!outcome?.ok) {\n throw new Error(\n (outcome && 'error' in outcome && outcome.error) || 'The contact could not be removed.',\n )\n }\n return outcome.removed\n },\n [removeOutcomes],\n )\n\n return useMemo(() => ({ removeMany, removeOne }), [removeMany, removeOne])\n}\n\nexport default useContactRemove\n"],"names":["useCallback","useMemo","useCrmApi","useContactRemove","hostId","callCrm","removeOutcomes","contactIds","response","payload","ok","error","Error","status","Array","isArray","removeMany","map","outcome","id","contactId","removeOne","removed"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;AAEA,SAASA,WAAW,EAAEC,OAAO,QAAQ,QAAO;AAC5C,SAASC,SAAS,QAAQ,+BAA2B;AAIrD;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC,iBAAiBC,MAAqB;IACpD,MAAMC,UAAUH,UAAUE;IAE1B,MAAME,iBAAiBN,YACrB,OAAOO;QACL,MAAM,EAAEC,QAAQ,EAAEC,OAAO,EAAE,GAAG,MAAMJ,QAAQ,kBAAkB;YAC5DE,YAAY;mBAAIA;aAAW;QAC7B;QACA,IAAI,CAACC,SAASE,EAAE,EAAE;YAChB,MAAMC,QAAQF,OAAO,CAAC,QAAQ;YAC9B,MAAM,IAAIG,MACR,OAAOD,UAAU,YAAYA,QACzBA,QACA,CAAC,kCAAkC,EAAEH,SAASK,MAAM,CAAC,EAAE,CAAC;QAEhE;QACA,OAAOC,MAAMC,OAAO,CAACN,OAAO,CAAC,UAAU,IAAIA,OAAO,CAAC,UAAU,GAAG,EAAE;IACpE,GACA;QAACJ;KAAQ;IAGX,MAAMW,aAAahB,YACjB,OAAOO,aACL,AAAC,CAAA,MAAMD,eAAeC,WAAU,EAAGU,GAAG,CAAC,CAACC,UAAa;gBACnDC,IAAID,QAAQE,SAAS;gBACrBV,IAAIQ,QAAQR,EAAE;eACV,WAAWQ,UAAU;gBAAEP,OAAOO,QAAQP,KAAK;YAAC,IAAI,CAAC,KAEzD;QAACL;KAAe;IAGlB,MAAMe,YAAYrB,YAChB,OAAOoB;QACL,MAAM,CAACF,QAAQ,GAAG,MAAMZ,eAAe;YAACc;SAAU;QAClD,IAAI,EAACF,2BAAAA,QAASR,EAAE,GAAE;YAChB,MAAM,IAAIE,MACR,AAACM,WAAW,WAAWA,WAAWA,QAAQP,KAAK,IAAK;QAExD;QACA,OAAOO,QAAQI,OAAO;IACxB,GACA;QAAChB;KAAe;IAGlB,OAAOL,QAAQ,IAAO,CAAA;YAAEe;YAAYK;QAAU,CAAA,GAAI;QAACL;QAAYK;KAAU;AAC3E;AAEA,eAAelB,iBAAgB"}
@@ -1,4 +1,4 @@
1
- import { type HostCampaigns } from '@aglyn/tenant-feature-instance';
1
+ import { type ContainerOptions } from '@aglyn/tenant-feature-instance';
2
2
  /**
3
3
  * THE CAMPAIGNS A CRM SURFACE OFFERS AND NAMES, at either level.
4
4
  *
@@ -17,5 +17,5 @@ export declare function useCrmCampaigns(scope: {
17
17
  orgId: string | null | undefined;
18
18
  }, options?: {
19
19
  enabled?: boolean;
20
- }): HostCampaigns;
20
+ }): ContainerOptions;
21
21
  export default useCrmCampaigns;
@@ -14,7 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */ 'use client';
17
- import { useHostCampaigns, useOrgCampaigns } from "@aglyn/tenant-feature-instance";
17
+ import { useSiteContainerOptions, useOrgContainerOptions } from "@aglyn/tenant-feature-instance";
18
18
  /**
19
19
  * THE CAMPAIGNS A CRM SURFACE OFFERS AND NAMES, at either level.
20
20
  *
@@ -31,10 +31,10 @@ import { useHostCampaigns, useOrgCampaigns } from "@aglyn/tenant-feature-instanc
31
31
  var _ref;
32
32
  const enabled = (_ref = options == null ? void 0 : options.enabled) != null ? _ref : false;
33
33
  const hostId = scope.hostId || null;
34
- const site = useHostCampaigns(hostId != null ? hostId : undefined, {
34
+ const site = useSiteContainerOptions('campaign', hostId != null ? hostId : undefined, {
35
35
  enabled: enabled && Boolean(hostId)
36
36
  });
37
- const org = useOrgCampaigns(scope.orgId, {
37
+ const org = useOrgContainerOptions('campaign', scope.orgId, {
38
38
  enabled: enabled && !hostId
39
39
  });
40
40
  return hostId ? site : org;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-campaigns.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 {\n useHostCampaigns,\n useOrgCampaigns,\n type HostCampaigns,\n} from '@aglyn/tenant-feature-instance'\n\n/**\n * THE CAMPAIGNS A CRM SURFACE OFFERS AND NAMES, at either level.\n *\n * Campaigns belong to the organization, and so do leads. Under a site the\n * list is the campaigns placed on that site — the ones its hub shows and\n * its captures file under. At the organization level (`hostId` null) it is\n * every campaign in the org, because the list there spans every site and a\n * lead from any of them may be filed under any campaign.\n *\n * Both hooks are called on every render, since a hook may not be called\n * conditionally; only the one for this level is enabled, so only one\n * listener opens.\n */\nexport function useCrmCampaigns(\n scope: {\n hostId: string | null | undefined\n orgId: string | null | undefined\n },\n options?: { enabled?: boolean },\n): HostCampaigns {\n const enabled = options?.enabled ?? false\n const hostId = scope.hostId || null\n const site = useHostCampaigns(hostId ?? undefined, {\n enabled: enabled && Boolean(hostId),\n })\n const org = useOrgCampaigns(scope.orgId, {\n enabled: enabled && !hostId,\n })\n return hostId ? site : org\n}\n\nexport default useCrmCampaigns\n"],"names":["useHostCampaigns","useOrgCampaigns","useCrmCampaigns","scope","options","enabled","hostId","site","undefined","Boolean","org","orgId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SACEA,gBAAgB,EAChBC,eAAe,QAEV,iCAAgC;AAEvC;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC,gBACdC,KAGC,EACDC,OAA+B;;IAE/B,MAAMC,kBAAUD,2BAAAA,QAASC,OAAO,mBAAI;IACpC,MAAMC,SAASH,MAAMG,MAAM,IAAI;IAC/B,MAAMC,OAAOP,iBAAiBM,iBAAAA,SAAUE,WAAW;QACjDH,SAASA,WAAWI,QAAQH;IAC9B;IACA,MAAMI,MAAMT,gBAAgBE,MAAMQ,KAAK,EAAE;QACvCN,SAASA,WAAW,CAACC;IACvB;IACA,OAAOA,SAASC,OAAOG;AACzB;AAEA,eAAeR,gBAAe"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-campaigns.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 {\n useSiteContainerOptions,\n useOrgContainerOptions,\n type ContainerOptions,\n} from '@aglyn/tenant-feature-instance'\n\n/**\n * THE CAMPAIGNS A CRM SURFACE OFFERS AND NAMES, at either level.\n *\n * Campaigns belong to the organization, and so do leads. Under a site the\n * list is the campaigns placed on that site — the ones its hub shows and\n * its captures file under. At the organization level (`hostId` null) it is\n * every campaign in the org, because the list there spans every site and a\n * lead from any of them may be filed under any campaign.\n *\n * Both hooks are called on every render, since a hook may not be called\n * conditionally; only the one for this level is enabled, so only one\n * listener opens.\n */\nexport function useCrmCampaigns(\n scope: {\n hostId: string | null | undefined\n orgId: string | null | undefined\n },\n options?: { enabled?: boolean },\n): ContainerOptions {\n const enabled = options?.enabled ?? false\n const hostId = scope.hostId || null\n const site = useSiteContainerOptions('campaign', hostId ?? undefined, {\n enabled: enabled && Boolean(hostId),\n })\n const org = useOrgContainerOptions('campaign', scope.orgId, {\n enabled: enabled && !hostId,\n })\n return hostId ? site : org\n}\n\nexport default useCrmCampaigns\n"],"names":["useSiteContainerOptions","useOrgContainerOptions","useCrmCampaigns","scope","options","enabled","hostId","site","undefined","Boolean","org","orgId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SACEA,uBAAuB,EACvBC,sBAAsB,QAEjB,iCAAgC;AAEvC;;;;;;;;;;;;CAYC,GACD,OAAO,SAASC,gBACdC,KAGC,EACDC,OAA+B;;IAE/B,MAAMC,kBAAUD,2BAAAA,QAASC,OAAO,mBAAI;IACpC,MAAMC,SAASH,MAAMG,MAAM,IAAI;IAC/B,MAAMC,OAAOP,wBAAwB,YAAYM,iBAAAA,SAAUE,WAAW;QACpEH,SAASA,WAAWI,QAAQH;IAC9B;IACA,MAAMI,MAAMT,uBAAuB,YAAYE,MAAMQ,KAAK,EAAE;QAC1DN,SAASA,WAAW,CAACC;IACvB;IACA,OAAOA,SAASC,OAAOG;AACzB;AAEA,eAAeR,gBAAe"}
@@ -0,0 +1,30 @@
1
+ import { type CrmSharingObject, type CrmSharingSite } from '../model/crm-sharing';
2
+ import type { CrmOrgDoc } from './use-crm-scope';
3
+ export interface CrmSharingSites {
4
+ sites: CrmSharingSite[];
5
+ ready: boolean;
6
+ /** How a site reads: its name, or a neutral phrase for one this reader cannot name. */
7
+ siteName: (hostId: string) => string;
8
+ }
9
+ /**
10
+ * The org's sites, for a sharing surface (AGL-3336).
11
+ *
12
+ * At the organization level the hub already holds them (`useCrmOrgMount`).
13
+ * Under a site a member cannot list the org's other sites, so a MANAGER's
14
+ * surface asks `crm/sharing` for them — the one reader a share is offered
15
+ * to — and every other reader names them as "another site".
16
+ */
17
+ export declare function useCrmSharingSites(input: {
18
+ hostId: string | null;
19
+ orgId: string | null;
20
+ enabled: boolean;
21
+ }): CrmSharingSites;
22
+ /** The org's sharing rules, off the org document the shell already passed. */
23
+ export declare function useCrmSharingRules(org: CrmOrgDoc): import("../model/crm-sharing").CrmSharingRule[];
24
+ /**
25
+ * The follow-up a CLIENT-DIRECT write to a lead, a company or a deal owes
26
+ * the org's sharing rules (AGL-3336): a server write is followed by the
27
+ * core's record-written seam, a browser's by this. Fire-and-forget — the
28
+ * save has landed whether or not a rule then shares the record.
29
+ */
30
+ export declare function useCrmSharingFollowUp(hostId: string | null | undefined, orgId: string | null | undefined): (object: CrmSharingObject, ids: readonly string[]) => void;