@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,287 @@
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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import { CONTACT_LIFECYCLE_STAGE_LABELS, CRM_LEAD_STATUS_LABELS, pluginDocsHelp } from "@aglyn/aglyn";
19
+ import { mdiDeleteOutline, mdiPencilOutline, mdiRefresh } from "@aglyn/shared-data-mdi";
20
+ import { CardDisplay, MdiIcon } from "@aglyn/shared-ui-jsx";
21
+ import RowActionsMenu from "@aglyn/shared-ui-jsx/components/row-actions-menu.component";
22
+ import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
23
+ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
24
+ import { useUser } from "@aglyn/tenant-feature-instance";
25
+ import { Button, LinearProgress, Stack, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material";
26
+ import { useCallback, useState } from "react";
27
+ import { useCrmCampaigns } from "../hooks/use-crm-campaigns.js";
28
+ import { useCrmSharingRules, useCrmSharingSites } from "../hooks/use-crm-sharing.js";
29
+ import { useOrgMemberDirectory } from "../hooks/use-org-member-directory.js";
30
+ import { CRM_SHARING_RULES_MAX, describeShareTargets, describeSharingRuleScope } from "../model/crm-sharing.js";
31
+ import { callCrmSharing } from "../model/crm-sharing-api.js";
32
+ import { SharingRuleDrawer } from "./sharing-rule-drawer.js";
33
+ /** How far a rule's recompute has got, as the table shows it. */ function runLabel(rule) {
34
+ var _run_error;
35
+ const run = rule.run;
36
+ if (rule.deleting) return 'Removing what it shared…';
37
+ if (!run) return rule.enabled ? 'On' : 'Off';
38
+ if (run.status === 'running') {
39
+ return `${run.mode === 'remove' ? 'Removing' : 'Applying'} — ${run.processed} checked, ${run.changed} changed`;
40
+ }
41
+ if (run.status === 'failed') return (_run_error = run.error) != null ? _run_error : 'Stopped';
42
+ return `${rule.enabled ? 'On' : 'Off'} — ${run.changed} ${run.changed === 1 ? 'record' : 'records'} changed`;
43
+ }
44
+ /**
45
+ * SHARING RULES — the organization's automated sharing (AGL-3336).
46
+ *
47
+ * A rule shares every record it matches with other sites: the existing ones
48
+ * through a recompute that runs when the rule is saved, with its progress
49
+ * on the row, and every later capture or change through the record-written
50
+ * seam. The recompute runs in passes; the card keeps asking while the page
51
+ * is open, and a rule whose run stopped offers Resume.
52
+ *
53
+ * Mounted at the organization level only: a rule is a fact about the org,
54
+ * and its targets are the org's sites.
55
+ */ export function SharingRulesCard(props) {
56
+ const { orgId, org, canManage, ready } = props;
57
+ const { data: user } = useUser();
58
+ const { enqueueSnackbar } = useSnackbar();
59
+ const rules = useCrmSharingRules(org);
60
+ const sites = useCrmSharingSites({
61
+ hostId: null,
62
+ orgId,
63
+ enabled: canManage
64
+ });
65
+ const roster = useOrgMemberDirectory(orgId);
66
+ const campaigns = useCrmCampaigns({
67
+ hostId: null,
68
+ orgId
69
+ }, {
70
+ enabled: canManage
71
+ });
72
+ const [editing, setEditing] = useState(null);
73
+ const [drawerOpen, setDrawerOpen] = useState(false);
74
+ const [busy, setBusy] = useState(false);
75
+ const scope = orgId ? {
76
+ orgId
77
+ } : null;
78
+ /** One action, then `rule-continue` until the rule's run has nothing left. */ const run = useCallback(async (action, body, said)=>{
79
+ if (!scope) return;
80
+ setBusy(true);
81
+ try {
82
+ var _ref, _body_ruleId;
83
+ var _answer_rule;
84
+ let answer = await callCrmSharing(user, scope, action, body);
85
+ const ruleId = (_ref = (_answer_rule = answer.rule) == null ? void 0 : _answer_rule.id) != null ? _ref : String((_body_ruleId = body['ruleId']) != null ? _body_ruleId : '');
86
+ while(answer.more && ruleId){
87
+ answer = await callCrmSharing(user, scope, 'rule-continue', {
88
+ ruleId
89
+ });
90
+ }
91
+ enqueueSnackbar(said, {
92
+ variant: 'success',
93
+ persist: false
94
+ });
95
+ setDrawerOpen(false);
96
+ } catch (error) {
97
+ enqueueSnackbar(error.message, {
98
+ variant: 'error',
99
+ allowDuplicate: true
100
+ });
101
+ } finally{
102
+ setBusy(false);
103
+ }
104
+ }, // `scope` is rebuilt from `orgId` every render.
105
+ // eslint-disable-next-line react-hooks/exhaustive-deps
106
+ [
107
+ user,
108
+ orgId,
109
+ enqueueSnackbar
110
+ ]);
111
+ const save = (draft)=>void run('rule-save', {
112
+ rule: draft
113
+ }, draft.id ? 'Rule saved' : 'Rule added');
114
+ const canEdit = ready && canManage && !busy;
115
+ const stageLabel = (id)=>{
116
+ var _ref, _CRM_LEAD_STATUS_LABELS_id;
117
+ return (_ref = (_CRM_LEAD_STATUS_LABELS_id = CRM_LEAD_STATUS_LABELS[id]) != null ? _CRM_LEAD_STATUS_LABELS_id : CONTACT_LIFECYCLE_STAGE_LABELS[id]) != null ? _ref : id;
118
+ };
119
+ return /*#__PURE__*/ _jsxs(CardDisplay, {
120
+ header: 'Sharing rules',
121
+ help: pluginDocsHelp('crmSharing', {
122
+ anchor: '#sharing-rules'
123
+ }),
124
+ contentGutterX: true,
125
+ contentGutterY: true,
126
+ contentBordered: "all",
127
+ HeaderProps: {
128
+ action: /*#__PURE__*/ _jsx(Button, {
129
+ variant: "contained",
130
+ disabled: !canEdit || rules.length >= CRM_SHARING_RULES_MAX,
131
+ onClick: ()=>{
132
+ setEditing(null);
133
+ setDrawerOpen(true);
134
+ },
135
+ children: 'Add rule'
136
+ })
137
+ },
138
+ children: [
139
+ /*#__PURE__*/ _jsxs(Stack, {
140
+ spacing: 2,
141
+ children: [
142
+ /*#__PURE__*/ _jsx(Typography, {
143
+ variant: "body2",
144
+ color: "text.secondary",
145
+ children: 'Share leads, contacts, companies or deals captured on one site with other sites, ' + 'automatically. A rule applies to the records you have now and to every one captured ' + 'or changed later. Sharing is visibility only: a site never gains a person’s consent ' + 'through it.'
146
+ }),
147
+ busy ? /*#__PURE__*/ _jsx(LinearProgress, {}) : null,
148
+ rules.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
149
+ variant: "body2",
150
+ color: "text.secondary",
151
+ children: 'No sharing rules. Every record is visible only to the sites that captured it.'
152
+ }) : /*#__PURE__*/ _jsxs(ScrollTable, {
153
+ size: "small",
154
+ children: [
155
+ /*#__PURE__*/ _jsx(TableHead, {
156
+ children: /*#__PURE__*/ _jsxs(TableRow, {
157
+ children: [
158
+ /*#__PURE__*/ _jsx(TableCell, {
159
+ children: 'Rule'
160
+ }),
161
+ /*#__PURE__*/ _jsx(TableCell, {
162
+ children: 'Which records'
163
+ }),
164
+ /*#__PURE__*/ _jsx(TableCell, {
165
+ children: 'Shared with'
166
+ }),
167
+ /*#__PURE__*/ _jsx(TableCell, {
168
+ children: 'Status'
169
+ }),
170
+ /*#__PURE__*/ _jsx(TableCell, {
171
+ align: "right"
172
+ })
173
+ ]
174
+ })
175
+ }),
176
+ /*#__PURE__*/ _jsx(TableBody, {
177
+ children: rules.map((rule)=>/*#__PURE__*/ _jsxs(TableRow, {
178
+ hover: true,
179
+ children: [
180
+ /*#__PURE__*/ _jsx(TableCell, {
181
+ children: /*#__PURE__*/ _jsx(Typography, {
182
+ variant: "body2",
183
+ children: rule.name
184
+ })
185
+ }),
186
+ /*#__PURE__*/ _jsx(TableCell, {
187
+ children: /*#__PURE__*/ _jsx(Typography, {
188
+ variant: "body2",
189
+ children: describeSharingRuleScope(rule, sites.siteName, {
190
+ owner: roster.nameOf,
191
+ stage: stageLabel
192
+ })
193
+ })
194
+ }),
195
+ /*#__PURE__*/ _jsx(TableCell, {
196
+ children: /*#__PURE__*/ _jsx(Typography, {
197
+ variant: "body2",
198
+ children: `${describeShareTargets(rule.targets, sites.siteName)}, ${rule.access === 'edit' ? 'read and edit' : 'read-only'}`
199
+ })
200
+ }),
201
+ /*#__PURE__*/ _jsx(TableCell, {
202
+ children: /*#__PURE__*/ _jsx(Typography, {
203
+ variant: "body2",
204
+ color: "text.secondary",
205
+ children: runLabel(rule)
206
+ })
207
+ }),
208
+ /*#__PURE__*/ _jsx(TableCell, {
209
+ align: "right",
210
+ sx: {
211
+ width: 56
212
+ },
213
+ children: /*#__PURE__*/ _jsx(RowActionsMenu, {
214
+ label: rule.name,
215
+ items: [
216
+ {
217
+ key: 'edit',
218
+ label: 'Edit rule',
219
+ icon: /*#__PURE__*/ _jsx(MdiIcon, {
220
+ path: mdiPencilOutline.path,
221
+ size: 0.8
222
+ }),
223
+ disabled: !canEdit || rule.deleting === true,
224
+ onClick: ()=>{
225
+ setEditing(rule);
226
+ setDrawerOpen(true);
227
+ }
228
+ },
229
+ ...rule.run && rule.run.status !== 'done' ? [
230
+ {
231
+ key: 'resume',
232
+ label: 'Resume',
233
+ icon: /*#__PURE__*/ _jsx(MdiIcon, {
234
+ path: mdiRefresh.path,
235
+ size: 0.8
236
+ }),
237
+ disabled: !canEdit,
238
+ onClick: ()=>void run('rule-continue', {
239
+ ruleId: rule.id
240
+ }, 'Rule applied')
241
+ }
242
+ ] : [],
243
+ {
244
+ key: 'delete',
245
+ label: 'Delete rule',
246
+ icon: /*#__PURE__*/ _jsx(MdiIcon, {
247
+ path: mdiDeleteOutline.path,
248
+ size: 0.8
249
+ }),
250
+ destructive: true,
251
+ disabled: !canEdit,
252
+ onClick: ()=>void run('rule-delete', {
253
+ ruleId: rule.id
254
+ }, 'Rule deleted')
255
+ }
256
+ ]
257
+ })
258
+ })
259
+ ]
260
+ }, rule.id))
261
+ })
262
+ ]
263
+ }),
264
+ ready && !canManage ? /*#__PURE__*/ _jsx(Typography, {
265
+ variant: "caption",
266
+ color: "text.secondary",
267
+ children: 'Only a workspace owner or admin can change sharing rules.'
268
+ }) : null
269
+ ]
270
+ }),
271
+ /*#__PURE__*/ _jsx(SharingRuleDrawer, {
272
+ open: drawerOpen,
273
+ onClose: ()=>setDrawerOpen(false),
274
+ rule: editing,
275
+ sites: sites.sites,
276
+ members: roster.members,
277
+ campaigns: campaigns.options,
278
+ busy: busy,
279
+ onSubmit: save
280
+ })
281
+ ]
282
+ });
283
+ }
284
+ SharingRulesCard.displayName = 'SharingRulesCard';
285
+ export default SharingRulesCard;
286
+
287
+ //# sourceMappingURL=sharing-rules-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/sharing-rules-card.tsx"],"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 CONTACT_LIFECYCLE_STAGE_LABELS,\n type ContactLifecycleStage,\n CRM_LEAD_STATUS_LABELS,\n type CrmLeadStatus,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport { mdiDeleteOutline, mdiPencilOutline, mdiRefresh } from '@aglyn/shared-data-mdi'\nimport { CardDisplay, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport RowActionsMenu from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n LinearProgress,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from '@mui/material'\nimport { useCallback, useState } from 'react'\nimport { useCrmCampaigns } from '../hooks/use-crm-campaigns'\nimport { useCrmSharingRules, useCrmSharingSites } from '../hooks/use-crm-sharing'\nimport type { CrmOrgDoc } from '../hooks/use-crm-scope'\nimport { useOrgMemberDirectory } from '../hooks/use-org-member-directory'\nimport {\n CRM_SHARING_RULES_MAX,\n type CrmSharingAction,\n type CrmSharingRule,\n describeShareTargets,\n describeSharingRuleScope,\n} from '../model/crm-sharing'\nimport { callCrmSharing } from '../model/crm-sharing-api'\nimport { SharingRuleDrawer, type SharingRuleDraft } from './sharing-rule-drawer'\n\nexport interface SharingRulesCardProps {\n orgId: string | null\n org: CrmOrgDoc\n canManage: boolean\n ready: boolean\n}\n\n/** How far a rule's recompute has got, as the table shows it. */\nfunction runLabel(rule: CrmSharingRule): string {\n const run = rule.run\n if (rule.deleting) return 'Removing what it shared…'\n if (!run) return rule.enabled ? 'On' : 'Off'\n if (run.status === 'running') {\n return `${run.mode === 'remove' ? 'Removing' : 'Applying'} — ${run.processed} checked, ${run.changed} changed`\n }\n if (run.status === 'failed') return run.error ?? 'Stopped'\n return `${rule.enabled ? 'On' : 'Off'} — ${run.changed} ${run.changed === 1 ? 'record' : 'records'} changed`\n}\n\n/**\n * SHARING RULES — the organization's automated sharing (AGL-3336).\n *\n * A rule shares every record it matches with other sites: the existing ones\n * through a recompute that runs when the rule is saved, with its progress\n * on the row, and every later capture or change through the record-written\n * seam. The recompute runs in passes; the card keeps asking while the page\n * is open, and a rule whose run stopped offers Resume.\n *\n * Mounted at the organization level only: a rule is a fact about the org,\n * and its targets are the org's sites.\n */\nexport function SharingRulesCard(props: SharingRulesCardProps) {\n const { orgId, org, canManage, ready } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const rules = useCrmSharingRules(org)\n const sites = useCrmSharingSites({ hostId: null, orgId, enabled: canManage })\n const roster = useOrgMemberDirectory(orgId)\n const campaigns = useCrmCampaigns({ hostId: null, orgId }, { enabled: canManage })\n const [editing, setEditing] = useState<CrmSharingRule | null>(null)\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [busy, setBusy] = useState(false)\n const scope = orgId ? { orgId } : null\n\n /** One action, then `rule-continue` until the rule's run has nothing left. */\n const run = useCallback(\n async (action: CrmSharingAction, body: Record<string, unknown>, said: string) => {\n if (!scope) return\n setBusy(true)\n try {\n let answer = await callCrmSharing(user, scope, action, body)\n const ruleId = answer.rule?.id ?? String(body['ruleId'] ?? '')\n while (answer.more && ruleId) {\n answer = await callCrmSharing(user, scope, 'rule-continue', { ruleId })\n }\n enqueueSnackbar(said, { variant: 'success', persist: false })\n setDrawerOpen(false)\n } catch (error) {\n enqueueSnackbar((error as Error).message, { variant: 'error', allowDuplicate: true })\n } finally {\n setBusy(false)\n }\n },\n // `scope` is rebuilt from `orgId` every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [user, orgId, enqueueSnackbar],\n )\n\n const save = (draft: SharingRuleDraft) =>\n void run('rule-save', { rule: draft }, draft.id ? 'Rule saved' : 'Rule added')\n\n const canEdit = ready && canManage && !busy\n const stageLabel = (id: string) =>\n CRM_LEAD_STATUS_LABELS[id as CrmLeadStatus] ??\n CONTACT_LIFECYCLE_STAGE_LABELS[id as ContactLifecycleStage] ??\n id\n return (\n <CardDisplay\n header={'Sharing rules'}\n help={pluginDocsHelp('crmSharing', { anchor: '#sharing-rules' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n HeaderProps={{\n action: (\n <Button\n variant=\"contained\"\n disabled={!canEdit || rules.length >= CRM_SHARING_RULES_MAX}\n onClick={() => {\n setEditing(null)\n setDrawerOpen(true)\n }}\n >\n {'Add rule'}\n </Button>\n ),\n }}\n >\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Share leads, contacts, companies or deals captured on one site with other sites, ' +\n 'automatically. A rule applies to the records you have now and to every one captured ' +\n 'or changed later. Sharing is visibility only: a site never gains a person’s consent ' +\n 'through it.'}\n </Typography>\n {busy ? <LinearProgress /> : null}\n {rules.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No sharing rules. Every record is visible only to the sites that captured it.'}\n </Typography>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Rule'}</TableCell>\n <TableCell>{'Which records'}</TableCell>\n <TableCell>{'Shared with'}</TableCell>\n <TableCell>{'Status'}</TableCell>\n <TableCell align=\"right\" />\n </TableRow>\n </TableHead>\n <TableBody>\n {rules.map((rule) => (\n <TableRow key={rule.id} hover>\n <TableCell>\n <Typography variant=\"body2\">{rule.name}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">\n {describeSharingRuleScope(rule, sites.siteName, {\n owner: roster.nameOf,\n stage: stageLabel,\n })}\n </Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">\n {`${describeShareTargets(rule.targets, sites.siteName)}, ${\n rule.access === 'edit' ? 'read and edit' : 'read-only'\n }`}\n </Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {runLabel(rule)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\" sx={{ width: 56 }}>\n <RowActionsMenu\n label={rule.name}\n items={[\n {\n key: 'edit',\n label: 'Edit rule',\n icon: <MdiIcon path={mdiPencilOutline.path} size={0.8} />,\n disabled: !canEdit || rule.deleting === true,\n onClick: () => {\n setEditing(rule)\n setDrawerOpen(true)\n },\n },\n ...(rule.run && rule.run.status !== 'done'\n ? [\n {\n key: 'resume',\n label: 'Resume',\n icon: <MdiIcon path={mdiRefresh.path} size={0.8} />,\n disabled: !canEdit,\n onClick: () =>\n void run('rule-continue', { ruleId: rule.id }, 'Rule applied'),\n },\n ]\n : []),\n {\n key: 'delete',\n label: 'Delete rule',\n icon: <MdiIcon path={mdiDeleteOutline.path} size={0.8} />,\n destructive: true,\n disabled: !canEdit,\n onClick: () =>\n void run('rule-delete', { ruleId: rule.id }, 'Rule deleted'),\n },\n ]}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n {ready && !canManage ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Only a workspace owner or admin can change sharing rules.'}\n </Typography>\n ) : null}\n </Stack>\n <SharingRuleDrawer\n open={drawerOpen}\n onClose={() => setDrawerOpen(false)}\n rule={editing}\n sites={sites.sites}\n members={roster.members}\n campaigns={campaigns.options}\n busy={busy}\n onSubmit={save}\n />\n </CardDisplay>\n )\n}\nSharingRulesCard.displayName = 'SharingRulesCard'\n\nexport default SharingRulesCard\n"],"names":["CONTACT_LIFECYCLE_STAGE_LABELS","CRM_LEAD_STATUS_LABELS","pluginDocsHelp","mdiDeleteOutline","mdiPencilOutline","mdiRefresh","CardDisplay","MdiIcon","RowActionsMenu","ScrollTable","useSnackbar","useUser","Button","LinearProgress","Stack","TableBody","TableCell","TableHead","TableRow","Typography","useCallback","useState","useCrmCampaigns","useCrmSharingRules","useCrmSharingSites","useOrgMemberDirectory","CRM_SHARING_RULES_MAX","describeShareTargets","describeSharingRuleScope","callCrmSharing","SharingRuleDrawer","runLabel","rule","run","deleting","enabled","status","mode","processed","changed","error","SharingRulesCard","props","orgId","org","canManage","ready","data","user","enqueueSnackbar","rules","sites","hostId","roster","campaigns","editing","setEditing","drawerOpen","setDrawerOpen","busy","setBusy","scope","action","body","said","answer","ruleId","id","String","more","variant","persist","message","allowDuplicate","save","draft","canEdit","stageLabel","header","help","anchor","contentGutterX","contentGutterY","contentBordered","HeaderProps","disabled","length","onClick","spacing","color","size","align","map","hover","name","siteName","owner","nameOf","stage","targets","access","sx","width","label","items","key","icon","path","destructive","open","onClose","members","options","onSubmit","displayName"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /** The routes `registerCrmConsoleApi` registers under `/api/crm/`. */
2
- export type CrmApiRoute = 'contacts-create' | 'leads-create' | 'contact-email-history' | 'contact-update' | 'company-delete' | 'contacts-merge' | 'email-send' | 'email-check' | 'erase-person' | 'org-activity' | 'recipe-install' | 'recipe-status' | 'inbound-address' | 'email-template-duplicate';
2
+ export type CrmApiRoute = 'contacts-create' | 'leads-create' | 'contact-email-history' | 'contact-update' | 'contact-remove' | 'company-delete' | 'contacts-merge' | 'email-send' | 'email-check' | 'erase-person' | 'org-activity' | 'recipe-install' | 'recipe-status' | 'inbound-address' | 'email-template-duplicate';
3
3
  /** What one call to the CRM API answered with. */
4
4
  export interface CrmApiResult {
5
5
  response: Response;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/use-crm-api.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 authorizedFetch,\n type TokenSource,\n} from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { useCallback, useRef } from 'react'\nimport { useCrmOrgMount } from '../hooks/use-crm-org-mount'\n\n/** The routes `registerCrmConsoleApi` registers under `/api/crm/`. */\nexport type CrmApiRoute =\n | 'contacts-create'\n | 'leads-create'\n | 'contact-email-history'\n | 'contact-update'\n | 'company-delete'\n | 'contacts-merge'\n | 'email-send'\n | 'email-check'\n | 'erase-person'\n | 'org-activity'\n | 'recipe-install'\n | 'recipe-status'\n | 'inbound-address'\n | 'email-template-duplicate'\n\n/** What one call to the CRM API answered with. */\nexport interface CrmApiResult {\n response: Response\n payload: Record<string, any>\n}\n\n/**\n * ONE AUTHORIZED POST TO THE CRM's SERVER HALF (AGL-2596).\n *\n * The route is a fixed member of {@link CrmApiRoute} rather than a string\n * the caller composes, so a component cannot post the console's credentials\n * anywhere this plugin does not own. The site id rides in the body because\n * that is where the dispatcher's per-site gate reads it from.\n *\n * The user is read through a ref, for the reason the campaign API hook\n * gives: the user object is a new object on most renders, and a callback\n * that changed identity with it would re-fire every effect that depends on\n * it. The token is fetched at call time either way — `authorizedFetch`\n * resolves it under a deadline and answers a 401 of its own rather than\n * sending the request unauthenticated, so a signed-out caller is told so\n * through the same `response.ok` branch every other refusal takes.\n */\n/**\n * ## The organization level\n *\n * Beneath the org hub's mount (AGL-2630) the body also names the ORG, and\n * that is what makes the call the route's org variant (AGL-2634): the route\n * authorizes the caller by the org rather than by a site's role, and a\n * `hostId` beside it — the record's own capturing site, or `null` for a\n * record no site has captured — is what the act needs a site FOR, never\n * what it is authorized against. Under a site there is no mount and the\n * body is what it always was.\n */\nexport function useCrmApi(\n /**\n * The site the request is made for. At the organization level the\n * record's own site, or `null` for a record no site has captured — the\n * org variant of a route serves both, and a route with no org variant\n * (a create, which is always captured BY a site) refuses the null as it\n * always has.\n */\n hostId: string | null,\n) {\n const { data: user } = useUser()\n const userRef = useRef(user)\n userRef.current = user\n const orgId = useCrmOrgMount()?.orgId ?? null\n return useCallback(\n async (\n route: CrmApiRoute,\n payload: Record<string, unknown>,\n ): Promise<CrmApiResult> => {\n const response = await authorizedFetch(\n userRef.current as TokenSource | null | undefined,\n `/api/crm/${route}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n ...(orgId ? { orgId } : {}),\n ...payload,\n }),\n },\n )\n const json = await response.json().catch(() => ({}))\n return { response, payload: json as Record<string, any> }\n },\n [hostId, orgId],\n )\n}\n\nexport default useCrmApi\n"],"names":["authorizedFetch","useUser","useCallback","useRef","useCrmOrgMount","useCrmApi","hostId","data","user","userRef","current","orgId","route","payload","response","method","headers","body","JSON","stringify","json","catch"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SACEA,eAAe,QAEV,2CAA0C;AACjD,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,WAAW,EAAEC,MAAM,QAAQ,QAAO;AAC3C,SAASC,cAAc,QAAQ,gCAA4B;AAyB3D;;;;;;;;;;;;;;;CAeC,GACD;;;;;;;;;;CAUC,GACD,OAAO,SAASC,UACd;;;;;;GAMC,GACDC,MAAqB;;QAKPF;IAHd,MAAM,EAAEG,MAAMC,IAAI,EAAE,GAAGP;IACvB,MAAMQ,UAAUN,OAAOK;IACvBC,QAAQC,OAAO,GAAGF;IAClB,MAAMG,iBAAQP,kBAAAA,qCAAAA,gBAAkBO,KAAK,mBAAI;IACzC,OAAOT,YACL,OACEU,OACAC;QAEA,MAAMC,WAAW,MAAMd,gBACrBS,QAAQC,OAAO,EACf,CAAC,SAAS,EAAEE,OAAO,EACnB;YACEG,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,MAAMC,KAAKC,SAAS,CAAC;gBACnBb;eACIK,QAAQ;gBAAEA;YAAM,IAAI,CAAC,GACtBE;QAEP;QAEF,MAAMO,OAAO,MAAMN,SAASM,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACjD,OAAO;YAAEP;YAAUD,SAASO;QAA4B;IAC1D,GACA;QAACd;QAAQK;KAAM;AAEnB;AAEA,eAAeN,UAAS"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/use-crm-api.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 authorizedFetch,\n type TokenSource,\n} from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { useCallback, useRef } from 'react'\nimport { useCrmOrgMount } from '../hooks/use-crm-org-mount'\n\n/** The routes `registerCrmConsoleApi` registers under `/api/crm/`. */\nexport type CrmApiRoute =\n | 'contacts-create'\n | 'leads-create'\n | 'contact-email-history'\n | 'contact-update'\n | 'contact-remove'\n | 'company-delete'\n | 'contacts-merge'\n | 'email-send'\n | 'email-check'\n | 'erase-person'\n | 'org-activity'\n | 'recipe-install'\n | 'recipe-status'\n | 'inbound-address'\n | 'email-template-duplicate'\n\n/** What one call to the CRM API answered with. */\nexport interface CrmApiResult {\n response: Response\n payload: Record<string, any>\n}\n\n/**\n * ONE AUTHORIZED POST TO THE CRM's SERVER HALF (AGL-2596).\n *\n * The route is a fixed member of {@link CrmApiRoute} rather than a string\n * the caller composes, so a component cannot post the console's credentials\n * anywhere this plugin does not own. The site id rides in the body because\n * that is where the dispatcher's per-site gate reads it from.\n *\n * The user is read through a ref, for the reason the campaign API hook\n * gives: the user object is a new object on most renders, and a callback\n * that changed identity with it would re-fire every effect that depends on\n * it. The token is fetched at call time either way — `authorizedFetch`\n * resolves it under a deadline and answers a 401 of its own rather than\n * sending the request unauthenticated, so a signed-out caller is told so\n * through the same `response.ok` branch every other refusal takes.\n */\n/**\n * ## The organization level\n *\n * Beneath the org hub's mount (AGL-2630) the body also names the ORG, and\n * that is what makes the call the route's org variant (AGL-2634): the route\n * authorizes the caller by the org rather than by a site's role, and a\n * `hostId` beside it — the record's own capturing site, or `null` for a\n * record no site has captured — is what the act needs a site FOR, never\n * what it is authorized against. Under a site there is no mount and the\n * body is what it always was.\n */\nexport function useCrmApi(\n /**\n * The site the request is made for. At the organization level the\n * record's own site, or `null` for a record no site has captured — the\n * org variant of a route serves both, and a route with no org variant\n * (a create, which is always captured BY a site) refuses the null as it\n * always has.\n */\n hostId: string | null,\n) {\n const { data: user } = useUser()\n const userRef = useRef(user)\n userRef.current = user\n const orgId = useCrmOrgMount()?.orgId ?? null\n return useCallback(\n async (\n route: CrmApiRoute,\n payload: Record<string, unknown>,\n ): Promise<CrmApiResult> => {\n const response = await authorizedFetch(\n userRef.current as TokenSource | null | undefined,\n `/api/crm/${route}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n ...(orgId ? { orgId } : {}),\n ...payload,\n }),\n },\n )\n const json = await response.json().catch(() => ({}))\n return { response, payload: json as Record<string, any> }\n },\n [hostId, orgId],\n )\n}\n\nexport default useCrmApi\n"],"names":["authorizedFetch","useUser","useCallback","useRef","useCrmOrgMount","useCrmApi","hostId","data","user","userRef","current","orgId","route","payload","response","method","headers","body","JSON","stringify","json","catch"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SACEA,eAAe,QAEV,2CAA0C;AACjD,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SAASC,WAAW,EAAEC,MAAM,QAAQ,QAAO;AAC3C,SAASC,cAAc,QAAQ,gCAA4B;AA0B3D;;;;;;;;;;;;;;;CAeC,GACD;;;;;;;;;;CAUC,GACD,OAAO,SAASC,UACd;;;;;;GAMC,GACDC,MAAqB;;QAKPF;IAHd,MAAM,EAAEG,MAAMC,IAAI,EAAE,GAAGP;IACvB,MAAMQ,UAAUN,OAAOK;IACvBC,QAAQC,OAAO,GAAGF;IAClB,MAAMG,iBAAQP,kBAAAA,qCAAAA,gBAAkBO,KAAK,mBAAI;IACzC,OAAOT,YACL,OACEU,OACAC;QAEA,MAAMC,WAAW,MAAMd,gBACrBS,QAAQC,OAAO,EACf,CAAC,SAAS,EAAEE,OAAO,EACnB;YACEG,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,MAAMC,KAAKC,SAAS,CAAC;gBACnBb;eACIK,QAAQ;gBAAEA;YAAM,IAAI,CAAC,GACtBE;QAEP;QAEF,MAAMO,OAAO,MAAMN,SAASM,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;QACjD,OAAO;YAAEP;YAAUD,SAASO;QAA4B;IAC1D,GACA;QAACd;QAAQK;KAAM;AAEnB;AAEA,eAAeN,UAAS"}
@@ -0,0 +1,25 @@
1
+ import type { PluginRecordRouteContext } from '@aglyn/aglyn/plugin-manager/plugin-record-routes';
2
+ /**
3
+ * The SITE a CRM surface asks the record-route registry about — the
4
+ * organization's slug and the site's subdomain — or `null` when it cannot
5
+ * name one (AGL-3080).
6
+ *
7
+ * What a CRM record page links to on another plugin's page is a site's: the
8
+ * report of an email a site sent, the Sending section that fixes a site's
9
+ * missing identity. The address itself is the owner's to publish
10
+ * (`pluginRecordHref('emailMessage', …)`), and this names the site to ask it
11
+ * for. Read off the URL rather than resolved, because the `[host]` segment is
12
+ * the site's subdomain and nothing a CRM component holds says what that is.
13
+ *
14
+ * ⚠️ Under a site, THIS SITE only. A record page under one site cannot
15
+ * address a sibling site's pages without that site's subdomain, which a
16
+ * contact document does not carry.
17
+ *
18
+ * At the ORGANIZATION level (AGL-2634) the URL names no site, and the mount
19
+ * holds the org's site list instead: handed a `hostId`, this answers that
20
+ * site — or `null` for a site whose subdomain the list could not answer,
21
+ * which is named and not linked. Handed none, `null`: an org-level page has
22
+ * no site of its own to fall back to.
23
+ */
24
+ export declare function useSiteRouteContext(hostId?: string | null): PluginRecordRouteContext | null;
25
+ export default useSiteRouteContext;
@@ -0,0 +1,58 @@
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 { useParams } from "next/navigation";
18
+ import { useCrmOrgMount } from "../hooks/use-crm-org-mount.js";
19
+ /**
20
+ * The SITE a CRM surface asks the record-route registry about — the
21
+ * organization's slug and the site's subdomain — or `null` when it cannot
22
+ * name one (AGL-3080).
23
+ *
24
+ * What a CRM record page links to on another plugin's page is a site's: the
25
+ * report of an email a site sent, the Sending section that fixes a site's
26
+ * missing identity. The address itself is the owner's to publish
27
+ * (`pluginRecordHref('emailMessage', …)`), and this names the site to ask it
28
+ * for. Read off the URL rather than resolved, because the `[host]` segment is
29
+ * the site's subdomain and nothing a CRM component holds says what that is.
30
+ *
31
+ * ⚠️ Under a site, THIS SITE only. A record page under one site cannot
32
+ * address a sibling site's pages without that site's subdomain, which a
33
+ * contact document does not carry.
34
+ *
35
+ * At the ORGANIZATION level (AGL-2634) the URL names no site, and the mount
36
+ * holds the org's site list instead: handed a `hostId`, this answers that
37
+ * site — or `null` for a site whose subdomain the list could not answer,
38
+ * which is named and not linked. Handed none, `null`: an org-level page has
39
+ * no site of its own to fall back to.
40
+ */ export function useSiteRouteContext(hostId) {
41
+ const params = useParams();
42
+ const mount = useCrmOrgMount();
43
+ const orgSlug = params == null ? void 0 : params.orgSlug;
44
+ const host = params == null ? void 0 : params.host;
45
+ if (orgSlug && host) return {
46
+ orgSlug,
47
+ host
48
+ };
49
+ if (!mount || !hostId) return null;
50
+ const subdomain = mount.siteSubdomain(hostId);
51
+ return subdomain ? {
52
+ orgSlug: mount.orgSlug,
53
+ host: subdomain
54
+ } : null;
55
+ }
56
+ export default useSiteRouteContext;
57
+
58
+ //# sourceMappingURL=use-site-route-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/components/use-site-route-context.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 { PluginRecordRouteContext } from '@aglyn/aglyn/plugin-manager/plugin-record-routes'\nimport { useParams } from 'next/navigation'\nimport { useCrmOrgMount } from '../hooks/use-crm-org-mount'\n\n/**\n * The SITE a CRM surface asks the record-route registry about — the\n * organization's slug and the site's subdomain — or `null` when it cannot\n * name one (AGL-3080).\n *\n * What a CRM record page links to on another plugin's page is a site's: the\n * report of an email a site sent, the Sending section that fixes a site's\n * missing identity. The address itself is the owner's to publish\n * (`pluginRecordHref('emailMessage', …)`), and this names the site to ask it\n * for. Read off the URL rather than resolved, because the `[host]` segment is\n * the site's subdomain and nothing a CRM component holds says what that is.\n *\n * ⚠️ Under a site, THIS SITE only. A record page under one site cannot\n * address a sibling site's pages without that site's subdomain, which a\n * contact document does not carry.\n *\n * At the ORGANIZATION level (AGL-2634) the URL names no site, and the mount\n * holds the org's site list instead: handed a `hostId`, this answers that\n * site — or `null` for a site whose subdomain the list could not answer,\n * which is named and not linked. Handed none, `null`: an org-level page has\n * no site of its own to fall back to.\n */\nexport function useSiteRouteContext(hostId?: string | null): PluginRecordRouteContext | null {\n const params = useParams<{ orgSlug: string; host: string }>()\n const mount = useCrmOrgMount()\n const orgSlug = params?.orgSlug\n const host = params?.host\n if (orgSlug && host) return { orgSlug, host }\n if (!mount || !hostId) return null\n const subdomain = mount.siteSubdomain(hostId)\n return subdomain ? { orgSlug: mount.orgSlug, host: subdomain } : null\n}\n\nexport default useSiteRouteContext\n"],"names":["useParams","useCrmOrgMount","useSiteRouteContext","hostId","params","mount","orgSlug","host","subdomain","siteSubdomain"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAGA,SAASA,SAAS,QAAQ,kBAAiB;AAC3C,SAASC,cAAc,QAAQ,gCAA4B;AAE3D;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASC,oBAAoBC,MAAsB;IACxD,MAAMC,SAASJ;IACf,MAAMK,QAAQJ;IACd,MAAMK,UAAUF,0BAAAA,OAAQE,OAAO;IAC/B,MAAMC,OAAOH,0BAAAA,OAAQG,IAAI;IACzB,IAAID,WAAWC,MAAM,OAAO;QAAED;QAASC;IAAK;IAC5C,IAAI,CAACF,SAAS,CAACF,QAAQ,OAAO;IAC9B,MAAMK,YAAYH,MAAMI,aAAa,CAACN;IACtC,OAAOK,YAAY;QAAEF,SAASD,MAAMC,OAAO;QAAEC,MAAMC;IAAU,IAAI;AACnE;AAEA,eAAeN,oBAAmB"}
@@ -34,6 +34,12 @@ export declare const CRM_API_ROUTES: {
34
34
  * every facet write the console makes; see `server/contact-update.ts`.
35
35
  */
36
36
  readonly contactUpdate: "crm/contact-update";
37
+ /**
38
+ * `POST` — lets one or more contacts go from a site, or deletes them once
39
+ * nobody else holds them, keeping every marketing refusal they held
40
+ * (AGL-3338); see `server/contact-remove.ts`.
41
+ */
42
+ readonly contactRemove: "crm/contact-remove";
37
43
  /**
38
44
  * `POST` — unlinks the contacts that name a company, then deletes it
39
45
  * (AGL-2804); see `server/company-delete.ts`.
@@ -64,6 +70,31 @@ export declare const CRM_API_ROUTES: {
64
70
  * `server/inbound-address.ts`.
65
71
  */
66
72
  readonly inboundAddress: "crm/inbound-address";
73
+ /**
74
+ * `POST` (a run) or `GET` (the plan) — the daily digest, posted by the
75
+ * scheduler with the cron secret (AGL-2619); a machine's route, see
76
+ * `server/daily-digest-route.ts`.
77
+ */
78
+ readonly dailyDigest: "crm/daily-digest";
79
+ /**
80
+ * `POST` (a run) or `GET` (the plan) — the hourly task reminders, posted
81
+ * by the scheduler with the cron secret (AGL-2659); a machine's route, see
82
+ * `server/task-reminders-route.ts`.
83
+ */
84
+ readonly taskReminders: "crm/task-reminders";
85
+ /**
86
+ * `POST` — the mail provider's signed notice of a message received at a
87
+ * capture address (AGL-2657); a machine's route, see
88
+ * `server/inbound-route.ts`.
89
+ */
90
+ readonly inbound: "crm/inbound";
91
+ /**
92
+ * `GET` — one of the organization's CRM collections, or a site's leads,
93
+ * as a CSV streamed over every row (AGL-2662); the contacts and leads
94
+ * files are every workspace's (a portability route), see
95
+ * `server/export-route.ts`.
96
+ */
97
+ readonly export: "crm/export";
67
98
  };
68
99
  /**
69
100
  * One site's answer to `crm/recipe-status` (AGL-2639).
@@ -30,6 +30,11 @@
30
30
  * every facet write the console makes; see `server/contact-update.ts`.
31
31
  */ contactUpdate: 'crm/contact-update',
32
32
  /**
33
+ * `POST` — lets one or more contacts go from a site, or deletes them once
34
+ * nobody else holds them, keeping every marketing refusal they held
35
+ * (AGL-3338); see `server/contact-remove.ts`.
36
+ */ contactRemove: 'crm/contact-remove',
37
+ /**
33
38
  * `POST` — unlinks the contacts that name a company, then deletes it
34
39
  * (AGL-2804); see `server/company-delete.ts`.
35
40
  */ companyDelete: 'crm/company-delete',
@@ -52,7 +57,28 @@
52
57
  * `POST` — the workspace's email capture address (AGL-2657), minted on
53
58
  * the first ask and replaced with `rotate: true`; see
54
59
  * `server/inbound-address.ts`.
55
- */ inboundAddress: 'crm/inbound-address'
60
+ */ inboundAddress: 'crm/inbound-address',
61
+ /**
62
+ * `POST` (a run) or `GET` (the plan) — the daily digest, posted by the
63
+ * scheduler with the cron secret (AGL-2619); a machine's route, see
64
+ * `server/daily-digest-route.ts`.
65
+ */ dailyDigest: 'crm/daily-digest',
66
+ /**
67
+ * `POST` (a run) or `GET` (the plan) — the hourly task reminders, posted
68
+ * by the scheduler with the cron secret (AGL-2659); a machine's route, see
69
+ * `server/task-reminders-route.ts`.
70
+ */ taskReminders: 'crm/task-reminders',
71
+ /**
72
+ * `POST` — the mail provider's signed notice of a message received at a
73
+ * capture address (AGL-2657); a machine's route, see
74
+ * `server/inbound-route.ts`.
75
+ */ inbound: 'crm/inbound',
76
+ /**
77
+ * `GET` — one of the organization's CRM collections, or a site's leads,
78
+ * as a CSV streamed over every row (AGL-2662); the contacts and leads
79
+ * files are every workspace's (a portability route), see
80
+ * `server/export-route.ts`.
81
+ */ export: 'crm/export'
56
82
  };
57
83
  /**
58
84
  * What an organization-level activity line may point at: the CRM's record
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/constants/api-routes.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CrmActionRecipeId } from '@aglyn/aglyn'\n\n/**\n * The CRM plugin's console API routes, as the dispatcher keys them.\n *\n * One file both halves import, because the server registers the path and\n * the client fetches it, and a route spelled twice is a route that 404s\n * the day one spelling changes. Client-safe: constants only.\n */\nexport const CRM_API_ROUTES = {\n ping: 'crm/ping',\n /**\n * `POST` — moves one contact to a lifecycle stage, or clears it; see\n * `server.ts`.\n */\n contactStage: 'crm/contact-stage',\n /**\n * `POST` — one holder's profile fields on one or more contacts (AGL-2804):\n * every facet write the console makes; see `server/contact-update.ts`.\n */\n contactUpdate: 'crm/contact-update',\n /**\n * `POST` — unlinks the contacts that name a company, then deletes it\n * (AGL-2804); see `server/company-delete.ts`.\n */\n companyDelete: 'crm/company-delete',\n /** `POST` — one email to one person from a record; see `server/email-send.ts`. */\n emailSend: 'crm/email-send',\n /**\n * `POST` — one line in the ORGANIZATION's activity feed for an act the\n * org-level hub performed client-direct (AGL-2634); see\n * `server/org-activity.ts`.\n */\n orgActivity: 'crm/org-activity',\n /**\n * `POST` — installs one recipe's action on one site (AGL-2639): the\n * server builds it, stamps it and writes it into the site's actions;\n * see `server/recipe-routes.ts`.\n */\n recipeInstall: 'crm/recipe-install',\n /**\n * `POST` — which recipes each of the organization's sites carries\n * (AGL-2639), read off the stamps; see `server/recipe-routes.ts`.\n */\n recipeStatus: 'crm/recipe-status',\n /**\n * `POST` — the workspace's email capture address (AGL-2657), minted on\n * the first ask and replaced with `rotate: true`; see\n * `server/inbound-address.ts`.\n */\n inboundAddress: 'crm/inbound-address',\n} as const\n\n/**\n * One site's answer to `crm/recipe-status` (AGL-2639).\n *\n * `installed` names the recipes a live action on the site is stamped with.\n * `unstamped` counts the live actions that carry NO stamp — every action\n * saved before the stamp existed — and a site with any is one the reader\n * cannot call free of a recipe: the card names it as \"may already have\n * it\" rather than offering the install as if to a blank site.\n */\nexport interface CrmRecipeSiteStatus {\n hostId: string\n installed: CrmActionRecipeId[]\n unstamped: number\n}\n\n/** The body `crm/recipe-install` reads, beside the route scope. */\nexport interface CrmRecipeInstallRequest {\n hostId: string\n orgId?: string\n recipeId: CrmActionRecipeId\n /** The site's form a recipe that `needs: 'form'` is keyed on. */\n formId?: string\n}\n\n/** What a successful `crm/recipe-install` answers with. */\nexport interface CrmRecipeInstallResult {\n ok: true\n actionId: string\n /** The installed action's name, as the site's Actions list will show it. */\n name: string\n recipeId: CrmActionRecipeId\n}\n\n/**\n * What an organization-level activity line may point at: the CRM's record\n * kinds, and nothing the org feed holds for its own reasons (a member, a\n * subscription). The route refuses any other type, so a bulk bar cannot\n * write a line the feed's presenter would render as a workspace event.\n */\nexport const CRM_ORG_ACTIVITY_KINDS = [\n 'contact',\n 'company',\n 'deal',\n 'lead',\n 'task',\n] as const\n\nexport type CrmOrgActivityKind = (typeof CRM_ORG_ACTIVITY_KINDS)[number]\n\n/** The most an activity line may say — a sentence, not a report. */\nexport const CRM_ORG_ACTIVITY_ACTION_MAX = 160\n\n/** The browser-side URL for a route key. */\nexport function crmApiUrl(route: keyof typeof CRM_API_ROUTES): string {\n return `/api/${CRM_API_ROUTES[route]}`\n}\n"],"names":["CRM_API_ROUTES","ping","contactStage","contactUpdate","companyDelete","emailSend","orgActivity","recipeInstall","recipeStatus","inboundAddress","CRM_ORG_ACTIVITY_KINDS","CRM_ORG_ACTIVITY_ACTION_MAX","crmApiUrl","route"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAID;;;;;;CAMC,GACD,OAAO,MAAMA,iBAAiB;IAC5BC,MAAM;IACN;;;GAGC,GACDC,cAAc;IACd;;;GAGC,GACDC,eAAe;IACf;;;GAGC,GACDC,eAAe;IACf,gFAAgF,GAChFC,WAAW;IACX;;;;GAIC,GACDC,aAAa;IACb;;;;GAIC,GACDC,eAAe;IACf;;;GAGC,GACDC,cAAc;IACd;;;;GAIC,GACDC,gBAAgB;AAClB,EAAU;AAmCV;;;;;CAKC,GACD,OAAO,MAAMC,yBAAyB;IACpC;IACA;IACA;IACA;IACA;CACD,CAAS;AAIV,kEAAkE,GAClE,OAAO,MAAMC,8BAA8B,IAAG;AAE9C,0CAA0C,GAC1C,OAAO,SAASC,UAAUC,KAAkC;IAC1D,OAAO,CAAC,KAAK,EAAEb,cAAc,CAACa,MAAM,EAAE;AACxC"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/constants/api-routes.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CrmActionRecipeId } from '@aglyn/aglyn'\n\n/**\n * The CRM plugin's console API routes, as the dispatcher keys them.\n *\n * One file both halves import, because the server registers the path and\n * the client fetches it, and a route spelled twice is a route that 404s\n * the day one spelling changes. Client-safe: constants only.\n */\nexport const CRM_API_ROUTES = {\n ping: 'crm/ping',\n /**\n * `POST` — moves one contact to a lifecycle stage, or clears it; see\n * `server.ts`.\n */\n contactStage: 'crm/contact-stage',\n /**\n * `POST` — one holder's profile fields on one or more contacts (AGL-2804):\n * every facet write the console makes; see `server/contact-update.ts`.\n */\n contactUpdate: 'crm/contact-update',\n /**\n * `POST` — lets one or more contacts go from a site, or deletes them once\n * nobody else holds them, keeping every marketing refusal they held\n * (AGL-3338); see `server/contact-remove.ts`.\n */\n contactRemove: 'crm/contact-remove',\n /**\n * `POST` — unlinks the contacts that name a company, then deletes it\n * (AGL-2804); see `server/company-delete.ts`.\n */\n companyDelete: 'crm/company-delete',\n /** `POST` — one email to one person from a record; see `server/email-send.ts`. */\n emailSend: 'crm/email-send',\n /**\n * `POST` — one line in the ORGANIZATION's activity feed for an act the\n * org-level hub performed client-direct (AGL-2634); see\n * `server/org-activity.ts`.\n */\n orgActivity: 'crm/org-activity',\n /**\n * `POST` — installs one recipe's action on one site (AGL-2639): the\n * server builds it, stamps it and writes it into the site's actions;\n * see `server/recipe-routes.ts`.\n */\n recipeInstall: 'crm/recipe-install',\n /**\n * `POST` — which recipes each of the organization's sites carries\n * (AGL-2639), read off the stamps; see `server/recipe-routes.ts`.\n */\n recipeStatus: 'crm/recipe-status',\n /**\n * `POST` — the workspace's email capture address (AGL-2657), minted on\n * the first ask and replaced with `rotate: true`; see\n * `server/inbound-address.ts`.\n */\n inboundAddress: 'crm/inbound-address',\n /**\n * `POST` (a run) or `GET` (the plan) — the daily digest, posted by the\n * scheduler with the cron secret (AGL-2619); a machine's route, see\n * `server/daily-digest-route.ts`.\n */\n dailyDigest: 'crm/daily-digest',\n /**\n * `POST` (a run) or `GET` (the plan) — the hourly task reminders, posted\n * by the scheduler with the cron secret (AGL-2659); a machine's route, see\n * `server/task-reminders-route.ts`.\n */\n taskReminders: 'crm/task-reminders',\n /**\n * `POST` — the mail provider's signed notice of a message received at a\n * capture address (AGL-2657); a machine's route, see\n * `server/inbound-route.ts`.\n */\n inbound: 'crm/inbound',\n /**\n * `GET` — one of the organization's CRM collections, or a site's leads,\n * as a CSV streamed over every row (AGL-2662); the contacts and leads\n * files are every workspace's (a portability route), see\n * `server/export-route.ts`.\n */\n export: 'crm/export',\n} as const\n\n/**\n * One site's answer to `crm/recipe-status` (AGL-2639).\n *\n * `installed` names the recipes a live action on the site is stamped with.\n * `unstamped` counts the live actions that carry NO stamp — every action\n * saved before the stamp existed — and a site with any is one the reader\n * cannot call free of a recipe: the card names it as \"may already have\n * it\" rather than offering the install as if to a blank site.\n */\nexport interface CrmRecipeSiteStatus {\n hostId: string\n installed: CrmActionRecipeId[]\n unstamped: number\n}\n\n/** The body `crm/recipe-install` reads, beside the route scope. */\nexport interface CrmRecipeInstallRequest {\n hostId: string\n orgId?: string\n recipeId: CrmActionRecipeId\n /** The site's form a recipe that `needs: 'form'` is keyed on. */\n formId?: string\n}\n\n/** What a successful `crm/recipe-install` answers with. */\nexport interface CrmRecipeInstallResult {\n ok: true\n actionId: string\n /** The installed action's name, as the site's Actions list will show it. */\n name: string\n recipeId: CrmActionRecipeId\n}\n\n/**\n * What an organization-level activity line may point at: the CRM's record\n * kinds, and nothing the org feed holds for its own reasons (a member, a\n * subscription). The route refuses any other type, so a bulk bar cannot\n * write a line the feed's presenter would render as a workspace event.\n */\nexport const CRM_ORG_ACTIVITY_KINDS = [\n 'contact',\n 'company',\n 'deal',\n 'lead',\n 'task',\n] as const\n\nexport type CrmOrgActivityKind = (typeof CRM_ORG_ACTIVITY_KINDS)[number]\n\n/** The most an activity line may say — a sentence, not a report. */\nexport const CRM_ORG_ACTIVITY_ACTION_MAX = 160\n\n/** The browser-side URL for a route key. */\nexport function crmApiUrl(route: keyof typeof CRM_API_ROUTES): string {\n return `/api/${CRM_API_ROUTES[route]}`\n}\n"],"names":["CRM_API_ROUTES","ping","contactStage","contactUpdate","contactRemove","companyDelete","emailSend","orgActivity","recipeInstall","recipeStatus","inboundAddress","dailyDigest","taskReminders","inbound","export","CRM_ORG_ACTIVITY_KINDS","CRM_ORG_ACTIVITY_ACTION_MAX","crmApiUrl","route"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAID;;;;;;CAMC,GACD,OAAO,MAAMA,iBAAiB;IAC5BC,MAAM;IACN;;;GAGC,GACDC,cAAc;IACd;;;GAGC,GACDC,eAAe;IACf;;;;GAIC,GACDC,eAAe;IACf;;;GAGC,GACDC,eAAe;IACf,gFAAgF,GAChFC,WAAW;IACX;;;;GAIC,GACDC,aAAa;IACb;;;;GAIC,GACDC,eAAe;IACf;;;GAGC,GACDC,cAAc;IACd;;;;GAIC,GACDC,gBAAgB;IAChB;;;;GAIC,GACDC,aAAa;IACb;;;;GAIC,GACDC,eAAe;IACf;;;;GAIC,GACDC,SAAS;IACT;;;;;GAKC,GACDC,QAAQ;AACV,EAAU;AAmCV;;;;;CAKC,GACD,OAAO,MAAMC,yBAAyB;IACpC;IACA;IACA;IACA;IACA;CACD,CAAS;AAIV,kEAAkE,GAClE,OAAO,MAAMC,8BAA8B,IAAG;AAE9C,0CAA0C,GAC1C,OAAO,SAASC,UAAUC,KAAkC;IAC1D,OAAO,CAAC,KAAK,EAAElB,cAAc,CAACkB,MAAM,EAAE;AACxC"}
@@ -12,3 +12,5 @@
12
12
  * (AGL-2614), so `contacts` now reads as an unknown id like any other.
13
13
  */
14
14
  export declare const BUNDLE_ID = "crm";
15
+ /** The records band's meter in the monthly usage sweep (`server/crm-records-meter.ts`). */
16
+ export declare const CRM_RECORDS_METER_ID = "records";
@@ -10,5 +10,6 @@
10
10
  * the old value was retired once that backfill reported nothing left
11
11
  * (AGL-2614), so `contacts` now reads as an unknown id like any other.
12
12
  */ export const BUNDLE_ID = 'crm';
13
+ /** The records band's meter in the monthly usage sweep (`server/crm-records-meter.ts`). */ export const CRM_RECORDS_METER_ID = 'records';
13
14
 
14
15
  //# sourceMappingURL=bundle-common.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/constants/bundle-common.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 */\n\n/**\n * The persisted plugin id (AGL-2595). It was `contacts` while the surface was\n * one list; the stored lists were rewritten and the plugin manager's alias for\n * the old value was retired once that backfill reported nothing left\n * (AGL-2614), so `contacts` now reads as an unknown id like any other.\n */\nexport const BUNDLE_ID = 'crm'\n"],"names":["BUNDLE_ID"],"mappings":"AAAA;;;;;;CAMC,GAED;;;;;CAKC,GACD,OAAO,MAAMA,YAAY,MAAK"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/constants/bundle-common.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 */\n\n/**\n * The persisted plugin id (AGL-2595). It was `contacts` while the surface was\n * one list; the stored lists were rewritten and the plugin manager's alias for\n * the old value was retired once that backfill reported nothing left\n * (AGL-2614), so `contacts` now reads as an unknown id like any other.\n */\nexport const BUNDLE_ID = 'crm'\n\n/** The records band's meter in the monthly usage sweep (`server/crm-records-meter.ts`). */\nexport const CRM_RECORDS_METER_ID = 'records'\n"],"names":["BUNDLE_ID","CRM_RECORDS_METER_ID"],"mappings":"AAAA;;;;;;CAMC,GAED;;;;;CAKC,GACD,OAAO,MAAMA,YAAY,MAAK;AAE9B,yFAAyF,GACzF,OAAO,MAAMC,uBAAuB,UAAS"}