@aglyn/aglyn 1.0.0-beta.143

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 (963) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +11 -0
  3. package/package.json +66 -0
  4. package/src/index.d.ts +25 -0
  5. package/src/index.js +26 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/aglyn.d.ts +31 -0
  8. package/src/lib/aglyn.js +114 -0
  9. package/src/lib/aglyn.js.map +1 -0
  10. package/src/lib/app-utils/abuse-report.d.ts +193 -0
  11. package/src/lib/app-utils/abuse-report.js +321 -0
  12. package/src/lib/app-utils/abuse-report.js.map +1 -0
  13. package/src/lib/app-utils/accept-negotiation.d.ts +129 -0
  14. package/src/lib/app-utils/accept-negotiation.js +266 -0
  15. package/src/lib/app-utils/accept-negotiation.js.map +1 -0
  16. package/src/lib/app-utils/account-emails.d.ts +263 -0
  17. package/src/lib/app-utils/account-emails.js +264 -0
  18. package/src/lib/app-utils/account-emails.js.map +1 -0
  19. package/src/lib/app-utils/actions.d.ts +717 -0
  20. package/src/lib/app-utils/actions.js +1031 -0
  21. package/src/lib/app-utils/actions.js.map +1 -0
  22. package/src/lib/app-utils/activity-presenter.d.ts +152 -0
  23. package/src/lib/app-utils/activity-presenter.js +326 -0
  24. package/src/lib/app-utils/activity-presenter.js.map +1 -0
  25. package/src/lib/app-utils/advertising-tag-mounts.d.ts +133 -0
  26. package/src/lib/app-utils/advertising-tag-mounts.js +118 -0
  27. package/src/lib/app-utils/advertising-tag-mounts.js.map +1 -0
  28. package/src/lib/app-utils/advertising-tags.d.ts +307 -0
  29. package/src/lib/app-utils/advertising-tags.js +525 -0
  30. package/src/lib/app-utils/advertising-tags.js.map +1 -0
  31. package/src/lib/app-utils/agent-api-catalog.d.ts +94 -0
  32. package/src/lib/app-utils/agent-api-catalog.js +106 -0
  33. package/src/lib/app-utils/agent-api-catalog.js.map +1 -0
  34. package/src/lib/app-utils/agent-openapi.d.ts +103 -0
  35. package/src/lib/app-utils/agent-openapi.js +1128 -0
  36. package/src/lib/app-utils/agent-openapi.js.map +1 -0
  37. package/src/lib/app-utils/analytics-beacon.d.ts +154 -0
  38. package/src/lib/app-utils/analytics-beacon.js +152 -0
  39. package/src/lib/app-utils/analytics-beacon.js.map +1 -0
  40. package/src/lib/app-utils/analytics-environment.d.ts +133 -0
  41. package/src/lib/app-utils/analytics-environment.js +152 -0
  42. package/src/lib/app-utils/analytics-environment.js.map +1 -0
  43. package/src/lib/app-utils/analytics-events.d.ts +744 -0
  44. package/src/lib/app-utils/analytics-events.js +650 -0
  45. package/src/lib/app-utils/analytics-events.js.map +1 -0
  46. package/src/lib/app-utils/analytics-link-clicks.d.ts +102 -0
  47. package/src/lib/app-utils/analytics-link-clicks.js +267 -0
  48. package/src/lib/app-utils/analytics-link-clicks.js.map +1 -0
  49. package/src/lib/app-utils/analytics-path-key.d.ts +46 -0
  50. package/src/lib/app-utils/analytics-path-key.js +46 -0
  51. package/src/lib/app-utils/analytics-path-key.js.map +1 -0
  52. package/src/lib/app-utils/api-adapter.d.ts +47 -0
  53. package/src/lib/app-utils/api-adapter.js +367 -0
  54. package/src/lib/app-utils/api-adapter.js.map +1 -0
  55. package/src/lib/app-utils/api-idempotency.d.ts +169 -0
  56. package/src/lib/app-utils/api-idempotency.js +213 -0
  57. package/src/lib/app-utils/api-idempotency.js.map +1 -0
  58. package/src/lib/app-utils/api-plugins.d.ts +210 -0
  59. package/src/lib/app-utils/api-plugins.js +221 -0
  60. package/src/lib/app-utils/api-plugins.js.map +1 -0
  61. package/src/lib/app-utils/assist-credits.d.ts +482 -0
  62. package/src/lib/app-utils/assist-credits.js +509 -0
  63. package/src/lib/app-utils/assist-credits.js.map +1 -0
  64. package/src/lib/app-utils/attribution-attribute.d.ts +34 -0
  65. package/src/lib/app-utils/attribution-attribute.js +34 -0
  66. package/src/lib/app-utils/attribution-attribute.js.map +1 -0
  67. package/src/lib/app-utils/attribution-guard.d.ts +130 -0
  68. package/src/lib/app-utils/attribution-guard.js +410 -0
  69. package/src/lib/app-utils/attribution-guard.js.map +1 -0
  70. package/src/lib/app-utils/author-css.d.ts +123 -0
  71. package/src/lib/app-utils/author-css.js +275 -0
  72. package/src/lib/app-utils/author-css.js.map +1 -0
  73. package/src/lib/app-utils/author-html-markdown.d.ts +31 -0
  74. package/src/lib/app-utils/author-html-markdown.js +497 -0
  75. package/src/lib/app-utils/author-html-markdown.js.map +1 -0
  76. package/src/lib/app-utils/author-html.d.ts +135 -0
  77. package/src/lib/app-utils/author-html.js +1037 -0
  78. package/src/lib/app-utils/author-html.js.map +1 -0
  79. package/src/lib/app-utils/automation-placeholders.d.ts +72 -0
  80. package/src/lib/app-utils/automation-placeholders.js +207 -0
  81. package/src/lib/app-utils/automation-placeholders.js.map +1 -0
  82. package/src/lib/app-utils/bandwidth-cap.d.ts +183 -0
  83. package/src/lib/app-utils/bandwidth-cap.js +193 -0
  84. package/src/lib/app-utils/bandwidth-cap.js.map +1 -0
  85. package/src/lib/app-utils/binding-token-catalog.d.ts +82 -0
  86. package/src/lib/app-utils/binding-token-catalog.js +293 -0
  87. package/src/lib/app-utils/binding-token-catalog.js.map +1 -0
  88. package/src/lib/app-utils/binding-tokens.d.ts +157 -0
  89. package/src/lib/app-utils/binding-tokens.js +251 -0
  90. package/src/lib/app-utils/binding-tokens.js.map +1 -0
  91. package/src/lib/app-utils/breadcrumb-json-ld.d.ts +57 -0
  92. package/src/lib/app-utils/breadcrumb-json-ld.js +67 -0
  93. package/src/lib/app-utils/breadcrumb-json-ld.js.map +1 -0
  94. package/src/lib/app-utils/campaign-attribution.d.ts +117 -0
  95. package/src/lib/app-utils/campaign-attribution.js +162 -0
  96. package/src/lib/app-utils/campaign-attribution.js.map +1 -0
  97. package/src/lib/app-utils/campaign-forwarding.d.ts +220 -0
  98. package/src/lib/app-utils/campaign-forwarding.js +332 -0
  99. package/src/lib/app-utils/campaign-forwarding.js.map +1 -0
  100. package/src/lib/app-utils/campaign-membership.d.ts +109 -0
  101. package/src/lib/app-utils/campaign-membership.js +176 -0
  102. package/src/lib/app-utils/campaign-membership.js.map +1 -0
  103. package/src/lib/app-utils/campaign-touch.d.ts +206 -0
  104. package/src/lib/app-utils/campaign-touch.js +326 -0
  105. package/src/lib/app-utils/campaign-touch.js.map +1 -0
  106. package/src/lib/app-utils/child-contract-compose.d.ts +28 -0
  107. package/src/lib/app-utils/child-contract-compose.js +140 -0
  108. package/src/lib/app-utils/child-contract-compose.js.map +1 -0
  109. package/src/lib/app-utils/child-contract.d.ts +129 -0
  110. package/src/lib/app-utils/child-contract.js +153 -0
  111. package/src/lib/app-utils/child-contract.js.map +1 -0
  112. package/src/lib/app-utils/collection-delete.d.ts +113 -0
  113. package/src/lib/app-utils/collection-delete.js +120 -0
  114. package/src/lib/app-utils/collection-delete.js.map +1 -0
  115. package/src/lib/app-utils/collection-entries.d.ts +833 -0
  116. package/src/lib/app-utils/collection-entries.js +1285 -0
  117. package/src/lib/app-utils/collection-entries.js.map +1 -0
  118. package/src/lib/app-utils/collection-entry-date.d.ts +129 -0
  119. package/src/lib/app-utils/collection-entry-date.js +183 -0
  120. package/src/lib/app-utils/collection-entry-date.js.map +1 -0
  121. package/src/lib/app-utils/collection-kind.d.ts +55 -0
  122. package/src/lib/app-utils/collection-kind.js +69 -0
  123. package/src/lib/app-utils/collection-kind.js.map +1 -0
  124. package/src/lib/app-utils/collection-slug.d.ts +79 -0
  125. package/src/lib/app-utils/collection-slug.js +70 -0
  126. package/src/lib/app-utils/collection-slug.js.map +1 -0
  127. package/src/lib/app-utils/compose-layout-nodes.d.ts +147 -0
  128. package/src/lib/app-utils/compose-layout-nodes.js +261 -0
  129. package/src/lib/app-utils/compose-layout-nodes.js.map +1 -0
  130. package/src/lib/app-utils/compose-layout-props.d.ts +71 -0
  131. package/src/lib/app-utils/compose-layout-props.js +61 -0
  132. package/src/lib/app-utils/compose-layout-props.js.map +1 -0
  133. package/src/lib/app-utils/compose-reusable-components.d.ts +504 -0
  134. package/src/lib/app-utils/compose-reusable-components.js +1366 -0
  135. package/src/lib/app-utils/compose-reusable-components.js.map +1 -0
  136. package/src/lib/app-utils/compress.d.ts +35 -0
  137. package/src/lib/app-utils/compress.js +38 -0
  138. package/src/lib/app-utils/compress.js.map +1 -0
  139. package/src/lib/app-utils/consent-banner-ui.d.ts +226 -0
  140. package/src/lib/app-utils/consent-banner-ui.js +583 -0
  141. package/src/lib/app-utils/consent-banner-ui.js.map +1 -0
  142. package/src/lib/app-utils/consent-groups.d.ts +189 -0
  143. package/src/lib/app-utils/consent-groups.js +219 -0
  144. package/src/lib/app-utils/consent-groups.js.map +1 -0
  145. package/src/lib/app-utils/consent-preferences-dialog.d.ts +58 -0
  146. package/src/lib/app-utils/consent-preferences-dialog.js +106 -0
  147. package/src/lib/app-utils/consent-preferences-dialog.js.map +1 -0
  148. package/src/lib/app-utils/console-record-links.d.ts +163 -0
  149. package/src/lib/app-utils/console-record-links.js +178 -0
  150. package/src/lib/app-utils/console-record-links.js.map +1 -0
  151. package/src/lib/app-utils/console-routes.d.ts +658 -0
  152. package/src/lib/app-utils/console-routes.js +489 -0
  153. package/src/lib/app-utils/console-routes.js.map +1 -0
  154. package/src/lib/app-utils/console-widget-slot-context.d.ts +46 -0
  155. package/src/lib/app-utils/console-widget-slot-context.js +23 -0
  156. package/src/lib/app-utils/console-widget-slot-context.js.map +1 -0
  157. package/src/lib/app-utils/contact-custom-fields.d.ts +191 -0
  158. package/src/lib/app-utils/contact-custom-fields.js +349 -0
  159. package/src/lib/app-utils/contact-custom-fields.js.map +1 -0
  160. package/src/lib/app-utils/contact-holder.d.ts +52 -0
  161. package/src/lib/app-utils/contact-holder.js +98 -0
  162. package/src/lib/app-utils/contact-holder.js.map +1 -0
  163. package/src/lib/app-utils/contact-merge.d.ts +136 -0
  164. package/src/lib/app-utils/contact-merge.js +379 -0
  165. package/src/lib/app-utils/contact-merge.js.map +1 -0
  166. package/src/lib/app-utils/contacts.d.ts +554 -0
  167. package/src/lib/app-utils/contacts.js +401 -0
  168. package/src/lib/app-utils/contacts.js.map +1 -0
  169. package/src/lib/app-utils/content-author-profile.d.ts +68 -0
  170. package/src/lib/app-utils/content-author-profile.js +118 -0
  171. package/src/lib/app-utils/content-author-profile.js.map +1 -0
  172. package/src/lib/app-utils/content-authors.d.ts +662 -0
  173. package/src/lib/app-utils/content-authors.js +771 -0
  174. package/src/lib/app-utils/content-authors.js.map +1 -0
  175. package/src/lib/app-utils/content-schema-type.d.ts +81 -0
  176. package/src/lib/app-utils/content-schema-type.js +87 -0
  177. package/src/lib/app-utils/content-schema-type.js.map +1 -0
  178. package/src/lib/app-utils/contexts.d.ts +35 -0
  179. package/src/lib/app-utils/contexts.js +35 -0
  180. package/src/lib/app-utils/contexts.js.map +1 -0
  181. package/src/lib/app-utils/create-resource-uid.d.ts +18 -0
  182. package/src/lib/app-utils/create-resource-uid.js +23 -0
  183. package/src/lib/app-utils/create-resource-uid.js.map +1 -0
  184. package/src/lib/app-utils/crm-booking.d.ts +75 -0
  185. package/src/lib/app-utils/crm-booking.js +133 -0
  186. package/src/lib/app-utils/crm-booking.js.map +1 -0
  187. package/src/lib/app-utils/crm-csv.d.ts +232 -0
  188. package/src/lib/app-utils/crm-csv.js +432 -0
  189. package/src/lib/app-utils/crm-csv.js.map +1 -0
  190. package/src/lib/app-utils/crm-digest.d.ts +179 -0
  191. package/src/lib/app-utils/crm-digest.js +271 -0
  192. package/src/lib/app-utils/crm-digest.js.map +1 -0
  193. package/src/lib/app-utils/crm-email-templates.d.ts +172 -0
  194. package/src/lib/app-utils/crm-email-templates.js +382 -0
  195. package/src/lib/app-utils/crm-email-templates.js.map +1 -0
  196. package/src/lib/app-utils/crm-inbound.d.ts +245 -0
  197. package/src/lib/app-utils/crm-inbound.js +407 -0
  198. package/src/lib/app-utils/crm-inbound.js.map +1 -0
  199. package/src/lib/app-utils/crm-kinds.d.ts +73 -0
  200. package/src/lib/app-utils/crm-kinds.js +92 -0
  201. package/src/lib/app-utils/crm-kinds.js.map +1 -0
  202. package/src/lib/app-utils/crm-next-activity.d.ts +107 -0
  203. package/src/lib/app-utils/crm-next-activity.js +140 -0
  204. package/src/lib/app-utils/crm-next-activity.js.map +1 -0
  205. package/src/lib/app-utils/crm-reports.d.ts +479 -0
  206. package/src/lib/app-utils/crm-reports.js +680 -0
  207. package/src/lib/app-utils/crm-reports.js.map +1 -0
  208. package/src/lib/app-utils/crm-task-reminders.d.ts +129 -0
  209. package/src/lib/app-utils/crm-task-reminders.js +139 -0
  210. package/src/lib/app-utils/crm-task-reminders.js.map +1 -0
  211. package/src/lib/app-utils/crm.d.ts +1546 -0
  212. package/src/lib/app-utils/crm.js +1814 -0
  213. package/src/lib/app-utils/crm.js.map +1 -0
  214. package/src/lib/app-utils/csp-report.d.ts +84 -0
  215. package/src/lib/app-utils/csp-report.js +177 -0
  216. package/src/lib/app-utils/csp-report.js.map +1 -0
  217. package/src/lib/app-utils/csv-import.d.ts +192 -0
  218. package/src/lib/app-utils/csv-import.js +279 -0
  219. package/src/lib/app-utils/csv-import.js.map +1 -0
  220. package/src/lib/app-utils/dataset-csv.d.ts +109 -0
  221. package/src/lib/app-utils/dataset-csv.js +235 -0
  222. package/src/lib/app-utils/dataset-csv.js.map +1 -0
  223. package/src/lib/app-utils/dataset-models.d.ts +194 -0
  224. package/src/lib/app-utils/dataset-models.js +409 -0
  225. package/src/lib/app-utils/dataset-models.js.map +1 -0
  226. package/src/lib/app-utils/dataset-query.d.ts +57 -0
  227. package/src/lib/app-utils/dataset-query.js +126 -0
  228. package/src/lib/app-utils/dataset-query.js.map +1 -0
  229. package/src/lib/app-utils/datasets.d.ts +136 -0
  230. package/src/lib/app-utils/datasets.js +177 -0
  231. package/src/lib/app-utils/datasets.js.map +1 -0
  232. package/src/lib/app-utils/decompress.d.ts +36 -0
  233. package/src/lib/app-utils/decompress.js +32 -0
  234. package/src/lib/app-utils/decompress.js.map +1 -0
  235. package/src/lib/app-utils/dedicated-sending-domain.d.ts +47 -0
  236. package/src/lib/app-utils/dedicated-sending-domain.js +114 -0
  237. package/src/lib/app-utils/dedicated-sending-domain.js.map +1 -0
  238. package/src/lib/app-utils/deferred-image.d.ts +86 -0
  239. package/src/lib/app-utils/deferred-image.js +83 -0
  240. package/src/lib/app-utils/deferred-image.js.map +1 -0
  241. package/src/lib/app-utils/definition-canvas-tree.d.ts +61 -0
  242. package/src/lib/app-utils/definition-canvas-tree.js +126 -0
  243. package/src/lib/app-utils/definition-canvas-tree.js.map +1 -0
  244. package/src/lib/app-utils/deployment-shape.d.ts +167 -0
  245. package/src/lib/app-utils/deployment-shape.js +238 -0
  246. package/src/lib/app-utils/deployment-shape.js.map +1 -0
  247. package/src/lib/app-utils/detect-template-placeholders.d.ts +30 -0
  248. package/src/lib/app-utils/detect-template-placeholders.js +53 -0
  249. package/src/lib/app-utils/detect-template-placeholders.js.map +1 -0
  250. package/src/lib/app-utils/dmca-counter-notice.d.ts +185 -0
  251. package/src/lib/app-utils/dmca-counter-notice.js +277 -0
  252. package/src/lib/app-utils/dmca-counter-notice.js.map +1 -0
  253. package/src/lib/app-utils/docs-deflection.d.ts +156 -0
  254. package/src/lib/app-utils/docs-deflection.js +547 -0
  255. package/src/lib/app-utils/docs-deflection.js.map +1 -0
  256. package/src/lib/app-utils/docs-help.d.ts +57 -0
  257. package/src/lib/app-utils/docs-help.generated.d.ts +303 -0
  258. package/src/lib/app-utils/docs-help.generated.js +867 -0
  259. package/src/lib/app-utils/docs-help.generated.js.map +1 -0
  260. package/src/lib/app-utils/docs-help.js +46 -0
  261. package/src/lib/app-utils/docs-help.js.map +1 -0
  262. package/src/lib/app-utils/docs-index.generated.d.ts +29 -0
  263. package/src/lib/app-utils/docs-index.generated.js +8388 -0
  264. package/src/lib/app-utils/docs-index.generated.js.map +1 -0
  265. package/src/lib/app-utils/docs-retrieval.d.ts +67 -0
  266. package/src/lib/app-utils/docs-retrieval.js +188 -0
  267. package/src/lib/app-utils/docs-retrieval.js.map +1 -0
  268. package/src/lib/app-utils/document-landmark.d.ts +50 -0
  269. package/src/lib/app-utils/document-landmark.js +100 -0
  270. package/src/lib/app-utils/document-landmark.js.map +1 -0
  271. package/src/lib/app-utils/duplicate-resource.d.ts +101 -0
  272. package/src/lib/app-utils/duplicate-resource.js +206 -0
  273. package/src/lib/app-utils/duplicate-resource.js.map +1 -0
  274. package/src/lib/app-utils/dynamic-list-rule.d.ts +471 -0
  275. package/src/lib/app-utils/dynamic-list-rule.js +914 -0
  276. package/src/lib/app-utils/dynamic-list-rule.js.map +1 -0
  277. package/src/lib/app-utils/element-animation.d.ts +200 -0
  278. package/src/lib/app-utils/element-animation.js +233 -0
  279. package/src/lib/app-utils/element-animation.js.map +1 -0
  280. package/src/lib/app-utils/element-hidden-style.d.ts +46 -0
  281. package/src/lib/app-utils/element-hidden-style.js +48 -0
  282. package/src/lib/app-utils/element-hidden-style.js.map +1 -0
  283. package/src/lib/app-utils/element-ui.d.ts +243 -0
  284. package/src/lib/app-utils/element-ui.js +459 -0
  285. package/src/lib/app-utils/element-ui.js.map +1 -0
  286. package/src/lib/app-utils/email-starter-policy.d.ts +160 -0
  287. package/src/lib/app-utils/email-starter-policy.js +327 -0
  288. package/src/lib/app-utils/email-starter-policy.js.map +1 -0
  289. package/src/lib/app-utils/email-topics.d.ts +310 -0
  290. package/src/lib/app-utils/email-topics.js +336 -0
  291. package/src/lib/app-utils/email-topics.js.map +1 -0
  292. package/src/lib/app-utils/enabled-plugins-context.d.ts +100 -0
  293. package/src/lib/app-utils/enabled-plugins-context.js +113 -0
  294. package/src/lib/app-utils/enabled-plugins-context.js.map +1 -0
  295. package/src/lib/app-utils/ensure-canvas-root.d.ts +38 -0
  296. package/src/lib/app-utils/ensure-canvas-root.js +61 -0
  297. package/src/lib/app-utils/ensure-canvas-root.js.map +1 -0
  298. package/src/lib/app-utils/entity-picker-context.d.ts +199 -0
  299. package/src/lib/app-utils/entity-picker-context.js +93 -0
  300. package/src/lib/app-utils/entity-picker-context.js.map +1 -0
  301. package/src/lib/app-utils/error-beacon.d.ts +107 -0
  302. package/src/lib/app-utils/error-beacon.js +296 -0
  303. package/src/lib/app-utils/error-beacon.js.map +1 -0
  304. package/src/lib/app-utils/expand-repeatables.d.ts +172 -0
  305. package/src/lib/app-utils/expand-repeatables.js +299 -0
  306. package/src/lib/app-utils/expand-repeatables.js.map +1 -0
  307. package/src/lib/app-utils/foreign-script.d.ts +82 -0
  308. package/src/lib/app-utils/foreign-script.js +102 -0
  309. package/src/lib/app-utils/foreign-script.js.map +1 -0
  310. package/src/lib/app-utils/form-abuse-ceiling.d.ts +146 -0
  311. package/src/lib/app-utils/form-abuse-ceiling.js +158 -0
  312. package/src/lib/app-utils/form-abuse-ceiling.js.map +1 -0
  313. package/src/lib/app-utils/form-contract.d.ts +198 -0
  314. package/src/lib/app-utils/form-contract.js +282 -0
  315. package/src/lib/app-utils/form-contract.js.map +1 -0
  316. package/src/lib/app-utils/form-dataset-binding.d.ts +50 -0
  317. package/src/lib/app-utils/form-dataset-binding.js +74 -0
  318. package/src/lib/app-utils/form-dataset-binding.js.map +1 -0
  319. package/src/lib/app-utils/forms.d.ts +727 -0
  320. package/src/lib/app-utils/forms.js +777 -0
  321. package/src/lib/app-utils/forms.js.map +1 -0
  322. package/src/lib/app-utils/functions.d.ts +188 -0
  323. package/src/lib/app-utils/functions.js +529 -0
  324. package/src/lib/app-utils/functions.js.map +1 -0
  325. package/src/lib/app-utils/guarded-version-save.d.ts +91 -0
  326. package/src/lib/app-utils/guarded-version-save.js +131 -0
  327. package/src/lib/app-utils/guarded-version-save.js.map +1 -0
  328. package/src/lib/app-utils/health-report.d.ts +1766 -0
  329. package/src/lib/app-utils/health-report.js +2072 -0
  330. package/src/lib/app-utils/health-report.js.map +1 -0
  331. package/src/lib/app-utils/host-naming.d.ts +135 -0
  332. package/src/lib/app-utils/host-naming.js +188 -0
  333. package/src/lib/app-utils/host-naming.js.map +1 -0
  334. package/src/lib/app-utils/host-permissions.d.ts +76 -0
  335. package/src/lib/app-utils/host-permissions.js +119 -0
  336. package/src/lib/app-utils/host-permissions.js.map +1 -0
  337. package/src/lib/app-utils/host-tokens.d.ts +228 -0
  338. package/src/lib/app-utils/host-tokens.js +304 -0
  339. package/src/lib/app-utils/host-tokens.js.map +1 -0
  340. package/src/lib/app-utils/idp-profile.d.ts +83 -0
  341. package/src/lib/app-utils/idp-profile.js +268 -0
  342. package/src/lib/app-utils/idp-profile.js.map +1 -0
  343. package/src/lib/app-utils/image-upload-types.d.ts +49 -0
  344. package/src/lib/app-utils/image-upload-types.js +86 -0
  345. package/src/lib/app-utils/image-upload-types.js.map +1 -0
  346. package/src/lib/app-utils/index.d.ts +18 -0
  347. package/src/lib/app-utils/index.js +23 -0
  348. package/src/lib/app-utils/index.js.map +1 -0
  349. package/src/lib/app-utils/internal-traffic.d.ts +197 -0
  350. package/src/lib/app-utils/internal-traffic.js +288 -0
  351. package/src/lib/app-utils/internal-traffic.js.map +1 -0
  352. package/src/lib/app-utils/lineal-order.d.ts +62 -0
  353. package/src/lib/app-utils/lineal-order.js +65 -0
  354. package/src/lib/app-utils/lineal-order.js.map +1 -0
  355. package/src/lib/app-utils/link-references.d.ts +36 -0
  356. package/src/lib/app-utils/link-references.js +89 -0
  357. package/src/lib/app-utils/link-references.js.map +1 -0
  358. package/src/lib/app-utils/link-target-search-context.d.ts +123 -0
  359. package/src/lib/app-utils/link-target-search-context.js +221 -0
  360. package/src/lib/app-utils/link-target-search-context.js.map +1 -0
  361. package/src/lib/app-utils/list-assignment-policy.d.ts +169 -0
  362. package/src/lib/app-utils/list-assignment-policy.js +170 -0
  363. package/src/lib/app-utils/list-assignment-policy.js.map +1 -0
  364. package/src/lib/app-utils/list-import.d.ts +158 -0
  365. package/src/lib/app-utils/list-import.js +332 -0
  366. package/src/lib/app-utils/list-import.js.map +1 -0
  367. package/src/lib/app-utils/llms-txt.d.ts +104 -0
  368. package/src/lib/app-utils/llms-txt.js +144 -0
  369. package/src/lib/app-utils/llms-txt.js.map +1 -0
  370. package/src/lib/app-utils/local-storage-budget.d.ts +75 -0
  371. package/src/lib/app-utils/local-storage-budget.js +153 -0
  372. package/src/lib/app-utils/local-storage-budget.js.map +1 -0
  373. package/src/lib/app-utils/lockdown.d.ts +698 -0
  374. package/src/lib/app-utils/lockdown.js +929 -0
  375. package/src/lib/app-utils/lockdown.js.map +1 -0
  376. package/src/lib/app-utils/margin-utilization.d.ts +267 -0
  377. package/src/lib/app-utils/margin-utilization.js +351 -0
  378. package/src/lib/app-utils/margin-utilization.js.map +1 -0
  379. package/src/lib/app-utils/markdown-lite.d.ts +297 -0
  380. package/src/lib/app-utils/markdown-lite.js +705 -0
  381. package/src/lib/app-utils/markdown-lite.js.map +1 -0
  382. package/src/lib/app-utils/marketing-consent.d.ts +704 -0
  383. package/src/lib/app-utils/marketing-consent.js +783 -0
  384. package/src/lib/app-utils/marketing-consent.js.map +1 -0
  385. package/src/lib/app-utils/marketplace-listing-visibility.d.ts +120 -0
  386. package/src/lib/app-utils/marketplace-listing-visibility.js +139 -0
  387. package/src/lib/app-utils/marketplace-listing-visibility.js.map +1 -0
  388. package/src/lib/app-utils/marketplace-overrides.d.ts +271 -0
  389. package/src/lib/app-utils/marketplace-overrides.js +462 -0
  390. package/src/lib/app-utils/marketplace-overrides.js.map +1 -0
  391. package/src/lib/app-utils/marketplace-provenance.d.ts +150 -0
  392. package/src/lib/app-utils/marketplace-provenance.js +136 -0
  393. package/src/lib/app-utils/marketplace-provenance.js.map +1 -0
  394. package/src/lib/app-utils/marketplace-theme.d.ts +237 -0
  395. package/src/lib/app-utils/marketplace-theme.js +525 -0
  396. package/src/lib/app-utils/marketplace-theme.js.map +1 -0
  397. package/src/lib/app-utils/marketplace-update-state.d.ts +119 -0
  398. package/src/lib/app-utils/marketplace-update-state.js +132 -0
  399. package/src/lib/app-utils/marketplace-update-state.js.map +1 -0
  400. package/src/lib/app-utils/marketplace-verification.d.ts +95 -0
  401. package/src/lib/app-utils/marketplace-verification.js +81 -0
  402. package/src/lib/app-utils/marketplace-verification.js.map +1 -0
  403. package/src/lib/app-utils/measure-node-map.d.ts +76 -0
  404. package/src/lib/app-utils/measure-node-map.js +111 -0
  405. package/src/lib/app-utils/measure-node-map.js.map +1 -0
  406. package/src/lib/app-utils/media-alt.d.ts +55 -0
  407. package/src/lib/app-utils/media-alt.js +58 -0
  408. package/src/lib/app-utils/media-alt.js.map +1 -0
  409. package/src/lib/app-utils/media-asset-facts.d.ts +125 -0
  410. package/src/lib/app-utils/media-asset-facts.js +467 -0
  411. package/src/lib/app-utils/media-asset-facts.js.map +1 -0
  412. package/src/lib/app-utils/media-cdn-scope.d.ts +65 -0
  413. package/src/lib/app-utils/media-cdn-scope.js +75 -0
  414. package/src/lib/app-utils/media-cdn-scope.js.map +1 -0
  415. package/src/lib/app-utils/media-folders.d.ts +161 -0
  416. package/src/lib/app-utils/media-folders.js +230 -0
  417. package/src/lib/app-utils/media-folders.js.map +1 -0
  418. package/src/lib/app-utils/media-metadata.d.ts +277 -0
  419. package/src/lib/app-utils/media-metadata.js +388 -0
  420. package/src/lib/app-utils/media-metadata.js.map +1 -0
  421. package/src/lib/app-utils/media-picker-context.d.ts +93 -0
  422. package/src/lib/app-utils/media-picker-context.js +26 -0
  423. package/src/lib/app-utils/media-picker-context.js.map +1 -0
  424. package/src/lib/app-utils/media-quarantine.d.ts +247 -0
  425. package/src/lib/app-utils/media-quarantine.js +323 -0
  426. package/src/lib/app-utils/media-quarantine.js.map +1 -0
  427. package/src/lib/app-utils/media-ref.d.ts +661 -0
  428. package/src/lib/app-utils/media-ref.js +1055 -0
  429. package/src/lib/app-utils/media-ref.js.map +1 -0
  430. package/src/lib/app-utils/media-takedown-reach.d.ts +126 -0
  431. package/src/lib/app-utils/media-takedown-reach.js +143 -0
  432. package/src/lib/app-utils/media-takedown-reach.js.map +1 -0
  433. package/src/lib/app-utils/member-email-aliases.d.ts +180 -0
  434. package/src/lib/app-utils/member-email-aliases.js +217 -0
  435. package/src/lib/app-utils/member-email-aliases.js.map +1 -0
  436. package/src/lib/app-utils/merge-node-sx.d.ts +47 -0
  437. package/src/lib/app-utils/merge-node-sx.js +123 -0
  438. package/src/lib/app-utils/merge-node-sx.js.map +1 -0
  439. package/src/lib/app-utils/name-match.d.ts +155 -0
  440. package/src/lib/app-utils/name-match.js +175 -0
  441. package/src/lib/app-utils/name-match.js.map +1 -0
  442. package/src/lib/app-utils/name-search.d.ts +117 -0
  443. package/src/lib/app-utils/name-search.js +145 -0
  444. package/src/lib/app-utils/name-search.js.map +1 -0
  445. package/src/lib/app-utils/node-capabilities.d.ts +85 -0
  446. package/src/lib/app-utils/node-capabilities.js +88 -0
  447. package/src/lib/app-utils/node-capabilities.js.map +1 -0
  448. package/src/lib/app-utils/node-definition-sanitizer.d.ts +164 -0
  449. package/src/lib/app-utils/node-definition-sanitizer.js +402 -0
  450. package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -0
  451. package/src/lib/app-utils/node-identity.d.ts +47 -0
  452. package/src/lib/app-utils/node-identity.js +50 -0
  453. package/src/lib/app-utils/node-identity.js.map +1 -0
  454. package/src/lib/app-utils/node-interactions.d.ts +102 -0
  455. package/src/lib/app-utils/node-interactions.js +192 -0
  456. package/src/lib/app-utils/node-interactions.js.map +1 -0
  457. package/src/lib/app-utils/node-url-policy.d.ts +54 -0
  458. package/src/lib/app-utils/node-url-policy.js +72 -0
  459. package/src/lib/app-utils/node-url-policy.js.map +1 -0
  460. package/src/lib/app-utils/notifications.d.ts +71 -0
  461. package/src/lib/app-utils/notifications.js +101 -0
  462. package/src/lib/app-utils/notifications.js.map +1 -0
  463. package/src/lib/app-utils/onboarding-deep-link.d.ts +120 -0
  464. package/src/lib/app-utils/onboarding-deep-link.js +142 -0
  465. package/src/lib/app-utils/onboarding-deep-link.js.map +1 -0
  466. package/src/lib/app-utils/operator-identity.d.ts +207 -0
  467. package/src/lib/app-utils/operator-identity.js +186 -0
  468. package/src/lib/app-utils/operator-identity.js.map +1 -0
  469. package/src/lib/app-utils/org-billing-doc.d.ts +231 -0
  470. package/src/lib/app-utils/org-billing-doc.js +238 -0
  471. package/src/lib/app-utils/org-billing-doc.js.map +1 -0
  472. package/src/lib/app-utils/org-override-reason.d.ts +100 -0
  473. package/src/lib/app-utils/org-override-reason.js +116 -0
  474. package/src/lib/app-utils/org-override-reason.js.map +1 -0
  475. package/src/lib/app-utils/org-permissions.d.ts +194 -0
  476. package/src/lib/app-utils/org-permissions.js +357 -0
  477. package/src/lib/app-utils/org-permissions.js.map +1 -0
  478. package/src/lib/app-utils/org-roles.d.ts +72 -0
  479. package/src/lib/app-utils/org-roles.js +131 -0
  480. package/src/lib/app-utils/org-roles.js.map +1 -0
  481. package/src/lib/app-utils/organizations.d.ts +407 -0
  482. package/src/lib/app-utils/organizations.js +511 -0
  483. package/src/lib/app-utils/organizations.js.map +1 -0
  484. package/src/lib/app-utils/page-header-actions-context.d.ts +83 -0
  485. package/src/lib/app-utils/page-header-actions-context.js +58 -0
  486. package/src/lib/app-utils/page-header-actions-context.js.map +1 -0
  487. package/src/lib/app-utils/page-header-record-context.d.ts +80 -0
  488. package/src/lib/app-utils/page-header-record-context.js +64 -0
  489. package/src/lib/app-utils/page-header-record-context.js.map +1 -0
  490. package/src/lib/app-utils/page-markdown.d.ts +103 -0
  491. package/src/lib/app-utils/page-markdown.js +385 -0
  492. package/src/lib/app-utils/page-markdown.js.map +1 -0
  493. package/src/lib/app-utils/paid-media-source.d.ts +90 -0
  494. package/src/lib/app-utils/paid-media-source.js +184 -0
  495. package/src/lib/app-utils/paid-media-source.js.map +1 -0
  496. package/src/lib/app-utils/palette-sx.d.ts +34 -0
  497. package/src/lib/app-utils/palette-sx.js +150 -0
  498. package/src/lib/app-utils/palette-sx.js.map +1 -0
  499. package/src/lib/app-utils/password-policy.d.ts +47 -0
  500. package/src/lib/app-utils/password-policy.js +46 -0
  501. package/src/lib/app-utils/password-policy.js.map +1 -0
  502. package/src/lib/app-utils/payments-configured.d.ts +84 -0
  503. package/src/lib/app-utils/payments-configured.js +88 -0
  504. package/src/lib/app-utils/payments-configured.js.map +1 -0
  505. package/src/lib/app-utils/person-erasure.d.ts +126 -0
  506. package/src/lib/app-utils/person-erasure.js +121 -0
  507. package/src/lib/app-utils/person-erasure.js.map +1 -0
  508. package/src/lib/app-utils/person-key.d.ts +32 -0
  509. package/src/lib/app-utils/person-key.js +62 -0
  510. package/src/lib/app-utils/person-key.js.map +1 -0
  511. package/src/lib/app-utils/plan-entitlements.d.ts +2756 -0
  512. package/src/lib/app-utils/plan-entitlements.js +4085 -0
  513. package/src/lib/app-utils/plan-entitlements.js.map +1 -0
  514. package/src/lib/app-utils/platform-ad-conversions.d.ts +122 -0
  515. package/src/lib/app-utils/platform-ad-conversions.js +174 -0
  516. package/src/lib/app-utils/platform-ad-conversions.js.map +1 -0
  517. package/src/lib/app-utils/platform-advertising-tags.d.ts +139 -0
  518. package/src/lib/app-utils/platform-advertising-tags.js +203 -0
  519. package/src/lib/app-utils/platform-advertising-tags.js.map +1 -0
  520. package/src/lib/app-utils/platform-brand.d.ts +151 -0
  521. package/src/lib/app-utils/platform-brand.js +175 -0
  522. package/src/lib/app-utils/platform-brand.js.map +1 -0
  523. package/src/lib/app-utils/platform-consent-default.d.ts +142 -0
  524. package/src/lib/app-utils/platform-consent-default.js +295 -0
  525. package/src/lib/app-utils/platform-consent-default.js.map +1 -0
  526. package/src/lib/app-utils/platform-marketing-consent.d.ts +151 -0
  527. package/src/lib/app-utils/platform-marketing-consent.js +182 -0
  528. package/src/lib/app-utils/platform-marketing-consent.js.map +1 -0
  529. package/src/lib/app-utils/platform-marketing-host.d.ts +33 -0
  530. package/src/lib/app-utils/platform-marketing-host.js +97 -0
  531. package/src/lib/app-utils/platform-marketing-host.js.map +1 -0
  532. package/src/lib/app-utils/platform-visitor-consent.d.ts +252 -0
  533. package/src/lib/app-utils/platform-visitor-consent.js +533 -0
  534. package/src/lib/app-utils/platform-visitor-consent.js.map +1 -0
  535. package/src/lib/app-utils/plugin-api-cross-origin.d.ts +61 -0
  536. package/src/lib/app-utils/plugin-api-cross-origin.js +202 -0
  537. package/src/lib/app-utils/plugin-api-cross-origin.js.map +1 -0
  538. package/src/lib/app-utils/plugin-api-rate-limit.d.ts +192 -0
  539. package/src/lib/app-utils/plugin-api-rate-limit.js +270 -0
  540. package/src/lib/app-utils/plugin-api-rate-limit.js.map +1 -0
  541. package/src/lib/app-utils/plugin-artifact-path.d.ts +32 -0
  542. package/src/lib/app-utils/plugin-artifact-path.js +33 -0
  543. package/src/lib/app-utils/plugin-artifact-path.js.map +1 -0
  544. package/src/lib/app-utils/plugin-bundle-checks.d.ts +148 -0
  545. package/src/lib/app-utils/plugin-bundle-checks.js +989 -0
  546. package/src/lib/app-utils/plugin-bundle-checks.js.map +1 -0
  547. package/src/lib/app-utils/plugin-manifest.d.ts +516 -0
  548. package/src/lib/app-utils/plugin-manifest.js +687 -0
  549. package/src/lib/app-utils/plugin-manifest.js.map +1 -0
  550. package/src/lib/app-utils/published-legal-pages.d.ts +71 -0
  551. package/src/lib/app-utils/published-legal-pages.js +90 -0
  552. package/src/lib/app-utils/published-legal-pages.js.map +1 -0
  553. package/src/lib/app-utils/publisher-agreement.d.ts +254 -0
  554. package/src/lib/app-utils/publisher-agreement.js +274 -0
  555. package/src/lib/app-utils/publisher-agreement.js.map +1 -0
  556. package/src/lib/app-utils/publisher-attestation.d.ts +99 -0
  557. package/src/lib/app-utils/publisher-attestation.js +158 -0
  558. package/src/lib/app-utils/publisher-attestation.js.map +1 -0
  559. package/src/lib/app-utils/recipient-email-render.d.ts +216 -0
  560. package/src/lib/app-utils/recipient-email-render.js +221 -0
  561. package/src/lib/app-utils/recipient-email-render.js.map +1 -0
  562. package/src/lib/app-utils/redispatch-caught-error.d.ts +38 -0
  563. package/src/lib/app-utils/redispatch-caught-error.js +46 -0
  564. package/src/lib/app-utils/redispatch-caught-error.js.map +1 -0
  565. package/src/lib/app-utils/registering-plugin.d.ts +19 -0
  566. package/src/lib/app-utils/registering-plugin.js +38 -0
  567. package/src/lib/app-utils/registering-plugin.js.map +1 -0
  568. package/src/lib/app-utils/release-flags.d.ts +283 -0
  569. package/src/lib/app-utils/release-flags.js +518 -0
  570. package/src/lib/app-utils/release-flags.js.map +1 -0
  571. package/src/lib/app-utils/repair-canvas-nodes.d.ts +130 -0
  572. package/src/lib/app-utils/repair-canvas-nodes.js +298 -0
  573. package/src/lib/app-utils/repair-canvas-nodes.js.map +1 -0
  574. package/src/lib/app-utils/repeat-infringer.d.ts +166 -0
  575. package/src/lib/app-utils/repeat-infringer.js +188 -0
  576. package/src/lib/app-utils/repeat-infringer.js.map +1 -0
  577. package/src/lib/app-utils/repeat-sources.d.ts +115 -0
  578. package/src/lib/app-utils/repeat-sources.js +86 -0
  579. package/src/lib/app-utils/repeat-sources.js.map +1 -0
  580. package/src/lib/app-utils/request-geo.d.ts +114 -0
  581. package/src/lib/app-utils/request-geo.js +247 -0
  582. package/src/lib/app-utils/request-geo.js.map +1 -0
  583. package/src/lib/app-utils/request-ip.d.ts +213 -0
  584. package/src/lib/app-utils/request-ip.js +344 -0
  585. package/src/lib/app-utils/request-ip.js.map +1 -0
  586. package/src/lib/app-utils/resolve-named-tokens.d.ts +26 -0
  587. package/src/lib/app-utils/resolve-named-tokens.js +59 -0
  588. package/src/lib/app-utils/resolve-named-tokens.js.map +1 -0
  589. package/src/lib/app-utils/responsive-typography-sx.d.ts +77 -0
  590. package/src/lib/app-utils/responsive-typography-sx.js +122 -0
  591. package/src/lib/app-utils/responsive-typography-sx.js.map +1 -0
  592. package/src/lib/app-utils/reusable-component-keys.d.ts +135 -0
  593. package/src/lib/app-utils/reusable-component-keys.js +140 -0
  594. package/src/lib/app-utils/reusable-component-keys.js.map +1 -0
  595. package/src/lib/app-utils/reusable-prop-values.d.ts +199 -0
  596. package/src/lib/app-utils/reusable-prop-values.js +494 -0
  597. package/src/lib/app-utils/reusable-prop-values.js.map +1 -0
  598. package/src/lib/app-utils/safe-json-ld.d.ts +29 -0
  599. package/src/lib/app-utils/safe-json-ld.js +37 -0
  600. package/src/lib/app-utils/safe-json-ld.js.map +1 -0
  601. package/src/lib/app-utils/sanitize-svg.d.ts +55 -0
  602. package/src/lib/app-utils/sanitize-svg.js +460 -0
  603. package/src/lib/app-utils/sanitize-svg.js.map +1 -0
  604. package/src/lib/app-utils/scheme-sx.d.ts +84 -0
  605. package/src/lib/app-utils/scheme-sx.js +148 -0
  606. package/src/lib/app-utils/scheme-sx.js.map +1 -0
  607. package/src/lib/app-utils/scope-tokens.d.ts +249 -0
  608. package/src/lib/app-utils/scope-tokens.js +331 -0
  609. package/src/lib/app-utils/scope-tokens.js.map +1 -0
  610. package/src/lib/app-utils/screen-link-context-value.d.ts +57 -0
  611. package/src/lib/app-utils/screen-link-context-value.js +43 -0
  612. package/src/lib/app-utils/screen-link-context-value.js.map +1 -0
  613. package/src/lib/app-utils/screen-link-context.d.ts +185 -0
  614. package/src/lib/app-utils/screen-link-context.js +304 -0
  615. package/src/lib/app-utils/screen-link-context.js.map +1 -0
  616. package/src/lib/app-utils/screen-link-value.d.ts +269 -0
  617. package/src/lib/app-utils/screen-link-value.js +384 -0
  618. package/src/lib/app-utils/screen-link-value.js.map +1 -0
  619. package/src/lib/app-utils/screen-route.d.ts +669 -0
  620. package/src/lib/app-utils/screen-route.js +751 -0
  621. package/src/lib/app-utils/screen-route.js.map +1 -0
  622. package/src/lib/app-utils/screen-seo-fields.d.ts +37 -0
  623. package/src/lib/app-utils/screen-seo-fields.js +42 -0
  624. package/src/lib/app-utils/screen-seo-fields.js.map +1 -0
  625. package/src/lib/app-utils/search-indexing.d.ts +162 -0
  626. package/src/lib/app-utils/search-indexing.js +207 -0
  627. package/src/lib/app-utils/search-indexing.js.map +1 -0
  628. package/src/lib/app-utils/seo-listing-fields.d.ts +70 -0
  629. package/src/lib/app-utils/seo-listing-fields.js +75 -0
  630. package/src/lib/app-utils/seo-listing-fields.js.map +1 -0
  631. package/src/lib/app-utils/seo-locale.d.ts +119 -0
  632. package/src/lib/app-utils/seo-locale.js +133 -0
  633. package/src/lib/app-utils/seo-locale.js.map +1 -0
  634. package/src/lib/app-utils/seo-title-variables.d.ts +149 -0
  635. package/src/lib/app-utils/seo-title-variables.js +190 -0
  636. package/src/lib/app-utils/seo-title-variables.js.map +1 -0
  637. package/src/lib/app-utils/seo-title.d.ts +70 -0
  638. package/src/lib/app-utils/seo-title.js +117 -0
  639. package/src/lib/app-utils/seo-title.js.map +1 -0
  640. package/src/lib/app-utils/server.d.ts +174 -0
  641. package/src/lib/app-utils/server.js +314 -0
  642. package/src/lib/app-utils/server.js.map +1 -0
  643. package/src/lib/app-utils/site-context.d.ts +106 -0
  644. package/src/lib/app-utils/site-context.js +100 -0
  645. package/src/lib/app-utils/site-context.js.map +1 -0
  646. package/src/lib/app-utils/sitemap.d.ts +117 -0
  647. package/src/lib/app-utils/sitemap.js +183 -0
  648. package/src/lib/app-utils/sitemap.js.map +1 -0
  649. package/src/lib/app-utils/social-image.d.ts +112 -0
  650. package/src/lib/app-utils/social-image.js +191 -0
  651. package/src/lib/app-utils/social-image.js.map +1 -0
  652. package/src/lib/app-utils/starter-templates.d.ts +99 -0
  653. package/src/lib/app-utils/starter-templates.js +579 -0
  654. package/src/lib/app-utils/starter-templates.js.map +1 -0
  655. package/src/lib/app-utils/stored-nodes.d.ts +120 -0
  656. package/src/lib/app-utils/stored-nodes.js +174 -0
  657. package/src/lib/app-utils/stored-nodes.js.map +1 -0
  658. package/src/lib/app-utils/strip-undefined.d.ts +59 -0
  659. package/src/lib/app-utils/strip-undefined.js +95 -0
  660. package/src/lib/app-utils/strip-undefined.js.map +1 -0
  661. package/src/lib/app-utils/stripe-deployment-mode.d.ts +47 -0
  662. package/src/lib/app-utils/stripe-deployment-mode.js +70 -0
  663. package/src/lib/app-utils/stripe-deployment-mode.js.map +1 -0
  664. package/src/lib/app-utils/support-tiers.d.ts +108 -0
  665. package/src/lib/app-utils/support-tiers.js +201 -0
  666. package/src/lib/app-utils/support-tiers.js.map +1 -0
  667. package/src/lib/app-utils/timezone-geo-hint.d.ts +36 -0
  668. package/src/lib/app-utils/timezone-geo-hint.js +180 -0
  669. package/src/lib/app-utils/timezone-geo-hint.js.map +1 -0
  670. package/src/lib/app-utils/upload-cors.d.ts +155 -0
  671. package/src/lib/app-utils/upload-cors.js +254 -0
  672. package/src/lib/app-utils/upload-cors.js.map +1 -0
  673. package/src/lib/app-utils/upload-inspection.d.ts +159 -0
  674. package/src/lib/app-utils/upload-inspection.js +539 -0
  675. package/src/lib/app-utils/upload-inspection.js.map +1 -0
  676. package/src/lib/app-utils/url-slug.d.ts +40 -0
  677. package/src/lib/app-utils/url-slug.js +42 -0
  678. package/src/lib/app-utils/url-slug.js.map +1 -0
  679. package/src/lib/app-utils/usage-budget.d.ts +429 -0
  680. package/src/lib/app-utils/usage-budget.js +421 -0
  681. package/src/lib/app-utils/usage-budget.js.map +1 -0
  682. package/src/lib/app-utils/variables.d.ts +96 -0
  683. package/src/lib/app-utils/variables.js +233 -0
  684. package/src/lib/app-utils/variables.js.map +1 -0
  685. package/src/lib/app-utils/video-asset-facts.d.ts +61 -0
  686. package/src/lib/app-utils/video-asset-facts.js +70 -0
  687. package/src/lib/app-utils/video-asset-facts.js.map +1 -0
  688. package/src/lib/app-utils/video-object.d.ts +89 -0
  689. package/src/lib/app-utils/video-object.js +245 -0
  690. package/src/lib/app-utils/video-object.js.map +1 -0
  691. package/src/lib/app-utils/visitor-consent.d.ts +757 -0
  692. package/src/lib/app-utils/visitor-consent.js +981 -0
  693. package/src/lib/app-utils/visitor-consent.js.map +1 -0
  694. package/src/lib/app-utils/visitor-record-ceiling.d.ts +223 -0
  695. package/src/lib/app-utils/visitor-record-ceiling.js +215 -0
  696. package/src/lib/app-utils/visitor-record-ceiling.js.map +1 -0
  697. package/src/lib/app-utils/web-vitals-rum.d.ts +53 -0
  698. package/src/lib/app-utils/web-vitals-rum.js +278 -0
  699. package/src/lib/app-utils/web-vitals-rum.js.map +1 -0
  700. package/src/lib/app-utils/webhook-delivery.d.ts +324 -0
  701. package/src/lib/app-utils/webhook-delivery.js +413 -0
  702. package/src/lib/app-utils/webhook-delivery.js.map +1 -0
  703. package/src/lib/app-utils/where-used.d.ts +57 -0
  704. package/src/lib/app-utils/where-used.js +59 -0
  705. package/src/lib/app-utils/where-used.js.map +1 -0
  706. package/src/lib/app-utils/wistia-embed.d.ts +86 -0
  707. package/src/lib/app-utils/wistia-embed.js +119 -0
  708. package/src/lib/app-utils/wistia-embed.js.map +1 -0
  709. package/src/lib/app-utils/workflows.d.ts +136 -0
  710. package/src/lib/app-utils/workflows.js +346 -0
  711. package/src/lib/app-utils/workflows.js.map +1 -0
  712. package/src/lib/canvas-manager/canvas-manager-tree.d.ts +109 -0
  713. package/src/lib/canvas-manager/canvas-manager-tree.js +139 -0
  714. package/src/lib/canvas-manager/canvas-manager-tree.js.map +1 -0
  715. package/src/lib/canvas-manager/canvas-manager.d.ts +549 -0
  716. package/src/lib/canvas-manager/canvas-manager.js +1311 -0
  717. package/src/lib/canvas-manager/canvas-manager.js.map +1 -0
  718. package/src/lib/canvas-manager/index.d.ts +20 -0
  719. package/src/lib/canvas-manager/index.js +21 -0
  720. package/src/lib/canvas-manager/index.js.map +1 -0
  721. package/src/lib/canvas-manager/stores/index.d.ts +17 -0
  722. package/src/lib/canvas-manager/stores/index.js +18 -0
  723. package/src/lib/canvas-manager/stores/index.js.map +1 -0
  724. package/src/lib/canvas-manager/stores/node.store.d.ts +30 -0
  725. package/src/lib/canvas-manager/stores/node.store.js +45 -0
  726. package/src/lib/canvas-manager/stores/node.store.js.map +1 -0
  727. package/src/lib/components-manager/components-manager.d.ts +56 -0
  728. package/src/lib/components-manager/components-manager.js +191 -0
  729. package/src/lib/components-manager/components-manager.js.map +1 -0
  730. package/src/lib/components-manager/index.d.ts +18 -0
  731. package/src/lib/components-manager/index.js +19 -0
  732. package/src/lib/components-manager/index.js.map +1 -0
  733. package/src/lib/emit-manager/emit-manager.d.ts +56 -0
  734. package/src/lib/emit-manager/emit-manager.js +60 -0
  735. package/src/lib/emit-manager/emit-manager.js.map +1 -0
  736. package/src/lib/emit-manager/index.d.ts +18 -0
  737. package/src/lib/emit-manager/index.js +19 -0
  738. package/src/lib/emit-manager/index.js.map +1 -0
  739. package/src/lib/foundation/constants/_internal.d.ts +18 -0
  740. package/src/lib/foundation/constants/_internal.js +62 -0
  741. package/src/lib/foundation/constants/_internal.js.map +1 -0
  742. package/src/lib/foundation/constants/app.d.ts +23 -0
  743. package/src/lib/foundation/constants/app.js +25 -0
  744. package/src/lib/foundation/constants/app.js.map +1 -0
  745. package/src/lib/foundation/constants/canvas.d.ts +18 -0
  746. package/src/lib/foundation/constants/canvas.js +18 -0
  747. package/src/lib/foundation/constants/canvas.js.map +1 -0
  748. package/src/lib/foundation/constants/components.d.ts +54 -0
  749. package/src/lib/foundation/constants/components.js +61 -0
  750. package/src/lib/foundation/constants/components.js.map +1 -0
  751. package/src/lib/foundation/constants/shared.d.ts +50 -0
  752. package/src/lib/foundation/constants/shared.js +49 -0
  753. package/src/lib/foundation/constants/shared.js.map +1 -0
  754. package/src/lib/foundation/constants/symbol.d.ts +63 -0
  755. package/src/lib/foundation/constants/symbol.js +75 -0
  756. package/src/lib/foundation/constants/symbol.js.map +1 -0
  757. package/src/lib/foundation/definitions/components.types.d.ts +372 -0
  758. package/src/lib/foundation/definitions/components.types.js +180 -0
  759. package/src/lib/foundation/definitions/components.types.js.map +1 -0
  760. package/src/lib/foundation/definitions/contact.types.d.ts +73 -0
  761. package/src/lib/foundation/definitions/contact.types.js +107 -0
  762. package/src/lib/foundation/definitions/contact.types.js.map +1 -0
  763. package/src/lib/foundation/definitions/host-content-collections.d.ts +137 -0
  764. package/src/lib/foundation/definitions/host-content-collections.js +219 -0
  765. package/src/lib/foundation/definitions/host-content-collections.js.map +1 -0
  766. package/src/lib/foundation/definitions/org-billing.types.d.ts +1361 -0
  767. package/src/lib/foundation/definitions/org-billing.types.js +77 -0
  768. package/src/lib/foundation/definitions/org-billing.types.js.map +1 -0
  769. package/src/lib/foundation/definitions/organization.types.d.ts +307 -0
  770. package/src/lib/foundation/definitions/organization.types.js +42 -0
  771. package/src/lib/foundation/definitions/organization.types.js.map +1 -0
  772. package/src/lib/foundation/definitions/platform.types.d.ts +1326 -0
  773. package/src/lib/foundation/definitions/platform.types.js +124 -0
  774. package/src/lib/foundation/definitions/platform.types.js.map +1 -0
  775. package/src/lib/foundation/definitions/property-kinds.d.ts +189 -0
  776. package/src/lib/foundation/definitions/property-kinds.js +565 -0
  777. package/src/lib/foundation/definitions/property-kinds.js.map +1 -0
  778. package/src/lib/foundation/definitions/shared.d.ts +23 -0
  779. package/src/lib/foundation/definitions/shared.js +18 -0
  780. package/src/lib/foundation/definitions/shared.js.map +1 -0
  781. package/src/lib/foundation/definitions/write-deny-coverage.util.d.ts +249 -0
  782. package/src/lib/foundation/definitions/write-deny-coverage.util.js +499 -0
  783. package/src/lib/foundation/definitions/write-deny-coverage.util.js.map +1 -0
  784. package/src/lib/foundation/index.d.ts +32 -0
  785. package/src/lib/foundation/index.js +67 -0
  786. package/src/lib/foundation/index.js.map +1 -0
  787. package/src/lib/lifecycle.d.ts +24 -0
  788. package/src/lib/lifecycle.js +39 -0
  789. package/src/lib/lifecycle.js.map +1 -0
  790. package/src/lib/mst/common.d.ts +17 -0
  791. package/src/lib/mst/common.js +23 -0
  792. package/src/lib/mst/common.js.map +1 -0
  793. package/src/lib/mst/index.d.ts +19 -0
  794. package/src/lib/mst/index.js +20 -0
  795. package/src/lib/mst/index.js.map +1 -0
  796. package/src/lib/mst/json.d.ts +22 -0
  797. package/src/lib/mst/json.js +23 -0
  798. package/src/lib/mst/json.js.map +1 -0
  799. package/src/lib/mst/types.d.ts +20 -0
  800. package/src/lib/mst/types.js +18 -0
  801. package/src/lib/mst/types.js.map +1 -0
  802. package/src/lib/plugin-manager/billing-webhook-hooks.d.ts +77 -0
  803. package/src/lib/plugin-manager/billing-webhook-hooks.js +55 -0
  804. package/src/lib/plugin-manager/billing-webhook-hooks.js.map +1 -0
  805. package/src/lib/plugin-manager/commerce-zone-props.d.ts +172 -0
  806. package/src/lib/plugin-manager/commerce-zone-props.js +31 -0
  807. package/src/lib/plugin-manager/commerce-zone-props.js.map +1 -0
  808. package/src/lib/plugin-manager/custom-fields.d.ts +60 -0
  809. package/src/lib/plugin-manager/custom-fields.js +39 -0
  810. package/src/lib/plugin-manager/custom-fields.js.map +1 -0
  811. package/src/lib/plugin-manager/editor-sessions.d.ts +109 -0
  812. package/src/lib/plugin-manager/editor-sessions.js +137 -0
  813. package/src/lib/plugin-manager/editor-sessions.js.map +1 -0
  814. package/src/lib/plugin-manager/enabled-plugins.d.ts +438 -0
  815. package/src/lib/plugin-manager/enabled-plugins.js +403 -0
  816. package/src/lib/plugin-manager/enabled-plugins.js.map +1 -0
  817. package/src/lib/plugin-manager/feature-plugins.d.ts +1314 -0
  818. package/src/lib/plugin-manager/feature-plugins.js +609 -0
  819. package/src/lib/plugin-manager/feature-plugins.js.map +1 -0
  820. package/src/lib/plugin-manager/first-party-plugins.generated.d.ts +11 -0
  821. package/src/lib/plugin-manager/first-party-plugins.generated.js +149 -0
  822. package/src/lib/plugin-manager/first-party-plugins.generated.js.map +1 -0
  823. package/src/lib/plugin-manager/index.d.ts +42 -0
  824. package/src/lib/plugin-manager/index.js +46 -0
  825. package/src/lib/plugin-manager/index.js.map +1 -0
  826. package/src/lib/plugin-manager/install-presets.d.ts +93 -0
  827. package/src/lib/plugin-manager/install-presets.js +86 -0
  828. package/src/lib/plugin-manager/install-presets.js.map +1 -0
  829. package/src/lib/plugin-manager/media-delivery-provider.d.ts +124 -0
  830. package/src/lib/plugin-manager/media-delivery-provider.js +53 -0
  831. package/src/lib/plugin-manager/media-delivery-provider.js.map +1 -0
  832. package/src/lib/plugin-manager/order-fulfilment.d.ts +142 -0
  833. package/src/lib/plugin-manager/order-fulfilment.js +104 -0
  834. package/src/lib/plugin-manager/order-fulfilment.js.map +1 -0
  835. package/src/lib/plugin-manager/plugin-activity-actions.d.ts +122 -0
  836. package/src/lib/plugin-manager/plugin-activity-actions.js +140 -0
  837. package/src/lib/plugin-manager/plugin-activity-actions.js.map +1 -0
  838. package/src/lib/plugin-manager/plugin-bridge.d.ts +98 -0
  839. package/src/lib/plugin-manager/plugin-bridge.js +154 -0
  840. package/src/lib/plugin-manager/plugin-bridge.js.map +1 -0
  841. package/src/lib/plugin-manager/plugin-config.d.ts +148 -0
  842. package/src/lib/plugin-manager/plugin-config.js +228 -0
  843. package/src/lib/plugin-manager/plugin-config.js.map +1 -0
  844. package/src/lib/plugin-manager/plugin-console-crons.d.ts +139 -0
  845. package/src/lib/plugin-manager/plugin-console-crons.js +177 -0
  846. package/src/lib/plugin-manager/plugin-console-crons.js.map +1 -0
  847. package/src/lib/plugin-manager/plugin-contact-capture.d.ts +220 -0
  848. package/src/lib/plugin-manager/plugin-contact-capture.js +89 -0
  849. package/src/lib/plugin-manager/plugin-contact-capture.js.map +1 -0
  850. package/src/lib/plugin-manager/plugin-contributions.d.ts +244 -0
  851. package/src/lib/plugin-manager/plugin-contributions.js +283 -0
  852. package/src/lib/plugin-manager/plugin-contributions.js.map +1 -0
  853. package/src/lib/plugin-manager/plugin-entitlement-keys.d.ts +169 -0
  854. package/src/lib/plugin-manager/plugin-entitlement-keys.js +84 -0
  855. package/src/lib/plugin-manager/plugin-entitlement-keys.js.map +1 -0
  856. package/src/lib/plugin-manager/plugin-entitlements.d.ts +181 -0
  857. package/src/lib/plugin-manager/plugin-entitlements.js +188 -0
  858. package/src/lib/plugin-manager/plugin-entitlements.js.map +1 -0
  859. package/src/lib/plugin-manager/plugin-events.d.ts +145 -0
  860. package/src/lib/plugin-manager/plugin-events.js +79 -0
  861. package/src/lib/plugin-manager/plugin-events.js.map +1 -0
  862. package/src/lib/plugin-manager/plugin-figures.d.ts +251 -0
  863. package/src/lib/plugin-manager/plugin-figures.js +252 -0
  864. package/src/lib/plugin-manager/plugin-figures.js.map +1 -0
  865. package/src/lib/plugin-manager/plugin-host-collections.d.ts +146 -0
  866. package/src/lib/plugin-manager/plugin-host-collections.js +116 -0
  867. package/src/lib/plugin-manager/plugin-host-collections.js.map +1 -0
  868. package/src/lib/plugin-manager/plugin-jobs.d.ts +130 -0
  869. package/src/lib/plugin-manager/plugin-jobs.js +182 -0
  870. package/src/lib/plugin-manager/plugin-jobs.js.map +1 -0
  871. package/src/lib/plugin-manager/plugin-loader.d.ts +86 -0
  872. package/src/lib/plugin-manager/plugin-loader.js +223 -0
  873. package/src/lib/plugin-manager/plugin-loader.js.map +1 -0
  874. package/src/lib/plugin-manager/plugin-manager.d.ts +95 -0
  875. package/src/lib/plugin-manager/plugin-manager.js +343 -0
  876. package/src/lib/plugin-manager/plugin-manager.js.map +1 -0
  877. package/src/lib/plugin-manager/plugin-metered-lines.d.ts +97 -0
  878. package/src/lib/plugin-manager/plugin-metered-lines.js +123 -0
  879. package/src/lib/plugin-manager/plugin-metered-lines.js.map +1 -0
  880. package/src/lib/plugin-manager/plugin-org-erasure.d.ts +52 -0
  881. package/src/lib/plugin-manager/plugin-org-erasure.js +100 -0
  882. package/src/lib/plugin-manager/plugin-org-erasure.js.map +1 -0
  883. package/src/lib/plugin-manager/plugin-permissions.d.ts +69 -0
  884. package/src/lib/plugin-manager/plugin-permissions.js +77 -0
  885. package/src/lib/plugin-manager/plugin-permissions.js.map +1 -0
  886. package/src/lib/plugin-manager/plugin-person-erasure.d.ts +58 -0
  887. package/src/lib/plugin-manager/plugin-person-erasure.js +109 -0
  888. package/src/lib/plugin-manager/plugin-person-erasure.js.map +1 -0
  889. package/src/lib/plugin-manager/plugin-record-cards.d.ts +99 -0
  890. package/src/lib/plugin-manager/plugin-record-cards.js +59 -0
  891. package/src/lib/plugin-manager/plugin-record-cards.js.map +1 -0
  892. package/src/lib/plugin-manager/plugin-record-facts.d.ts +111 -0
  893. package/src/lib/plugin-manager/plugin-record-facts.js +51 -0
  894. package/src/lib/plugin-manager/plugin-record-facts.js.map +1 -0
  895. package/src/lib/plugin-manager/plugin-record-routes.d.ts +129 -0
  896. package/src/lib/plugin-manager/plugin-record-routes.js +93 -0
  897. package/src/lib/plugin-manager/plugin-record-routes.js.map +1 -0
  898. package/src/lib/plugin-manager/plugin-record-timeline.d.ts +147 -0
  899. package/src/lib/plugin-manager/plugin-record-timeline.js +39 -0
  900. package/src/lib/plugin-manager/plugin-record-timeline.js.map +1 -0
  901. package/src/lib/plugin-manager/plugin-resource-drafts.d.ts +137 -0
  902. package/src/lib/plugin-manager/plugin-resource-drafts.js +51 -0
  903. package/src/lib/plugin-manager/plugin-resource-drafts.js.map +1 -0
  904. package/src/lib/plugin-manager/plugin-services.d.ts +94 -0
  905. package/src/lib/plugin-manager/plugin-services.js +153 -0
  906. package/src/lib/plugin-manager/plugin-services.js.map +1 -0
  907. package/src/lib/plugin-manager/plugin-styles-ui.d.ts +71 -0
  908. package/src/lib/plugin-manager/plugin-styles-ui.js +80 -0
  909. package/src/lib/plugin-manager/plugin-styles-ui.js.map +1 -0
  910. package/src/lib/plugin-manager/plugin-styles.d.ts +176 -0
  911. package/src/lib/plugin-manager/plugin-styles.js +186 -0
  912. package/src/lib/plugin-manager/plugin-styles.js.map +1 -0
  913. package/src/lib/plugin-manager/plugin-subprocessors.d.ts +135 -0
  914. package/src/lib/plugin-manager/plugin-subprocessors.js +129 -0
  915. package/src/lib/plugin-manager/plugin-subprocessors.js.map +1 -0
  916. package/src/lib/plugin-manager/plugin-tax-profile.d.ts +84 -0
  917. package/src/lib/plugin-manager/plugin-tax-profile.js +39 -0
  918. package/src/lib/plugin-manager/plugin-tax-profile.js.map +1 -0
  919. package/src/lib/plugin-manager/plugin-user-erasure.d.ts +53 -0
  920. package/src/lib/plugin-manager/plugin-user-erasure.js +84 -0
  921. package/src/lib/plugin-manager/plugin-user-erasure.js.map +1 -0
  922. package/src/lib/plugin-manager/plugin-zones.d.ts +121 -0
  923. package/src/lib/plugin-manager/plugin-zones.js +74 -0
  924. package/src/lib/plugin-manager/plugin-zones.js.map +1 -0
  925. package/src/lib/plugin-manager/realm-plugins.d.ts +112 -0
  926. package/src/lib/plugin-manager/realm-plugins.js +196 -0
  927. package/src/lib/plugin-manager/realm-plugins.js.map +1 -0
  928. package/src/lib/plugin-manager/realm-server.d.ts +54 -0
  929. package/src/lib/plugin-manager/realm-server.js +88 -0
  930. package/src/lib/plugin-manager/realm-server.js.map +1 -0
  931. package/src/lib/plugin-manager/record-zone-props.d.ts +126 -0
  932. package/src/lib/plugin-manager/record-zone-props.js +31 -0
  933. package/src/lib/plugin-manager/record-zone-props.js.map +1 -0
  934. package/src/lib/plugin-manager/site-page-hooks.d.ts +102 -0
  935. package/src/lib/plugin-manager/site-page-hooks.js +114 -0
  936. package/src/lib/plugin-manager/site-page-hooks.js.map +1 -0
  937. package/src/lib/plugin-manager/site-runtime.d.ts +57 -0
  938. package/src/lib/plugin-manager/site-runtime.js +25 -0
  939. package/src/lib/plugin-manager/site-runtime.js.map +1 -0
  940. package/src/lib/plugin-manager/usage-alert-contributors.d.ts +115 -0
  941. package/src/lib/plugin-manager/usage-alert-contributors.js +106 -0
  942. package/src/lib/plugin-manager/usage-alert-contributors.js.map +1 -0
  943. package/src/lib/types/ast.d.ts +199 -0
  944. package/src/lib/types/ast.js +20 -0
  945. package/src/lib/types/ast.js.map +1 -0
  946. package/src/lib/types/index.d.ts +20 -0
  947. package/src/lib/types/index.js +21 -0
  948. package/src/lib/types/index.js.map +1 -0
  949. package/src/lib/types/nodes.d.ts +608 -0
  950. package/src/lib/types/nodes.js +28 -0
  951. package/src/lib/types/nodes.js.map +1 -0
  952. package/src/lib/types/routing.d.ts +17 -0
  953. package/src/lib/types/routing.js +18 -0
  954. package/src/lib/types/routing.js.map +1 -0
  955. package/src/lib/types/screen.d.ts +23 -0
  956. package/src/lib/types/screen.js +18 -0
  957. package/src/lib/types/screen.js.map +1 -0
  958. package/src/lib/utils.d.ts +25 -0
  959. package/src/lib/utils.js +42 -0
  960. package/src/lib/utils.js.map +1 -0
  961. package/src/server.d.ts +37 -0
  962. package/src/server.js +55 -0
  963. package/src/server.js.map +1 -0
@@ -0,0 +1,1814 @@
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
+ * Contacts CRM v2 (AGL-2595): the records that sit BESIDE a contact.
18
+ *
19
+ * v1 is one collection — `contacts` — and everything a holder knows about a
20
+ * person lives in that holder's facet on the shared row. That shape is right
21
+ * for the person and wrong for everything a sales team keeps AROUND the
22
+ * person: a company is known by several contacts, a deal moves through
23
+ * stages on its own clock, a task is due whether or not anybody opens the
24
+ * contact it hangs off, and an activity log grows past anything a facet
25
+ * should carry. So each of those is a collection of its own under
26
+ * `orgs/{orgId}/`, pointing back at the contact by id.
27
+ *
28
+ * ## One scope model, not a second one
29
+ *
30
+ * Every collection here carries `visibleTo`, the same array `contacts`
31
+ * carries, and is stamped the same way — {@link crmScopeTokens} is the
32
+ * contact create path's expression, exported so that no creator computes its
33
+ * own. The rules gate all six on the contacts predicate (`canReadScopedPeople`,
34
+ * `data.manage`), because a deal or a call log is a fact about a person and
35
+ * discloses exactly what the contact row would.
36
+ *
37
+ * What these collections do NOT have is the facet map. A contact is shared
38
+ * across holders because one human is one row; a company, deal or task is
39
+ * one holder's record from the moment it is created, so `visibleTo` alone
40
+ * says who may see it and there is nothing to split per holder.
41
+ *
42
+ * Pure data module: types, constants and the small helpers every surface
43
+ * would otherwise write for itself. No Firestore, no React.
44
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
45
+ import { consentGroupScope } from "./consent-groups.js";
46
+ import { CONTACT_LIFECYCLE_STAGES, isContactLifecycleStage } from "./crm-kinds.js";
47
+ import { CONTACT_FACETS_FIELD, CONTACT_SOURCE_LABELS, normalizeContactEmail, readContactFacet } from "./contacts.js";
48
+ import { MAX_SCOPE_HOSTS, ORG_SCOPE_TOKEN } from "./scope-tokens.js";
49
+ // The fixed vocabularies and their guards live in a leaf module; every name
50
+ // stays importable from here.
51
+ export * from "./crm-kinds.js";
52
+ /**
53
+ * The CRM's collections, every one under `orgs/{orgId}/`.
54
+ *
55
+ * Named here rather than spelled at each call site because the rules, the
56
+ * indexes and the console must agree on the string, and the three prefixed
57
+ * ones are prefixed on purpose: `tasks`, `activities` and `views` are words
58
+ * the org document will want for something else one day, and a collection
59
+ * name is persisted in every document path that uses it.
60
+ */ export const CRM_COLLECTIONS = {
61
+ companies: 'companies',
62
+ pipelines: 'pipelines',
63
+ deals: 'deals',
64
+ tasks: 'crmTasks',
65
+ activities: 'crmActivities',
66
+ contactFields: 'contactFields',
67
+ views: 'crmViews',
68
+ emailTemplates: 'crmEmailTemplates'
69
+ };
70
+ /**
71
+ * The three collections the CRM RECORDS band counts (AGL-2611), in the order
72
+ * the billing caption lists them. `contacts` is not in `CRM_COLLECTIONS`
73
+ * because it predates the hub and is addressed through `orgDataCollection`,
74
+ * so the band's own list has to name all three itself. Tasks, pipelines,
75
+ * activities and field definitions are deliberately absent: a band that
76
+ * counted what a rep does every hour would price the team's effort, not the
77
+ * audience it holds.
78
+ */ export const CRM_RECORD_COLLECTIONS = [
79
+ 'contacts',
80
+ CRM_COLLECTIONS.companies,
81
+ CRM_COLLECTIONS.deals
82
+ ];
83
+ /**
84
+ * What a create says when the records band refused it, on every surface —
85
+ * the contacts list's alert, the company and deal drawers, the plugin's
86
+ * create routes and the lead conversion (AGL-2596, widened in AGL-2611).
87
+ *
88
+ * One sentence in one place, because a reader who is refused in the drawer
89
+ * and then reads the list must be told the same thing, and the remedy is the
90
+ * same wherever the refusal lands: a band refuses only on a plan that puts
91
+ * no overage rate past it, so "upgrade" is the whole of the answer.
92
+ */ export const CRM_RECORDS_BAND_FULL_MESSAGE = 'CRM records limit reached — this record was not added. Upgrade in ' + 'Billing to keep collecting.';
93
+ /**
94
+ * The most logged activities ONE record may carry (AGL-2611) — a contact's,
95
+ * a company's or a deal's own log, counted on the link the activity was
96
+ * filed under.
97
+ *
98
+ * A platform ceiling and not a plan dimension, in the family of
99
+ * `WEBHOOK_MAX_PER_HOST` and `NON_PAGE_SCREEN_MAX_PER_HOST`: activities are
100
+ * not in the records band because they are bounded by human effort, and
101
+ * this is the bound. Five thousand is a call a day for fourteen years on one
102
+ * person, so nobody working a real relationship reaches it — what does is
103
+ * an automation logging on every event, or an import replaying a history,
104
+ * and either of those past this line is a document cost with no reader.
105
+ *
106
+ * Enforced where an activity is written: the console's log dialog, the
107
+ * `logCrmActivity` automation step and `POST /v1/activities`, each with one
108
+ * aggregate read on the record's link before the create. The timeline reads
109
+ * a hundred at a time and is untouched by the number.
110
+ */ export const CRM_ACTIVITIES_PER_RECORD_CEILING = 5000;
111
+ /**
112
+ * What every writer says when a record's log is full — the console's log
113
+ * dialog, the automation step's run history and `POST /v1/activities`.
114
+ */ export const CRM_ACTIVITY_LOG_FULL_MESSAGE = `This record already has ${CRM_ACTIVITIES_PER_RECORD_CEILING.toLocaleString('en-US')} activities, which is the most one record can carry.`;
115
+ /**
116
+ * The field the per-record activity ceiling is counted on, or `null` for an
117
+ * activity that names no record at all.
118
+ *
119
+ * The contact leads, then the company, then the deal: an activity logged
120
+ * from a contact's page carries the company beside it (the automation step
121
+ * copies the facet's `companyId` onto every record it creates), and a
122
+ * ceiling counted on the company would let one busy account exhaust every
123
+ * contact filed under it. The record whose PAGE the log is read on is the
124
+ * one whose log has the limit. Shared by the client dialog and the two
125
+ * server writers so they count the same thing.
126
+ */ export function crmActivityCeilingLink(link) {
127
+ if (link.contactId) return {
128
+ field: 'contactId',
129
+ id: String(link.contactId)
130
+ };
131
+ if (link.companyId) return {
132
+ field: 'companyId',
133
+ id: String(link.companyId)
134
+ };
135
+ if (link.dealId) return {
136
+ field: 'dealId',
137
+ id: String(link.dealId)
138
+ };
139
+ // Last, because a converted lead's activities carry the contact beside it
140
+ // and the contact is the record whose page they are read on.
141
+ if (link.leadId) return {
142
+ field: 'leadId',
143
+ id: String(link.leadId)
144
+ };
145
+ return null;
146
+ }
147
+ /**
148
+ * Whether ONE MORE activity fits under `CRM_ACTIVITIES_PER_RECORD_CEILING`.
149
+ * Both halves of the boundary live here so no writer re-derives `>=`.
150
+ */ export function crmActivityLogHasRoom(existing) {
151
+ const count = Number(existing);
152
+ return !(Number.isFinite(count) && count >= CRM_ACTIVITIES_PER_RECORD_CEILING);
153
+ }
154
+ /** How a lifecycle stage reads on screen — typed so a stage cannot ship unlabeled. */ export const CONTACT_LIFECYCLE_STAGE_LABELS = {
155
+ subscriber: 'Subscriber',
156
+ lead: 'Lead',
157
+ 'marketing-qualified': 'Marketing qualified',
158
+ 'sales-qualified': 'Sales qualified',
159
+ opportunity: 'Opportunity',
160
+ customer: 'Customer',
161
+ evangelist: 'Evangelist',
162
+ other: 'Other'
163
+ };
164
+ /**
165
+ * The stage a person is in once a capture has happened that implies at least
166
+ * `floor` (AGL-2612).
167
+ *
168
+ * The one ordering rule every capture door shares: a door names the EARLIEST
169
+ * stage that describes what just happened — a form submission is a lead, a
170
+ * newsletter opt-in is a subscriber, a purchase is a customer — and the
171
+ * result is that stage for a person who had none or an earlier one, and the
172
+ * stage they already had otherwise. "Never downgrades" is the whole contract:
173
+ * a customer who fills in a contact form is still a customer, and `other` —
174
+ * the deliberate stage a business picked for a funnel step none of the names
175
+ * fit — sits after `customer` in the list precisely so no capture can
176
+ * overwrite it. A stored value that is not a stage at all reads as absent,
177
+ * because a capture door is not the place to preserve a typo.
178
+ *
179
+ * With no floor the answer is the current stage as it stands, or `undefined`
180
+ * for one that is absent or unusable — so a writer can apply this
181
+ * unconditionally and write only what comes back.
182
+ */ export function advanceContactLifecycleStage(current, floor) {
183
+ const held = isContactLifecycleStage(current) ? current : undefined;
184
+ if (!floor) return held;
185
+ if (!held) return floor;
186
+ const order = CONTACT_LIFECYCLE_STAGES;
187
+ return order.indexOf(held) < order.indexOf(floor) ? floor : held;
188
+ }
189
+ /**
190
+ * The stage a person is in once they have BOUGHT something (AGL-2596).
191
+ *
192
+ * `customer` when they had no stage or an earlier one; whatever they already
193
+ * had otherwise — {@link advanceContactLifecycleStage} with `customer` as the
194
+ * floor, kept under its own name because "after a purchase" is the question
195
+ * the order paths and the reports ask.
196
+ */ export function contactLifecycleStageAfterPurchase(current) {
197
+ var _advanceContactLifecycleStage;
198
+ return (_advanceContactLifecycleStage = advanceContactLifecycleStage(current, 'customer')) != null ? _advanceContactLifecycleStage : 'customer';
199
+ }
200
+ /** Whether a pipeline has been retired — see {@link CrmPipeline.archivedAt}. */ export function isPipelineArchived(pipeline) {
201
+ return typeof (pipeline == null ? void 0 : pipeline.archivedAt) === 'number' && pipeline.archivedAt > 0;
202
+ }
203
+ /**
204
+ * The stages a fresh pipeline starts with.
205
+ *
206
+ * Readonly on purpose: a pipeline document stores its own COPY (`[...]`), so
207
+ * a merchant editing their stages must not be editing the module's default,
208
+ * and a second pipeline seeded later must start from the original set.
209
+ */ export const DEFAULT_DEAL_STAGES = [
210
+ {
211
+ id: 'qualified',
212
+ name: 'Qualified',
213
+ order: 0,
214
+ probability: 10,
215
+ kind: 'open'
216
+ },
217
+ {
218
+ id: 'contact-made',
219
+ name: 'Contact made',
220
+ order: 1,
221
+ probability: 20,
222
+ kind: 'open'
223
+ },
224
+ {
225
+ id: 'proposal-sent',
226
+ name: 'Proposal sent',
227
+ order: 2,
228
+ probability: 40,
229
+ kind: 'open'
230
+ },
231
+ {
232
+ id: 'negotiation',
233
+ name: 'Negotiation',
234
+ order: 3,
235
+ probability: 60,
236
+ kind: 'open'
237
+ },
238
+ {
239
+ id: 'won',
240
+ name: 'Won',
241
+ order: 4,
242
+ probability: 100,
243
+ kind: 'won'
244
+ },
245
+ {
246
+ id: 'lost',
247
+ name: 'Lost',
248
+ order: 5,
249
+ probability: 0,
250
+ kind: 'lost'
251
+ }
252
+ ];
253
+ /** The most lines one deal carries — a quote, not a catalog. */ export const DEAL_LINE_ITEMS_MAX = 50;
254
+ export const DEAL_LINE_ITEM_NAME_MAX = 120;
255
+ /** Units per line; past this the number is a data-entry slip. */ export const DEAL_LINE_ITEM_QUANTITY_MAX = 1000000;
256
+ export const CRM_TASK_KIND_LABELS = {
257
+ call: 'Call',
258
+ email: 'Email',
259
+ meeting: 'Meeting',
260
+ todo: 'To-do'
261
+ };
262
+ /** How an activity kind reads on screen — typed so a kind cannot ship unlabeled. */ export const CRM_ACTIVITY_KIND_LABELS = {
263
+ call: 'Call',
264
+ email: 'Email',
265
+ meeting: 'Meeting',
266
+ note: 'Note',
267
+ other: 'Other'
268
+ };
269
+ /**
270
+ * Whether a kind takes an outcome and a duration.
271
+ *
272
+ * A call and a meeting are conversations: they end somewhere ("left a
273
+ * voicemail", "agreed to a trial") and they take a measurable amount of
274
+ * time, and both are what a manager reading the log wants to know. An email
275
+ * has neither in any useful sense, a note is not an event at all, and
276
+ * `other` is unknowable — so the dialog hides the two fields for those
277
+ * rather than offering boxes that mean nothing.
278
+ */ export function activityKindHasOutcome(kind) {
279
+ return kind === 'call' || kind === 'meeting';
280
+ }
281
+ /**
282
+ * Where a one-to-one email got to (AGL-2615), in the order it normally
283
+ * happens — the vocabulary the delivery webhook maps its events onto an
284
+ * `email` activity in, and the chip the timeline shows beside the entry.
285
+ *
286
+ * The first four are a progression: a message is sent, then delivered, then
287
+ * opened, then clicked, and a later state implies the earlier ones. The last
288
+ * two are terminal failures. A message the mailbox provider bounced or that
289
+ * the recipient reported is never "opened" in any sense the timeline should
290
+ * report, whatever a tracking pixel says afterwards.
291
+ */ export const CRM_EMAIL_DELIVERY_STATES = [
292
+ 'sent',
293
+ 'delivered',
294
+ 'opened',
295
+ 'clicked',
296
+ 'bounced',
297
+ 'complained'
298
+ ];
299
+ /** How a delivery state reads on the chip — typed so a state cannot ship unlabeled. */ export const CRM_EMAIL_DELIVERY_STATE_LABELS = {
300
+ sent: 'Sent',
301
+ delivered: 'Delivered',
302
+ opened: 'Opened',
303
+ clicked: 'Clicked',
304
+ bounced: 'Bounced',
305
+ complained: 'Marked as spam'
306
+ };
307
+ export function isCrmEmailDeliveryState(value) {
308
+ return typeof value === 'string' && CRM_EMAIL_DELIVERY_STATES.includes(value);
309
+ }
310
+ /** The two states that mean the message did not land. */ export function isCrmEmailDeliveryFailure(state) {
311
+ return state === 'bounced' || state === 'complained';
312
+ }
313
+ /**
314
+ * The rank the webhook advances by. Higher wins; a failure outranks every
315
+ * progression state, and a complaint outranks a bounce because it is the
316
+ * one a sender is scored on.
317
+ */ const CRM_EMAIL_DELIVERY_RANK = {
318
+ sent: 1,
319
+ delivered: 2,
320
+ opened: 3,
321
+ clicked: 4,
322
+ bounced: 5,
323
+ complained: 6
324
+ };
325
+ /**
326
+ * The state an activity holds after one more delivery event, from the state
327
+ * it held before.
328
+ *
329
+ * MONOTONIC. Provider events arrive at least once and in no promised order
330
+ * — an `opened` can reach the webhook before the `delivered` it implies, and
331
+ * a replay can hand back yesterday's `delivered` after today's `clicked` —
332
+ * so the row keeps whichever state is further along, and an event that says
333
+ * less than the row already knows changes nothing. A stored value the
334
+ * vocabulary does not name reads as nothing, so the incoming event stands.
335
+ */ export function nextCrmEmailDeliveryState(current, incoming) {
336
+ if (!isCrmEmailDeliveryState(current)) return incoming;
337
+ return CRM_EMAIL_DELIVERY_RANK[incoming] > CRM_EMAIL_DELIVERY_RANK[current] ? incoming : current;
338
+ }
339
+ /** The most a one-to-one email's subject may hold. */ export const CRM_EMAIL_SUBJECT_MAX = 200;
340
+ /** The most a one-to-one email's body may hold — a letter, not a document. */ export const CRM_EMAIL_BODY_MAX = 10000;
341
+ /**
342
+ * The `context` a one-to-one email is sent under, which `sendEmail` stamps
343
+ * as a provider tag on the message and the delivery log files it by.
344
+ */ export const CRM_EMAIL_CONTEXT = 'crm';
345
+ /** The provider tag naming the activity row a one-to-one email belongs to. */ export const CRM_EMAIL_ACTIVITY_TAG = 'activityId';
346
+ /** The provider tag naming the org whose `crmActivities` holds that row. */ export const CRM_EMAIL_ORG_TAG = 'orgId';
347
+ /** What a provider tag value may be — anything else fails the whole send. */ const PROVIDER_TAG_VALUE = /^[A-Za-z0-9_-]{1,256}$/;
348
+ /**
349
+ * The tags a one-to-one email carries so the delivery webhook can find its
350
+ * activity row (AGL-2615): the org, the activity, and the site for the
351
+ * per-site suppression list a bounce lands on.
352
+ *
353
+ * Every value is checked against the provider's alphabet rather than
354
+ * trusted, for the reason `contextTag` gives — a value the provider rejects
355
+ * fails the send, and a failed send is worse than an untracked one. The
356
+ * org and the activity are the pair the webhook needs, so an unusable
357
+ * value for EITHER yields no tags at all: a tag set that named a row it
358
+ * could not locate would be a promise the timeline cannot keep. The site
359
+ * is stamped when it can be and dropped alone when it cannot.
360
+ */ export function crmEmailDeliveryTags(input) {
361
+ var _input_orgId, _input_activityId, _input_hostId;
362
+ const orgId = String((_input_orgId = input.orgId) != null ? _input_orgId : '');
363
+ const activityId = String((_input_activityId = input.activityId) != null ? _input_activityId : '');
364
+ const hostId = String((_input_hostId = input.hostId) != null ? _input_hostId : '');
365
+ if (!PROVIDER_TAG_VALUE.test(orgId) || !PROVIDER_TAG_VALUE.test(activityId)) {
366
+ return [];
367
+ }
368
+ return [
369
+ {
370
+ name: CRM_EMAIL_ORG_TAG,
371
+ value: orgId
372
+ },
373
+ {
374
+ name: CRM_EMAIL_ACTIVITY_TAG,
375
+ value: activityId
376
+ },
377
+ ...PROVIDER_TAG_VALUE.test(hostId) ? [
378
+ {
379
+ name: 'hostId',
380
+ value: hostId
381
+ }
382
+ ] : []
383
+ ];
384
+ }
385
+ /**
386
+ * The activity row a sent one-to-one email is logged as (AGL-2615).
387
+ *
388
+ * ONE builder for the two writers — the console's send route and the
389
+ * `sendEmail` automation step — so a message a rep wrote and a message a
390
+ * flow sent are the same kind of entry on the timeline: `kind: 'email'`,
391
+ * outbound, starting at `sent` for the delivery webhook to advance. A
392
+ * writer that assembled its own would be the one whose rows the chip did
393
+ * not know how to read. Timestamps are the writer's: a server stamps
394
+ * `serverTimestamp()` and this module has no Firestore.
395
+ */ export function buildCrmEmailActivity(input) {
396
+ var _input_subject, _input_body;
397
+ const { link } = input;
398
+ return _extends({
399
+ kind: 'email',
400
+ subject: String((_input_subject = input.subject) != null ? _input_subject : '').slice(0, CRM_EMAIL_SUBJECT_MAX),
401
+ body: String((_input_body = input.body) != null ? _input_body : '').slice(0, CRM_EMAIL_BODY_MAX),
402
+ to: input.to,
403
+ direction: 'outbound',
404
+ deliveryState: 'sent',
405
+ deliveryAtMs: input.atMs,
406
+ atMs: input.atMs,
407
+ byUid: input.byUid
408
+ }, input.byName ? {
409
+ byName: input.byName
410
+ } : {}, input.sourceActionId ? {
411
+ sourceActionId: input.sourceActionId
412
+ } : {}, link.contactId ? {
413
+ contactId: String(link.contactId)
414
+ } : {}, link.companyId ? {
415
+ companyId: String(link.companyId)
416
+ } : {}, link.dealId ? {
417
+ dealId: String(link.dealId)
418
+ } : {}, link.leadId ? {
419
+ leadId: String(link.leadId)
420
+ } : {}, {
421
+ hostId: input.hostId,
422
+ visibleTo: [
423
+ ...input.visibleTo
424
+ ]
425
+ });
426
+ }
427
+ /**
428
+ * What became of one campaign email, as the words a timeline row prints
429
+ * after the email's name: `sent · delivered · opened ×2 · clicked`.
430
+ *
431
+ * In lifecycle order, and only the states that happened. `sent` is always
432
+ * first because the row exists; the counts appear only past one, because
433
+ * "opened ×1" says nothing "opened" does not. A bounce or a complaint is
434
+ * printed where it falls, after whatever succeeded before it — a message
435
+ * delivered and then complained about reads as both, which is what
436
+ * happened.
437
+ */ export function campaignEmailSummary(email) {
438
+ const counted = (word, count)=>count > 1 ? `${word} ×${count}` : word;
439
+ const parts = [
440
+ 'sent'
441
+ ];
442
+ if (email.deliveredAtMs) parts.push('delivered');
443
+ if (email.openedAtMs) parts.push(counted('opened', email.openCount));
444
+ if (email.clickedAtMs) parts.push(counted('clicked', email.clickCount));
445
+ if (email.bouncedAtMs) parts.push('bounced');
446
+ if (email.complainedAtMs) parts.push('marked as spam');
447
+ return parts;
448
+ }
449
+ /** A time that can be sorted on; anything that is not one sinks to the bottom. */ const sortableMs = (value)=>typeof value === 'number' && Number.isFinite(value) ? value : Number.NEGATIVE_INFINITY;
450
+ /**
451
+ * ONE newest-first stream from a contact's two histories.
452
+ *
453
+ * The captured interactions live on the contact's facet and the logged
454
+ * activities in their own collection, and a page showing them as two lists
455
+ * asks the reader to do the interleaving in their head — "did the call come
456
+ * before or after the order?" is the question a timeline exists to answer.
457
+ *
458
+ * STABLE on purpose. The sort is on `atMs` alone, and at a tie the captured
459
+ * entries keep their place ahead of the logged ones, each in the order it
460
+ * arrived: a facet's interactions are already newest-first and a listener's
461
+ * rows are already ordered, so the merge must not reshuffle what its inputs
462
+ * settled. An entry with no usable time goes LAST, never first — a row that
463
+ * cannot say when it happened must not read as the most recent thing.
464
+ *
465
+ * The key is what a list renders by. A captured interaction has no id of its
466
+ * own, so its key is built from what it does carry; a logged activity's is
467
+ * its document id; a campaign email's is the provider's message id.
468
+ *
469
+ * A campaign email is placed at the instant it was SENT, not at its latest
470
+ * open. The row tells the whole story of that message in one line, and a
471
+ * message that moved up the stream every time its reader re-opened it would
472
+ * be a timeline that reorders itself under the reader.
473
+ */ export function mergeContactTimeline(interactions, activities, campaignEmails) {
474
+ const entries = [
475
+ ...(interactions != null ? interactions : []).map((interaction, index)=>{
476
+ var _interaction_refId;
477
+ return {
478
+ kind: 'captured',
479
+ key: `captured:${interaction.type}:${(_interaction_refId = interaction.refId) != null ? _interaction_refId : index}:${interaction.atMs}:${index}`,
480
+ atMs: interaction.atMs,
481
+ interaction
482
+ };
483
+ }),
484
+ ...(activities != null ? activities : []).map((activity)=>({
485
+ kind: 'logged',
486
+ key: `logged:${activity.$id}`,
487
+ atMs: activity.atMs,
488
+ activity
489
+ })),
490
+ ...(campaignEmails != null ? campaignEmails : []).map((email)=>({
491
+ kind: 'campaign',
492
+ key: `campaign:${email.messageId}`,
493
+ atMs: email.sentAtMs,
494
+ email
495
+ }))
496
+ ];
497
+ // `Array.prototype.sort` is stable, which is what keeps the tie rule above
498
+ // true without a secondary comparison on the entry's kind or position.
499
+ return entries.sort((a, b)=>sortableMs(b.atMs) - sortableMs(a.atMs));
500
+ }
501
+ /**
502
+ * Which record an activity is ABOUT, for a surface that links to it, or
503
+ * `null` when it was filed against nothing.
504
+ *
505
+ * A contact outranks a deal outranks a company. An activity can name all
506
+ * three — a call with a person about a deal at their company — and the
507
+ * contact is the one a reader means when they ask "who was this with"; the
508
+ * deal is next because it is the thing with a clock on it; the company is
509
+ * the widest and so the last resort.
510
+ */ export function crmActivityRecordLink(activity) {
511
+ if (activity.contactId) return {
512
+ record: 'contact',
513
+ id: activity.contactId
514
+ };
515
+ if (activity.dealId) return {
516
+ record: 'deal',
517
+ id: activity.dealId
518
+ };
519
+ if (activity.companyId) return {
520
+ record: 'company',
521
+ id: activity.companyId
522
+ };
523
+ // A lead is the narrowest: once converted, the contact it became leads.
524
+ if (activity.leadId) return {
525
+ record: 'lead',
526
+ id: activity.leadId
527
+ };
528
+ return null;
529
+ }
530
+ const MINUTE_MS = 60000;
531
+ const HOUR_MS = 60 * MINUTE_MS;
532
+ const DAY_MS = 24 * HOUR_MS;
533
+ /**
534
+ * How long ago something happened, in the words a list row uses.
535
+ *
536
+ * Coarse on purpose. A row reads "3 days ago" and carries the full timestamp
537
+ * in its tooltip; the sentence exists so that a reader scanning a log can
538
+ * tell this week from last month without parsing dates. Past a week the
539
+ * relative form stops helping — "412 days ago" is a date the reader has to
540
+ * compute — so it becomes one. A time AHEAD of now is a date too: a call
541
+ * logged for tomorrow is a scheduling mistake the page should show plainly
542
+ * rather than dress as "in 14 hours". An unusable time reads as nothing.
543
+ *
544
+ * English rather than `Intl.RelativeTimeFormat` because the console is
545
+ * English-only, and the thresholds are what the spec pins.
546
+ */ export function activityTimeLabel(atMs, nowMs) {
547
+ if (!Number.isFinite(atMs) || !Number.isFinite(nowMs)) return '';
548
+ const elapsed = nowMs - atMs;
549
+ if (elapsed < -MINUTE_MS || elapsed >= 7 * DAY_MS) {
550
+ return new Date(atMs).toLocaleDateString();
551
+ }
552
+ if (elapsed < MINUTE_MS) return 'just now';
553
+ if (elapsed < HOUR_MS) return `${Math.floor(elapsed / MINUTE_MS)} min ago`;
554
+ if (elapsed < DAY_MS) return `${Math.floor(elapsed / HOUR_MS)} h ago`;
555
+ if (elapsed < 2 * DAY_MS) return 'yesterday';
556
+ return `${Math.floor(elapsed / DAY_MS)} days ago`;
557
+ }
558
+ /**
559
+ * The records a custom field may describe, in the order the Fields
560
+ * section tabs them (AGL-2661).
561
+ */ export const CRM_FIELD_OBJECTS = [
562
+ 'contact',
563
+ 'company',
564
+ 'deal'
565
+ ];
566
+ /** How each object reads on the Fields section's tabs and in a refusal. */ export const CRM_FIELD_OBJECT_LABELS = {
567
+ contact: 'Contacts',
568
+ company: 'Companies',
569
+ deal: 'Deals'
570
+ };
571
+ export function isCrmFieldObject(value) {
572
+ return typeof value === 'string' && CRM_FIELD_OBJECTS.includes(value);
573
+ }
574
+ /**
575
+ * Which record a definition describes — `contact` when the document says
576
+ * nothing, or says something no reader understands.
577
+ *
578
+ * The one reader of {@link ContactFieldDefinition.object}. A stored value
579
+ * outside the list is read as `contact` rather than refused, for the
580
+ * reason an absent one is: the definition predates the field, or was
581
+ * written by something that never learned it, and either way the values
582
+ * under its key sit on contacts.
583
+ */ export function fieldDefinitionObject(definition) {
584
+ return isCrmFieldObject(definition == null ? void 0 : definition.object) ? definition.object : 'contact';
585
+ }
586
+ /** What a stored field key must look like — a letter, then up to 39 of `[a-z0-9_]`. */ export const CONTACT_FIELD_KEY_PATTERN = /^[a-z][a-z0-9_]{0,39}$/;
587
+ /**
588
+ * A typed label, as the key it would be stored under, or `null` when nothing
589
+ * usable survives.
590
+ *
591
+ * Lowercased and snake-cased rather than refused, because the key is derived
592
+ * from the label a merchant typed ("Annual revenue" → `annual_revenue`) and
593
+ * they should not have to learn the grammar. Anything outside `[a-z0-9_]` is
594
+ * dropped after separators become underscores, runs collapse, and a leading
595
+ * run of digits or underscores goes — a key has to start with a letter so it
596
+ * can never collide with an array index or read as a number in a filter.
597
+ */ export function normalizeContactFieldKey(input) {
598
+ const key = String(input != null ? input : '').trim().toLowerCase().replace(/[\s-]+/g, '_').replace(/[^a-z0-9_]/g, '').replace(/_+/g, '_').replace(/^[^a-z]+/, '').replace(/_+$/, '').slice(0, 40);
599
+ return CONTACT_FIELD_KEY_PATTERN.test(key) ? key : null;
600
+ }
601
+ /** The stage a deal is in, or `null` when the pipeline no longer has it. */ export function dealStageById(pipeline, stageId) {
602
+ var _ref;
603
+ var _pipeline_stages;
604
+ return (_ref = pipeline == null ? void 0 : (_pipeline_stages = pipeline.stages) == null ? void 0 : _pipeline_stages.find((stage)=>stage.id === stageId)) != null ? _ref : null;
605
+ }
606
+ /**
607
+ * What a deal is worth to a forecast, in cents.
608
+ *
609
+ * STATUS wins over the stage. A deal marked won is worth its full amount
610
+ * whatever stage it happens to sit in, and a lost one is worth nothing —
611
+ * the stage's probability is the odds of an OPEN deal, and applying it to a
612
+ * closed one would forecast a sale that has already happened as a fraction
613
+ * of itself. An open deal with no resolvable stage is worth nothing rather
614
+ * than everything: the pipeline lost the stage, and a forecast that filled
615
+ * the gap with 100% would be the most optimistic number available.
616
+ */ export function weightedDealAmountCents(deal, stage) {
617
+ var _deal_amountCents;
618
+ const amount = Math.max(0, Math.round(Number((_deal_amountCents = deal.amountCents) != null ? _deal_amountCents : 0) || 0));
619
+ if (deal.status === 'won') return amount;
620
+ if (deal.status === 'lost' || !stage) return 0;
621
+ const probability = Math.min(100, Math.max(0, Number(stage.probability) || 0));
622
+ return Math.round(amount * probability / 100);
623
+ }
624
+ /** Whether a deal's amount is derived — it has at least one line item. */ export function dealHasLineItems(deal) {
625
+ return Array.isArray(deal == null ? void 0 : deal.lineItems) && deal.lineItems.length > 0;
626
+ }
627
+ /**
628
+ * What a set of line items adds up to, in cents — the amount a deal with
629
+ * line items stores. Whole cents, never negative: a line's quantity and
630
+ * unit amount have both been through `readDealLineItems`, but a stored
631
+ * document from an older writer is trusted no further than that.
632
+ */ export function lineItemsTotalCents(items) {
633
+ let total = 0;
634
+ for (const item of items != null ? items : []){
635
+ const quantity = Math.max(0, Math.round(Number(item.quantity) || 0));
636
+ const unit = Math.max(0, Math.round(Number(item.unitAmountCents) || 0));
637
+ total += quantity * unit;
638
+ }
639
+ return total;
640
+ }
641
+ /**
642
+ * Line items as a client typed or sent them, validated into the stored
643
+ * shape, or the one reason they were refused.
644
+ *
645
+ * The one reader for both writers — the products card on a deal's page
646
+ * and `POST`/`PATCH /v1/deals` — so a line the console accepts is a line
647
+ * the API accepts and the other way round. The rules: at most
648
+ * {@link DEAL_LINE_ITEMS_MAX} lines; every line a name, a whole quantity
649
+ * of one or more, a whole unit amount of zero or more; every line in the
650
+ * DEAL's currency (`currency`), which a line may omit and may not
651
+ * contradict. An empty list is valid and means "no line items" — the
652
+ * amount goes back to being typed.
653
+ */ export function readDealLineItems(input, currency) {
654
+ if (input === undefined || input === null) return {
655
+ items: []
656
+ };
657
+ if (!Array.isArray(input)) return {
658
+ error: 'Line items must be a list'
659
+ };
660
+ if (input.length > DEAL_LINE_ITEMS_MAX) {
661
+ return {
662
+ error: `A deal carries at most ${DEAL_LINE_ITEMS_MAX} line items`
663
+ };
664
+ }
665
+ const dealCurrency = String(currency || 'usd').trim().toLowerCase();
666
+ const items = [];
667
+ for (const [index, raw] of input.entries()){
668
+ var _line_name;
669
+ const at = `Line ${index + 1}`;
670
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
671
+ return {
672
+ error: `${at} must be an object`
673
+ };
674
+ }
675
+ const line = raw;
676
+ const name = String((_line_name = line.name) != null ? _line_name : '').trim().slice(0, DEAL_LINE_ITEM_NAME_MAX);
677
+ if (!name) return {
678
+ error: `${at} needs a name`
679
+ };
680
+ const quantity = Number(line.quantity);
681
+ if (!Number.isInteger(quantity) || quantity < 1 || quantity > DEAL_LINE_ITEM_QUANTITY_MAX) {
682
+ return {
683
+ error: `${at}: the quantity must be a whole number from 1 to ${DEAL_LINE_ITEM_QUANTITY_MAX.toLocaleString()}`
684
+ };
685
+ }
686
+ const unitAmountCents = Number(line.unitAmountCents);
687
+ if (!Number.isInteger(unitAmountCents) || unitAmountCents < 0) {
688
+ return {
689
+ error: `${at}: the unit amount must be a whole number of cents, 0 or more`
690
+ };
691
+ }
692
+ const lineCurrency = line.currency === undefined || line.currency === null || line.currency === '' ? dealCurrency : String(line.currency).trim().toLowerCase();
693
+ if (lineCurrency !== dealCurrency) {
694
+ return {
695
+ error: `${at} is in ${lineCurrency.toUpperCase()}; every line must be in the deal's currency, ${dealCurrency.toUpperCase()}`
696
+ };
697
+ }
698
+ const productId = typeof line.productId === 'string' && line.productId.trim() ? line.productId.trim().slice(0, 200) : undefined;
699
+ items.push(_extends({}, productId ? {
700
+ productId
701
+ } : {}, {
702
+ name,
703
+ quantity,
704
+ unitAmountCents,
705
+ currency: dealCurrency
706
+ }));
707
+ }
708
+ return {
709
+ items
710
+ };
711
+ }
712
+ /**
713
+ * Where a task stands against the clock.
714
+ *
715
+ * `today` is decided on the LOCAL calendar day and beats `overdue`: a task
716
+ * due at nine this morning is today's work until midnight, not something the
717
+ * list should paint red at 9:01. Overdue is yesterday or earlier. `done`
718
+ * comes first because a completed task's due date is history whichever side
719
+ * of now it fell on.
720
+ */ export function taskDueState(task, nowMs) {
721
+ if (task.status === 'done') return 'done';
722
+ const dueAtMs = task.dueAtMs;
723
+ if (typeof dueAtMs !== 'number' || !Number.isFinite(dueAtMs)) return 'none';
724
+ const due = new Date(dueAtMs);
725
+ const now = new Date(nowMs);
726
+ const sameDay = due.getFullYear() === now.getFullYear() && due.getMonth() === now.getMonth() && due.getDate() === now.getDate();
727
+ if (sameDay) return 'today';
728
+ return dueAtMs < nowMs ? 'overdue' : 'upcoming';
729
+ }
730
+ /**
731
+ * A hostname label: `[a-z0-9-]`, not starting or ending with a hyphen, at
732
+ * most 63 characters — RFC 1123 as far as a company domain needs it.
733
+ */ const DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
734
+ /**
735
+ * A typed or pasted domain, reduced to the bare lowercase hostname a company
736
+ * is keyed by, or `null` when what is left is not one.
737
+ *
738
+ * Strips what people paste along with a domain — the protocol, a `www.`, a
739
+ * path, a query, a port — because the value is a KEY: two contacts at
740
+ * `https://www.acme.com/about` and `acme.com` work for one company, and the
741
+ * match is only findable if both reduce to the same string. The last label
742
+ * has to be letters because a company's domain has a TLD; a bare IP address
743
+ * or a single word is not one and answers `null` rather than being stored as
744
+ * something a later match will never hit.
745
+ */ export function normalizeCompanyDomain(input) {
746
+ let value = String(input != null ? input : '').trim().toLowerCase();
747
+ if (!value) return null;
748
+ value = value.replace(/^[a-z][a-z0-9+.-]*:\/\//, '');
749
+ value = value.replace(/^www\./, '');
750
+ value = value.split(/[/?#]/, 1)[0];
751
+ value = value.split(':', 1)[0];
752
+ value = value.replace(/\.+$/, '');
753
+ if (!value || value.length > 253) return null;
754
+ const labels = value.split('.');
755
+ if (labels.length < 2) return null;
756
+ if (!labels.every((label)=>DOMAIN_LABEL.test(label))) return null;
757
+ if (!/^[a-z]{2,}$/.test(labels[labels.length - 1])) return null;
758
+ return value;
759
+ }
760
+ /** The longest website URL a company stores. */ const COMPANY_WEBSITE_MAX = 500;
761
+ /**
762
+ * The typed website, as a URL; `''` for a blank; `null` when it cannot be
763
+ * one.
764
+ *
765
+ * People type `acme.com` where a URL is asked for, and refusing that is
766
+ * pedantry — it becomes `https://acme.com`. What IS refused is anything the
767
+ * URL parser cannot read or a scheme other than http(s): a `javascript:` link
768
+ * on a record that renders as an anchor is not a website. One function for
769
+ * the company drawer and the companies import, so a website typed and a
770
+ * website imported are stored the same way.
771
+ */ export function normalizeCompanyWebsite(input) {
772
+ const raw = String(input != null ? input : '').trim();
773
+ if (!raw) return '';
774
+ const candidate = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw) ? raw : `https://${raw}`;
775
+ try {
776
+ const url = new URL(candidate);
777
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
778
+ return url.href.length > COMPANY_WEBSITE_MAX ? null : url.href;
779
+ } catch (unused) {
780
+ return null;
781
+ }
782
+ }
783
+ /**
784
+ * Mailbox domains that belong to people rather than to a business: the
785
+ * providers anybody can sign up with, and the ones an internet provider
786
+ * hands its subscribers.
787
+ *
788
+ * Auto-associating a contact with a company by email domain is the whole
789
+ * reason {@link companyDomainForEmail} exists, and it is wrong for every
790
+ * address at a public mailbox: `gmail.com` is not a company, and a rule
791
+ * that treated it as one would file half of a consumer list under a single
792
+ * phantom account. It is also the fact a cold email has to know — an
793
+ * address here is a person's own, not their work address — which is why the
794
+ * list is exported with {@link isPublicMailboxDomain}: a second list kept
795
+ * for that question would drift from this one.
796
+ *
797
+ * Exact domains, not suffixes: a subscriber's regional host (`nc.rr.com`)
798
+ * is not listed, and neither is a company that happens to end in `mail.com`.
799
+ */ export const PUBLIC_MAILBOX_DOMAINS = new Set([
800
+ // Google, Yahoo, Microsoft, Apple, AOL.
801
+ 'gmail.com',
802
+ 'googlemail.com',
803
+ 'yahoo.com',
804
+ 'yahoo.co.uk',
805
+ 'yahoo.ca',
806
+ 'yahoo.com.au',
807
+ 'yahoo.co.in',
808
+ 'yahoo.fr',
809
+ 'yahoo.de',
810
+ 'ymail.com',
811
+ 'rocketmail.com',
812
+ 'hotmail.com',
813
+ 'hotmail.co.uk',
814
+ 'hotmail.fr',
815
+ 'hotmail.de',
816
+ 'hotmail.it',
817
+ 'outlook.com',
818
+ 'live.com',
819
+ 'live.co.uk',
820
+ 'live.ca',
821
+ 'msn.com',
822
+ 'icloud.com',
823
+ 'me.com',
824
+ 'mac.com',
825
+ 'aol.com',
826
+ 'aim.com',
827
+ // Independent and privacy-first providers.
828
+ 'proton.me',
829
+ 'protonmail.com',
830
+ 'protonmail.ch',
831
+ 'pm.me',
832
+ 'tutanota.com',
833
+ 'tuta.io',
834
+ 'hushmail.com',
835
+ 'gmx.com',
836
+ 'gmx.net',
837
+ 'gmx.de',
838
+ 'web.de',
839
+ 'mail.com',
840
+ 'yandex.com',
841
+ 'yandex.ru',
842
+ 'zoho.com',
843
+ 'zohomail.com',
844
+ 'fastmail.com',
845
+ 'hey.com',
846
+ // The largest consumer providers outside the US and Europe.
847
+ 'qq.com',
848
+ '163.com',
849
+ '126.com',
850
+ 'sina.com',
851
+ 'naver.com',
852
+ 'hanmail.net',
853
+ 'rediffmail.com',
854
+ // US internet providers' subscriber mailboxes.
855
+ 'comcast.net',
856
+ 'att.net',
857
+ 'sbcglobal.net',
858
+ 'bellsouth.net',
859
+ 'pacbell.net',
860
+ 'verizon.net',
861
+ 'cox.net',
862
+ 'charter.net',
863
+ 'earthlink.net',
864
+ 'optonline.net',
865
+ 'frontier.com',
866
+ 'windstream.net',
867
+ 'centurylink.net',
868
+ 'juno.com',
869
+ 'netzero.net',
870
+ // Subscriber mailboxes at the largest providers in Canada, the UK, France,
871
+ // Germany, Italy and Australia.
872
+ 'shaw.ca',
873
+ 'sympatico.ca',
874
+ 'btinternet.com',
875
+ 'sky.com',
876
+ 'virginmedia.com',
877
+ 'orange.fr',
878
+ 'free.fr',
879
+ 'laposte.net',
880
+ 't-online.de',
881
+ 'libero.it',
882
+ 'bigpond.com'
883
+ ]);
884
+ /**
885
+ * Whether a domain — or the domain of an address — is one of the
886
+ * {@link PUBLIC_MAILBOX_DOMAINS}. Read the way a company domain is, so case,
887
+ * a trailing dot and a pasted `www.` do not hide one.
888
+ */ export function isPublicMailboxDomain(domainOrEmail) {
889
+ const value = String(domainOrEmail != null ? domainOrEmail : '').trim();
890
+ const domain = normalizeCompanyDomain(value.slice(value.lastIndexOf('@') + 1));
891
+ return domain !== null && PUBLIC_MAILBOX_DOMAINS.has(domain);
892
+ }
893
+ /**
894
+ * The company domain an email address implies, or `null` when it implies
895
+ * none — a malformed address, or one at a public mailbox provider.
896
+ */ export function companyDomainForEmail(email) {
897
+ const value = String(email != null ? email : '').trim().toLowerCase();
898
+ const at = value.lastIndexOf('@');
899
+ if (at < 1 || at === value.length - 1) return null;
900
+ if (/[\s@]/.test(value.slice(0, at))) return null;
901
+ const domain = normalizeCompanyDomain(value.slice(at + 1));
902
+ if (!domain || PUBLIC_MAILBOX_DOMAINS.has(domain)) return null;
903
+ return domain;
904
+ }
905
+ /**
906
+ * The name a company minted from a domain starts with: the first label with
907
+ * a capital — `acme.com` → `Acme`, `initech.co.uk` → `Initech`.
908
+ *
909
+ * A starting point and not a claim about what the business is called: the
910
+ * lead-convert dialog offers it for editing, and a company the capture door
911
+ * creates on its own carries it until somebody renames the record. The
912
+ * domain itself would be an honest name too, but a list of companies that
913
+ * reads `acme.com`, `globex.example` looks like a list of websites, and the
914
+ * domain is on the row beside the name anyway.
915
+ */ export function companyNameForDomain(domain) {
916
+ const label = domain.split('.')[0] || domain;
917
+ return label.charAt(0).toUpperCase() + label.slice(1);
918
+ }
919
+ /*==========================================
920
+ * THE CONTACT–COMPANY LINK (AGL-2597, AGL-2613).
921
+ *
922
+ * The association proper is `facets.{groupId}.companyId` — one company per
923
+ * holder, inside that holder's facet like the notes and the tags, and for
924
+ * the same reason: which account a person belongs to is one business's
925
+ * knowledge of them. But a facet path is per group, and Firestore cannot
926
+ * answer "every contact whose facet, whichever group's, names company X" —
927
+ * a `where` needs one field path, and the group id is part of the path. So
928
+ * the facet is MIRRORED into a top-level array an `array-contains` can
929
+ * query, and the company carries a COUNT of the contacts whose mirror names
930
+ * it, so a list of companies can say how many people are at each without
931
+ * reading a person.
932
+ *
933
+ * Three fields, kept in step by ONE planner. Every writer — the picker on a
934
+ * contact's page, the company page's link control, the bulk bar, the server
935
+ * doors that link on capture — asks {@link planContactCompanyLink} what
936
+ * changes and applies the answer with its own SDK's sentinels. None of them
937
+ * decides for itself whether the old id leaves the mirror, which is the rule
938
+ * a second copy would get wrong: another business filing the same person
939
+ * under the same account is THEIR link, and this holder letting go must not
940
+ * take it away.
941
+ *=========================================*/ /**
942
+ * The top-level field on a CONTACT naming every company it is linked to.
943
+ *
944
+ * It carries the union of every holder's link, so removing an id from it is
945
+ * only correct when no other holder's facet still names that id — the rule
946
+ * the planner enforces, and the reason nothing writes this field without
947
+ * going through it. The facet is the truth and this is its index: a reader
948
+ * answering "which company is this person at" reads the facet; only a QUERY
949
+ * reads this.
950
+ */ export const CONTACT_COMPANY_IDS_FIELD = 'companyIds';
951
+ /**
952
+ * The field on a COMPANY counting the contacts whose mirror names it.
953
+ *
954
+ * Denormalized because the honest figure is an aggregate over every contact
955
+ * in the org, which a list of two hundred companies cannot afford to take
956
+ * per row. Moved by `increment` in the same batch as the link that changes
957
+ * it, so the two cannot disagree by a failed second write; a company's own
958
+ * page still takes the live aggregate, which is what corrects a count that
959
+ * predates the counter.
960
+ */ export const COMPANY_CONTACTS_COUNT_FIELD = 'contactsCount';
961
+ /** The link state of a stored contact, read for one holder. */ export function readContactCompanyLink(contact, groupId) {
962
+ var _readContactFacet_companyId;
963
+ const document = contact != null ? contact : {};
964
+ const facets = document[CONTACT_FACETS_FIELD];
965
+ const heldElsewhere = new Set();
966
+ if (facets && typeof facets === 'object' && !Array.isArray(facets)) {
967
+ for (const [holder, facet] of Object.entries(facets)){
968
+ if (holder === groupId) continue;
969
+ const named = facet && typeof facet === 'object' && !Array.isArray(facet) ? facet['companyId'] : undefined;
970
+ if (typeof named === 'string' && named) heldElsewhere.add(named);
971
+ }
972
+ }
973
+ const mirror = document[CONTACT_COMPANY_IDS_FIELD];
974
+ return {
975
+ companyId: (_readContactFacet_companyId = readContactFacet(document, groupId).companyId) != null ? _readContactFacet_companyId : null,
976
+ companyIds: Array.isArray(mirror) ? mirror.filter((id)=>typeof id === 'string' && !!id) : [],
977
+ heldElsewhere: [
978
+ ...heldElsewhere
979
+ ]
980
+ };
981
+ }
982
+ /**
983
+ * Every holder whose facet names this company, in no order.
984
+ *
985
+ * What a company's DELETION clears. Unlike a link change, which is one
986
+ * holder's, a deletion takes the record away from every holder at once: a
987
+ * facet still naming it would be a link to nothing, on a surface its holder
988
+ * has no reason to revisit. Nothing else about another holder's facet is
989
+ * read.
990
+ */ export function contactGroupsNamingCompany(contact, companyId) {
991
+ const facets = (contact != null ? contact : {})[CONTACT_FACETS_FIELD];
992
+ if (!companyId || !facets || typeof facets !== 'object' || Array.isArray(facets)) {
993
+ return [];
994
+ }
995
+ return Object.entries(facets).filter(([, facet])=>Boolean(facet && typeof facet === 'object' && !Array.isArray(facet) && facet['companyId'] === companyId)).map(([groupId])=>groupId);
996
+ }
997
+ /**
998
+ * What linking a contact to a company FOR ONE HOLDER changes — or unlinking
999
+ * them, with `null`. `null` when the document already says what was asked.
1000
+ *
1001
+ * Three cases, and the mirror is handled differently in each because it is
1002
+ * shared across holders while the facet is not:
1003
+ *
1004
+ * - A first link `union`s the id in, which is safe against a concurrent
1005
+ * writer adding another holder's id.
1006
+ * - A MOVE from one company to another rewrites the mirror as a whole. The
1007
+ * old id is dropped only if no other holder's facet still names it.
1008
+ * - An unlink `remove`s the old id, on the same condition, and leaves the
1009
+ * mirror alone when another holder still needs it there.
1010
+ *
1011
+ * The counts follow the mirror, not the facet: the company's figure is "how
1012
+ * many contacts name me in the mirror", and that is the quantity the
1013
+ * company page's live aggregate measures.
1014
+ */ export function planContactCompanyLink(state, companyId) {
1015
+ const previous = state.companyId;
1016
+ if (previous === companyId) return null;
1017
+ const mirror = new Set(state.companyIds);
1018
+ const previousLeaves = previous !== null && !state.heldElsewhere.includes(previous);
1019
+ const counts = [];
1020
+ let change = null;
1021
+ if (companyId && !previous) {
1022
+ change = {
1023
+ op: 'union',
1024
+ companyId
1025
+ };
1026
+ if (!mirror.has(companyId)) counts.push({
1027
+ companyId,
1028
+ delta: 1
1029
+ });
1030
+ } else if (companyId && previous) {
1031
+ const kept = state.companyIds.filter((id)=>id !== previous || !previousLeaves);
1032
+ change = {
1033
+ op: 'set',
1034
+ companyIds: [
1035
+ ...new Set([
1036
+ ...kept,
1037
+ companyId
1038
+ ])
1039
+ ]
1040
+ };
1041
+ if (previousLeaves && mirror.has(previous)) {
1042
+ counts.push({
1043
+ companyId: previous,
1044
+ delta: -1
1045
+ });
1046
+ }
1047
+ if (!mirror.has(companyId)) counts.push({
1048
+ companyId,
1049
+ delta: 1
1050
+ });
1051
+ } else if (previous && previousLeaves) {
1052
+ change = {
1053
+ op: 'remove',
1054
+ companyId: previous
1055
+ };
1056
+ if (mirror.has(previous)) counts.push({
1057
+ companyId: previous,
1058
+ delta: -1
1059
+ });
1060
+ }
1061
+ return {
1062
+ companyId,
1063
+ mirror: change,
1064
+ counts
1065
+ };
1066
+ }
1067
+ /*==========================================
1068
+ * THE CRM's ORGANIZATION SETTINGS (AGL-2613).
1069
+ *
1070
+ * One map under `crm` on the org document, so the CRM → Settings section
1071
+ * can grow a key per setting without a rules change each time: the org
1072
+ * document's client branch is a deny-list, and `crm` is declared
1073
+ * client-writable in `ORG_CLIENT_WRITABLE_FIELDS` with its reason.
1074
+ *=========================================*/ /** The org-document key the CRM's settings live under. */ export const ORG_CRM_SETTINGS_FIELD = 'crm';
1075
+ /** The dotted path an `update()` writes the auto-create switch by. */ export const CRM_AUTO_CREATE_COMPANIES_PATH = `${ORG_CRM_SETTINGS_FIELD}.autoCreateCompanies`;
1076
+ /**
1077
+ * Whether a capture from a work email domain no visible company carries
1078
+ * should CREATE the company. Off unless the org document says `true`: a
1079
+ * company minted from every domain that ever submitted a form is a list
1080
+ * nobody asked for, so the default is the quiet one.
1081
+ *
1082
+ * Read off the raw document rather than a typed field, because the capture
1083
+ * door holds a `Partial<AglynOrganization>` and the console a
1084
+ * `Partial<AglynOrgBilling>`, and one reader has to answer both.
1085
+ */ export function orgAutoCreatesCompanies(orgDocument) {
1086
+ const settings = (orgDocument != null ? orgDocument : {})[ORG_CRM_SETTINGS_FIELD];
1087
+ return Boolean(settings && typeof settings === 'object' && !Array.isArray(settings) && settings['autoCreateCompanies'] === true);
1088
+ }
1089
+ /*==========================================
1090
+ * WHO A NEW RECORD BELONGS TO (AGL-2618).
1091
+ *
1092
+ * Salesforce calls these assignment rules and HubSpot rotates to an owner;
1093
+ * either way they are the first thing a sales team configures, because a
1094
+ * record with no owner is one nobody follows up. The shape here is what the
1095
+ * CRM → Settings section writes onto the org document under `crm`, what the
1096
+ * capture door's assignment pass reads, and what the `assignContactOwner`
1097
+ * automation step's round-robin mode reads — one vocabulary, three readers.
1098
+ *
1099
+ * ## The order of decision
1100
+ *
1101
+ * The rules are tried in their stored order and the FIRST match assigns; a
1102
+ * rule that names a member the roster no longer has, or a round-robin rule
1103
+ * over an empty pool, is passed over rather than stopping the pass. When no
1104
+ * rule claims the capture, the capturing site's default owner does; when
1105
+ * the site has none, the record stays unassigned, which is what the product
1106
+ * did before any of this existed and is the honest answer to "nobody has
1107
+ * said".
1108
+ *
1109
+ * ## Only a record with no owner
1110
+ *
1111
+ * The capture pass runs when a record is CREATED and never overwrites an
1112
+ * owner: a door that named one (the console's drawer, an import column, a
1113
+ * conversion with a picked owner) has expressed a person's choice, and a
1114
+ * returning visitor's contact already belongs to somebody. The automation
1115
+ * step is the deliberate exception — an author who put "assign an owner"
1116
+ * on a stage change means to reassign.
1117
+ *
1118
+ * ## Why the pointer is a uid, and why the server moves it
1119
+ *
1120
+ * See `OrgCrmRoundRobin`. The pool is edited in the console and the pointer
1121
+ * is advanced by the Admin SDK inside the transaction that writes the owner,
1122
+ * so concurrent captures take distinct turns and an edit to the pool never
1123
+ * skips or repeats a member.
1124
+ *=========================================*/ /** Where the ordered rules live on the org document. */ export const CRM_ASSIGNMENT_RULES_PATH = `${ORG_CRM_SETTINGS_FIELD}.assignmentRules`;
1125
+ /** The round-robin pool's member list, in rotation order. */ export const CRM_ROUND_ROBIN_POOL_PATH = `${ORG_CRM_SETTINGS_FIELD}.roundRobin.memberUids`;
1126
+ /** The member handed the most recent round-robin record. */ export const CRM_ROUND_ROBIN_LAST_ASSIGNED_PATH = `${ORG_CRM_SETTINGS_FIELD}.roundRobin.lastAssignedUid`;
1127
+ /**
1128
+ * The most rules an org may keep. A first-match list longer than this is
1129
+ * one nobody can reason about, and the section refuses the fifty-first
1130
+ * rather than letting the document grow unbounded.
1131
+ */ export const CRM_ASSIGNMENT_RULES_MAX = 50;
1132
+ /** The most members a round-robin pool may hold. */ export const CRM_ROUND_ROBIN_POOL_MAX = 50;
1133
+ /**
1134
+ * The map of per-site CRM settings under `crm` on the ORG document, keyed
1135
+ * by host id. A field on the org, not a subcollection of the host: the
1136
+ * host-subcollection guards read a quoted `'hosts'` beside a site id as a
1137
+ * client path under `hosts/{hostId}`, which this is not, so the key is
1138
+ * named here and spelled nowhere else.
1139
+ */ const CRM_HOST_SETTINGS_KEY = 'hosts';
1140
+ /**
1141
+ * The field-path SEGMENTS of a site's default owner on the org document.
1142
+ *
1143
+ * Segments rather than a dotted string, because the host id is a document
1144
+ * id and a document id may contain a dot; joined with dots it would be read
1145
+ * as two path elements and the write would land beside the setting rather
1146
+ * than in it. A caller builds a `FieldPath` from these on either SDK.
1147
+ */ export function crmHostDefaultOwnerSegments(hostId) {
1148
+ if (!hostId) throw new Error('a site default owner must name a site');
1149
+ return [
1150
+ ORG_CRM_SETTINGS_FIELD,
1151
+ CRM_HOST_SETTINGS_KEY,
1152
+ hostId,
1153
+ 'defaultOwnerUid'
1154
+ ];
1155
+ }
1156
+ function isContactSourceValue(value) {
1157
+ return typeof value === 'string' && value in CONTACT_SOURCE_LABELS;
1158
+ }
1159
+ function cleanText(value, max) {
1160
+ const text = typeof value === 'string' ? value.trim().slice(0, max) : '';
1161
+ return text || undefined;
1162
+ }
1163
+ /** A rule as the document holds it, or `null` for one that cannot assign. */ export function readCrmAssignmentRule(raw) {
1164
+ var _whenRaw_emailDomain;
1165
+ var _cleanText;
1166
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
1167
+ const entry = raw;
1168
+ const id = cleanText(entry['id'], 64);
1169
+ if (!id) return null;
1170
+ const whenRaw = entry['when'] && typeof entry['when'] === 'object' && !Array.isArray(entry['when']) ? entry['when'] : {};
1171
+ const when = {};
1172
+ if (isContactSourceValue(whenRaw['source'])) when.source = whenRaw['source'];
1173
+ const formId = cleanText(whenRaw['formId'], 128);
1174
+ if (formId) when.formId = formId;
1175
+ // A person types a domain the way they see one in an address — `@acme.com`
1176
+ // — so the `@` is what the field means, not part of the domain.
1177
+ const emailDomain = normalizeCompanyDomain(String((_whenRaw_emailDomain = whenRaw['emailDomain']) != null ? _whenRaw_emailDomain : '').trim().replace(/^@/, ''));
1178
+ if (emailDomain) when.emailDomain = emailDomain;
1179
+ const tag = (_cleanText = cleanText(whenRaw['tag'], 60)) == null ? void 0 : _cleanText.toLowerCase();
1180
+ if (tag) when.tag = tag;
1181
+ const assignRaw = entry['assign'] && typeof entry['assign'] === 'object' && !Array.isArray(entry['assign']) ? entry['assign'] : null;
1182
+ if (!assignRaw) return null;
1183
+ if (assignRaw['roundRobin'] === true) {
1184
+ return {
1185
+ id,
1186
+ when,
1187
+ assign: {
1188
+ roundRobin: true
1189
+ }
1190
+ };
1191
+ }
1192
+ const memberUid = cleanText(assignRaw['memberUid'], 128);
1193
+ return memberUid ? {
1194
+ id,
1195
+ when,
1196
+ assign: {
1197
+ memberUid
1198
+ }
1199
+ } : null;
1200
+ }
1201
+ export function readCrmAssignmentSettings(orgDocument) {
1202
+ var _cleanText;
1203
+ const settings = (orgDocument != null ? orgDocument : {})[ORG_CRM_SETTINGS_FIELD];
1204
+ const crm = settings && typeof settings === 'object' && !Array.isArray(settings) ? settings : {};
1205
+ const rules = (Array.isArray(crm['assignmentRules']) ? crm['assignmentRules'] : []).map(readCrmAssignmentRule).filter((rule)=>rule !== null).slice(0, CRM_ASSIGNMENT_RULES_MAX);
1206
+ const roundRobin = crm['roundRobin'] && typeof crm['roundRobin'] === 'object' ? crm['roundRobin'] : {};
1207
+ const memberUids = [
1208
+ ...new Set((Array.isArray(roundRobin['memberUids']) ? roundRobin['memberUids'] : []).map((uid)=>cleanText(uid, 128)).filter((uid)=>Boolean(uid)))
1209
+ ].slice(0, CRM_ROUND_ROBIN_POOL_MAX);
1210
+ const hostSettings = crm[CRM_HOST_SETTINGS_KEY];
1211
+ const hosts = hostSettings && typeof hostSettings === 'object' && !Array.isArray(hostSettings) ? hostSettings : {};
1212
+ const hostDefaultOwners = {};
1213
+ for (const [hostId, value] of Object.entries(hosts)){
1214
+ const owner = value && typeof value === 'object' ? cleanText(value['defaultOwnerUid'], 128) : undefined;
1215
+ if (owner) hostDefaultOwners[hostId] = owner;
1216
+ }
1217
+ return {
1218
+ rules,
1219
+ pool: {
1220
+ memberUids,
1221
+ lastAssignedUid: (_cleanText = cleanText(roundRobin['lastAssignedUid'], 128)) != null ? _cleanText : null
1222
+ },
1223
+ hostDefaultOwners
1224
+ };
1225
+ }
1226
+ /** The member a site hands unclaimed captures to, or `null` for nobody. */ export function crmHostDefaultOwner(orgDocument, hostId) {
1227
+ var _readCrmAssignmentSettings_hostDefaultOwners_hostId;
1228
+ return (_readCrmAssignmentSettings_hostDefaultOwners_hostId = readCrmAssignmentSettings(orgDocument).hostDefaultOwners[hostId]) != null ? _readCrmAssignmentSettings_hostDefaultOwners_hostId : null;
1229
+ }
1230
+ /**
1231
+ * The domain a rule's `emailDomain` is compared with — the address's own,
1232
+ * lowercased. Not `companyDomainForEmail`, which answers `null` for a public
1233
+ * mailbox: a team may well route every `gmail.com` sign-up to one rep, and
1234
+ * a rule that could not name a consumer domain could not say so.
1235
+ */ export function assignmentEmailDomain(email) {
1236
+ const at = email.lastIndexOf('@');
1237
+ if (at < 0) return null;
1238
+ return normalizeCompanyDomain(email.slice(at + 1));
1239
+ }
1240
+ /**
1241
+ * Whether every condition the rule names holds for this capture. A rule
1242
+ * with no condition matches every capture — the catch-all.
1243
+ */ export function assignmentRuleMatches(when, capture) {
1244
+ var _capture_formId;
1245
+ if (when.source && when.source !== capture.source) return false;
1246
+ if (when.formId && when.formId !== ((_capture_formId = capture.formId) != null ? _capture_formId : '')) return false;
1247
+ if (when.emailDomain && when.emailDomain !== assignmentEmailDomain(capture.email)) {
1248
+ return false;
1249
+ }
1250
+ if (when.tag) {
1251
+ var _capture_tags;
1252
+ const worn = ((_capture_tags = capture.tags) != null ? _capture_tags : []).map((tag)=>String(tag).trim().toLowerCase());
1253
+ if (!worn.includes(when.tag)) return false;
1254
+ }
1255
+ return true;
1256
+ }
1257
+ /**
1258
+ * The pool in the order the next record should try it: the member after
1259
+ * the last recipient first, wrapping round, and the last recipient
1260
+ * themselves at the end — so a pool of one still assigns, and a pointer
1261
+ * naming somebody no longer in the pool starts from the top.
1262
+ */ export function roundRobinOrder(memberUids, lastAssignedUid) {
1263
+ if (!memberUids.length) return [];
1264
+ const at = lastAssignedUid ? memberUids.indexOf(lastAssignedUid) : -1;
1265
+ if (at < 0) return [
1266
+ ...memberUids
1267
+ ];
1268
+ return [
1269
+ ...memberUids.slice(at + 1),
1270
+ ...memberUids.slice(0, at + 1)
1271
+ ];
1272
+ }
1273
+ /**
1274
+ * How a rule reads in the settings list — its conditions in words and
1275
+ * where it sends the record — so a reader can tell two rules apart without
1276
+ * opening either. `memberLabel` turns a uid into a name; the section passes
1277
+ * the roster's.
1278
+ */ export function describeAssignmentRule(rule, memberLabel) {
1279
+ const parts = [];
1280
+ if (rule.when.source) parts.push(`source is ${CONTACT_SOURCE_LABELS[rule.when.source]}`);
1281
+ if (rule.when.formId) parts.push(`form is ${rule.when.formId}`);
1282
+ if (rule.when.emailDomain) parts.push(`email domain is ${rule.when.emailDomain}`);
1283
+ if (rule.when.tag) parts.push(`tagged ${rule.when.tag}`);
1284
+ return {
1285
+ when: parts.length ? parts.join(' and ') : 'Every capture',
1286
+ assign: 'roundRobin' in rule.assign ? 'Round robin' : memberLabel(rule.assign.memberUid)
1287
+ };
1288
+ }
1289
+ /**
1290
+ * A fresh rule id, unique among the ones the org already holds. Time and
1291
+ * entropy rather than a counter, so two admins adding a rule in two tabs
1292
+ * do not mint the same id and have one reorder clobber the other's rule.
1293
+ */ export function newAssignmentRuleId(existing) {
1294
+ for(;;){
1295
+ const id = `rule-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1296
+ if (!existing.includes(id)) return id;
1297
+ }
1298
+ }
1299
+ /**
1300
+ * The `visibleTo` every CRM creator stamps — client or server, whichever
1301
+ * door the record comes in through.
1302
+ *
1303
+ * The contact create path's own expression (`upsertHostContact`), lifted
1304
+ * here so that a company, a deal or a task created from a site's console
1305
+ * lands in exactly the scope a contact captured on that site would: the
1306
+ * whole org when the org has chosen `defaultResourceScope: 'org'`, and
1307
+ * otherwise the sites that present as one sender — which, undeclared, is
1308
+ * this site alone. That is the agency's isolation, arrived at with nothing
1309
+ * configured, and the reason this is a function rather than a convention
1310
+ * eight creators are asked to remember.
1311
+ *
1312
+ * Widening past the group is an ACT — an org-wide member editing the scope
1313
+ * on the record — never a default. The rules refuse a scoped member creating
1314
+ * a record outside their own tokens, so a creator that bypassed this could
1315
+ * only make its record invisible to itself, never wider.
1316
+ */ export function crmScopeTokens(org, group) {
1317
+ return (org != null ? org : {})['defaultResourceScope'] === 'org' ? [
1318
+ ORG_SCOPE_TOKEN
1319
+ ] : consentGroupScope(group);
1320
+ }
1321
+ /**
1322
+ * The `visibleTo` tokens a reader of this group may LIST, for the
1323
+ * `array-contains-any` every CRM listener filters by.
1324
+ *
1325
+ * The other half of {@link crmScopeTokens}: that is what a creator stamps,
1326
+ * this is what a reader asks for, and the two differ by exactly one token.
1327
+ * `'org'` leads because an org-wide record is visible to every site — an org
1328
+ * that widened its default deliberately still sees its own rows — and the
1329
+ * group's sites follow. The contacts list computes this inline; every other
1330
+ * CRM reader takes it from here so that none of them can drop the org token
1331
+ * and lose the org-wide rows, or forget the cap and have Firestore refuse
1332
+ * the query outright.
1333
+ *
1334
+ * Capped at {@link MAX_SCOPE_HOSTS}: a group wider than the operator's limit
1335
+ * is listed as far as the limit reaches, which is the contacts list's
1336
+ * behavior and the only one short of an error.
1337
+ */ export function crmReadTokens(group) {
1338
+ return [
1339
+ ORG_SCOPE_TOKEN,
1340
+ ...consentGroupScope(group)
1341
+ ].slice(0, MAX_SCOPE_HOSTS);
1342
+ }
1343
+ export function parseCrmMemberRef(value) {
1344
+ const text = String(value != null ? value : '').trim();
1345
+ if (!text) return null;
1346
+ if (text.includes('@')) {
1347
+ const email = normalizeContactEmail(text);
1348
+ return email ? {
1349
+ kind: 'email',
1350
+ email
1351
+ } : null;
1352
+ }
1353
+ return {
1354
+ kind: 'uid',
1355
+ uid: text
1356
+ };
1357
+ }
1358
+ /**
1359
+ * A roster row as every CRM picker and column shows it.
1360
+ *
1361
+ * One mapping rather than four, because four is what the CRM had — and one
1362
+ * of them dropped a member whose document had neither a display name nor an
1363
+ * address, which is precisely the member the uid fallback exists for.
1364
+ */ export function crmMemberOption(member) {
1365
+ var _ref, _member_$id, _member_displayName, _member_email;
1366
+ const uid = String((_ref = (_member_$id = member['$id']) != null ? _member_$id : member['uid']) != null ? _ref : '').trim();
1367
+ if (!uid) return null;
1368
+ const displayName = String((_member_displayName = member['displayName']) != null ? _member_displayName : '').trim();
1369
+ const email = String((_member_email = member['email']) != null ? _member_email : '').trim();
1370
+ return _extends({
1371
+ uid,
1372
+ label: displayName || email || uid
1373
+ }, email ? {
1374
+ email
1375
+ } : {});
1376
+ }
1377
+ /**
1378
+ * The member a stored reference names: by uid first — the stored shape —
1379
+ * and by address second, so a record that carries an address where a uid
1380
+ * belongs (an older import, a hand edit) still names the person the roster
1381
+ * has under it. Undefined for nobody, which the caller renders honestly as
1382
+ * "former member" or as the reference itself rather than as unassigned.
1383
+ */ export function findOrgMember(members, ref) {
1384
+ const parsed = parseCrmMemberRef(ref);
1385
+ if (!parsed) return undefined;
1386
+ if (parsed.kind === 'uid') {
1387
+ return members.find((member)=>member.uid === parsed.uid);
1388
+ }
1389
+ return members.find((member)=>normalizeContactEmail(member.email) === parsed.email);
1390
+ }
1391
+ /*==========================================
1392
+ * LEADS (AGL-2608).
1393
+ *
1394
+ * A lead is NOT one of the six collections above. It lives at
1395
+ * `hosts/{hostId}/leads/{personKey}`, written by `addHostLead` when a
1396
+ * visitor signs up, books or submits a form, and it is host-scoped by PATH:
1397
+ * no `visibleTo`, no facet map, private to the site that captured it. What
1398
+ * the CRM adds is the working state a sales team keeps on such a capture —
1399
+ * a status, an owner, notes — and the record of its conversion into the
1400
+ * contact, company and deal that live in the org collections.
1401
+ *
1402
+ * These fields are typed here rather than beside `addHostLead` because the
1403
+ * writer of the capture and the reader of the working state are different
1404
+ * programs: the capture door stamps none of them, and a lead that predates
1405
+ * this block carries none of them, which is why every field is optional and
1406
+ * {@link crmLeadStatus} reads an absent status as `new`.
1407
+ *=========================================*/ /**
1408
+ * Where a lead stands, in the order a person works one.
1409
+ *
1410
+ * `qualified` is the CONVERTED state — a lead becomes a contact by being
1411
+ * qualified, and the conversion stamps `convertedContactId` beside it — and
1412
+ * `unqualified` is the closed-without-conversion state with its reason. A
1413
+ * fixed list rather than free text for the reason the lifecycle stages are:
1414
+ * the section filters on it and a report counts by it.
1415
+ */ export const CRM_LEAD_STATUSES = [
1416
+ 'new',
1417
+ 'working',
1418
+ 'qualified',
1419
+ 'unqualified'
1420
+ ];
1421
+ /** How a lead status reads on screen — typed so a status cannot ship unlabeled. */ export const CRM_LEAD_STATUS_LABELS = {
1422
+ new: 'New',
1423
+ working: 'Working',
1424
+ qualified: 'Qualified',
1425
+ unqualified: 'Unqualified'
1426
+ };
1427
+ /**
1428
+ * The statuses a lead still needs somebody's attention in — what the Leads
1429
+ * section shows by default, so the list opens on the work rather than on
1430
+ * the history.
1431
+ */ export const CRM_LEAD_OPEN_STATUSES = [
1432
+ 'new',
1433
+ 'working'
1434
+ ];
1435
+ /**
1436
+ * The statuses that mean nobody needs to work the lead any more — the
1437
+ * operand of the `in` clause an open-lead figure subtracts with. Subtracts,
1438
+ * because an untouched lead carries no status field at all and Firestore
1439
+ * cannot select on a field's absence; the closed statuses are always
1440
+ * written, so they can be counted, and what remains is open. See
1441
+ * `openLeadsFromCounts`.
1442
+ */ export const CRM_LEAD_CLOSED_STATUSES = CRM_LEAD_STATUSES.filter((status)=>!CRM_LEAD_OPEN_STATUSES.includes(status));
1443
+ export function isCrmLeadStatus(value) {
1444
+ return typeof value === 'string' && CRM_LEAD_STATUSES.includes(value);
1445
+ }
1446
+ /**
1447
+ * A lead's status as the list and the filter should read it.
1448
+ *
1449
+ * `new` for a lead that carries no status at all — every lead captured
1450
+ * before the CRM existed, and every lead the capture door writes today,
1451
+ * because `addHostLead` stamps none. Reading the absence as `new` is what
1452
+ * lets the section open on the leads a site already holds rather than on an
1453
+ * empty list until each one has been touched once. A stored value the union
1454
+ * does not name also reads as `new`: it is a document some other writer
1455
+ * produced, and refusing to list it would hide a person.
1456
+ */ export function crmLeadStatus(lead) {
1457
+ const status = lead == null ? void 0 : lead.status;
1458
+ return isCrmLeadStatus(status) ? status : 'new';
1459
+ }
1460
+ /** Whether a lead still needs working — see {@link CRM_LEAD_OPEN_STATUSES}. */ export function isCrmLeadOpen(lead) {
1461
+ return CRM_LEAD_OPEN_STATUSES.includes(crmLeadStatus(lead));
1462
+ }
1463
+ /*==========================================
1464
+ * SAVED VIEWS (AGL-2617) — a list the way one person works it.
1465
+ *
1466
+ * "My open leads in Texas" is a list a rep opens every morning, and it is
1467
+ * three things at once: the filters that pick the people, the columns they
1468
+ * want to see about them, and the order they want them in. A `ContactSegment`
1469
+ * kept the first of those for two dimensions — tags and capture sources —
1470
+ * and nothing kept the rest, so every reload put the reader back at the
1471
+ * whole list. A view keeps all three, for every list in the CRM, under a
1472
+ * name, and is addressable: `?view=<id>` on the section's own URL opens it.
1473
+ *
1474
+ * ## The filters are the LIST'S grammar, not a second one
1475
+ *
1476
+ * A clause here is `{ field, op, value }` — structurally the
1477
+ * `ListFilterRequest` the shared list-filter grammar already speaks, the
1478
+ * request a grid's filter panel produces and the one the query translator
1479
+ * and the in-memory matcher both read. A view stores a list of them and
1480
+ * nothing more, so a view can only ask what the list can already answer,
1481
+ * and a list that gains a filterable field gains it for its views at no
1482
+ * cost. The type is restated here rather than imported because this module
1483
+ * is pure data and the grammar's home is a UI library; the shape is the
1484
+ * contract, and `normalizeCrmViewFilters` is what holds a stored document
1485
+ * to it.
1486
+ *
1487
+ * ## Mine, and shared
1488
+ *
1489
+ * A view is one person's working arrangement until they say otherwise, so
1490
+ * it lists only for its owner; `shared` puts it in front of everyone who
1491
+ * can read the section. Both are stamped `visibleTo` like every CRM row,
1492
+ * because a view is a description of the people it selects and answers to
1493
+ * the same authority they do — a private view is hidden by the LISTING, not
1494
+ * by the rules, and the rules let the creator or an org-wide member change
1495
+ * or remove it.
1496
+ *
1497
+ * ## The default is the reader's, not the view's
1498
+ *
1499
+ * Which view a section opens on is a preference of one person for one
1500
+ * organization, so it lives on the reader's own profile document beside
1501
+ * their notification mutes rather than on the view — a shared view somebody
1502
+ * else made their default must not become everybody's.
1503
+ *=========================================*/ /** The lists a view can be saved for — every CRM section that has one. */ export const CRM_VIEW_SECTIONS = [
1504
+ 'contacts',
1505
+ 'companies',
1506
+ 'deals',
1507
+ 'tasks',
1508
+ 'leads'
1509
+ ];
1510
+ export function isCrmViewSection(value) {
1511
+ return typeof value === 'string' && CRM_VIEW_SECTIONS.includes(value);
1512
+ }
1513
+ export const CRM_VIEW_NAME_MAX = 60;
1514
+ /**
1515
+ * The most clauses one view carries. A bound on the predicate, not the
1516
+ * audience: the list matches most of them in memory over a bounded window,
1517
+ * and a stored array has no natural end.
1518
+ */ export const CRM_VIEW_MAX_FILTERS = 20;
1519
+ export const CRM_VIEW_MAX_COLUMNS = 60;
1520
+ /** Filter operators that carry no value, so an empty `value` is not a dropped clause. */ const VALUELESS_VIEW_OPS = new Set([
1521
+ 'isEmpty',
1522
+ 'isNotEmpty'
1523
+ ]);
1524
+ export const EMPTY_CRM_VIEW_STATE = Object.freeze({
1525
+ filters: [],
1526
+ columns: [],
1527
+ sort: null
1528
+ });
1529
+ const asViewText = (value, max)=>typeof value === 'string' ? value.trim().slice(0, max) : '';
1530
+ /**
1531
+ * A stored view's filters, held to the clause shape.
1532
+ *
1533
+ * Strict about what it keeps: a clause with no field or no operator is not
1534
+ * a filter, and a valued operator with no value would read as a filter
1535
+ * that matches nothing — so both are dropped rather than kept, for the same
1536
+ * reason the dynamic-list rule drops an empty branch: a view must not
1537
+ * quietly select a different population than the one it reads as.
1538
+ */ export function normalizeCrmViewFilters(value) {
1539
+ if (!Array.isArray(value)) return [];
1540
+ const clauses = [];
1541
+ for (const raw of value){
1542
+ const entry = raw != null ? raw : {};
1543
+ const field = asViewText(entry['field'], 80);
1544
+ const op = asViewText(entry['op'], 40);
1545
+ const text = asViewText(entry['value'], 500);
1546
+ if (!field || !op) continue;
1547
+ if (!text && !VALUELESS_VIEW_OPS.has(op)) continue;
1548
+ const label = asViewText(entry['label'], 120);
1549
+ clauses.push(_extends({
1550
+ field,
1551
+ op,
1552
+ value: text
1553
+ }, label ? {
1554
+ label
1555
+ } : {}));
1556
+ if (clauses.length >= CRM_VIEW_MAX_FILTERS) break;
1557
+ }
1558
+ return clauses;
1559
+ }
1560
+ export function normalizeCrmViewColumns(value) {
1561
+ if (!Array.isArray(value)) return [];
1562
+ const seen = new Set();
1563
+ for (const raw of value){
1564
+ const column = asViewText(raw, 80);
1565
+ if (column) seen.add(column);
1566
+ if (seen.size >= CRM_VIEW_MAX_COLUMNS) break;
1567
+ }
1568
+ return [
1569
+ ...seen
1570
+ ];
1571
+ }
1572
+ export function normalizeCrmViewSort(value) {
1573
+ const entry = value != null ? value : null;
1574
+ const field = entry ? asViewText(entry['field'], 80) : '';
1575
+ if (!field) return null;
1576
+ return {
1577
+ field,
1578
+ direction: (entry == null ? void 0 : entry['direction']) === 'desc' ? 'desc' : 'asc'
1579
+ };
1580
+ }
1581
+ /** A stored document's three list-facing fields, held to their shapes. */ export function normalizeCrmViewState(value) {
1582
+ const entry = value != null ? value : {};
1583
+ return {
1584
+ filters: normalizeCrmViewFilters(entry['filters']),
1585
+ columns: normalizeCrmViewColumns(entry['columns']),
1586
+ sort: normalizeCrmViewSort(entry['sort'])
1587
+ };
1588
+ }
1589
+ /**
1590
+ * Whether two states describe the same list — what "unsaved changes" means.
1591
+ *
1592
+ * Clause order matters (a list applies them in order, and the first one the
1593
+ * query can serve is the one it serves); the label on a clause does not,
1594
+ * because nothing matches on it.
1595
+ */ export function crmViewStateEquals(a, b) {
1596
+ if (a.filters.length !== b.filters.length) return false;
1597
+ for(let index = 0; index < a.filters.length; index += 1){
1598
+ const left = a.filters[index];
1599
+ const right = b.filters[index];
1600
+ if (left.field !== right.field || left.op !== right.op || left.value !== right.value) {
1601
+ return false;
1602
+ }
1603
+ }
1604
+ if (a.columns.length !== b.columns.length) return false;
1605
+ if (a.columns.some((column, index)=>column !== b.columns[index])) {
1606
+ return false;
1607
+ }
1608
+ if (!a.sort || !b.sort) return a.sort === b.sort;
1609
+ return a.sort.field === b.sort.field && a.sort.direction === b.sort.direction;
1610
+ }
1611
+ /**
1612
+ * Whether a view belongs in this reader's menu: their own, or one somebody
1613
+ * shared. The rules admit the read either way — see the module note — so
1614
+ * this is what keeps one person's private arrangement out of another's
1615
+ * list.
1616
+ */ export function crmViewIsListed(view, uid) {
1617
+ return view.shared === true || Boolean(uid) && view.ownerUid === uid;
1618
+ }
1619
+ /**
1620
+ * The Contacts list's filterable fields, by the names a view clause carries.
1621
+ *
1622
+ * A contract between three readers that cannot import one another: the
1623
+ * list's own filter grammar (which declares these as its columns), a saved
1624
+ * view (which stores them), and the dynamic-list translator below in
1625
+ * `dynamic-list-rule.ts` (which turns them into audience dimensions). Named
1626
+ * once so a rename on the list cannot silently stop an audience matching.
1627
+ * `custom` is a PREFIX: a custom field's column is the prefix and its key.
1628
+ */ export const CRM_CONTACT_VIEW_FIELDS = {
1629
+ tags: 'tags',
1630
+ source: 'source',
1631
+ owner: 'ownerUid',
1632
+ stage: 'lifecycleStage',
1633
+ company: 'companyId',
1634
+ createdAt: 'createdAt',
1635
+ updatedAt: 'updatedAt',
1636
+ orders: 'ordersCount',
1637
+ ltv: 'ltvCents',
1638
+ custom: 'custom_'
1639
+ };
1640
+ /** The column a custom contact field filters and shows as. */ export const crmContactCustomColumn = (key)=>`${CRM_CONTACT_VIEW_FIELDS.custom}${key}`;
1641
+ /** The field key a custom column stands for, or `null` for any other column. */ export function crmContactCustomKey(column) {
1642
+ const prefix = CRM_CONTACT_VIEW_FIELDS.custom;
1643
+ return column.startsWith(prefix) && column.length > prefix.length ? column.slice(prefix.length) : null;
1644
+ }
1645
+ /**
1646
+ * A stored phone number as the `href` of a click-to-call link, or `null`
1647
+ * when the value is not one (AGL-2661).
1648
+ *
1649
+ * The console stores E.164 (`normalizePhone` runs before every write), and
1650
+ * a `tel:` URL wants exactly that: digits with a leading `+`, nothing else.
1651
+ * Spaces, dots, dashes and parentheses are dropped rather than refused
1652
+ * because a value written before normalization existed may carry them;
1653
+ * anything that is not a run of digits after that — a word, an extension
1654
+ * typed as `x123` — is refused, because a dialer handed it would ring
1655
+ * nothing and the link would be a lie.
1656
+ */ export function crmTelHref(phone) {
1657
+ const text = String(phone != null ? phone : '').trim();
1658
+ if (!text) return null;
1659
+ const compact = text.replace(/[\s().-]/g, '');
1660
+ return /^\+?\d{3,20}$/.test(compact) ? `tel:${compact}` : null;
1661
+ }
1662
+ const CRM_VIEW_TAGS_FIELD = CRM_CONTACT_VIEW_FIELDS.tags;
1663
+ const CRM_VIEW_SOURCE_FIELD = CRM_CONTACT_VIEW_FIELDS.source;
1664
+ /**
1665
+ * A saved segment, as the filters of a contacts view.
1666
+ *
1667
+ * A segment is "any of these tags AND any of these sources", so each
1668
+ * becomes one `isAnyOf` clause — OR within, AND across, which is the
1669
+ * reading `contactMatchesSegment` gives it. A single tag is emitted as
1670
+ * `contains` instead: that operator is the one the contacts query can serve
1671
+ * from the index, so a one-tag segment opened as a view reaches the whole
1672
+ * collection rather than the loaded window. The values are the segment's
1673
+ * own, joined the way the grammar's `isAnyOf` splits them.
1674
+ */ export function crmViewFiltersFromSegment(segment) {
1675
+ var _segment_tags, _segment_sources;
1676
+ const tags = ((_segment_tags = segment.tags) != null ? _segment_tags : []).map((tag)=>tag.trim()).filter(Boolean);
1677
+ const sources = ((_segment_sources = segment.sources) != null ? _segment_sources : []).filter((source)=>source in CONTACT_SOURCE_LABELS);
1678
+ return [
1679
+ ...tags.length === 1 ? [
1680
+ {
1681
+ field: CRM_VIEW_TAGS_FIELD,
1682
+ op: 'contains',
1683
+ value: tags[0]
1684
+ }
1685
+ ] : tags.length ? [
1686
+ {
1687
+ field: CRM_VIEW_TAGS_FIELD,
1688
+ op: 'isAnyOf',
1689
+ value: tags.join(',')
1690
+ }
1691
+ ] : [],
1692
+ ...sources.length === 1 ? [
1693
+ {
1694
+ field: CRM_VIEW_SOURCE_FIELD,
1695
+ op: 'equals',
1696
+ value: sources[0]
1697
+ }
1698
+ ] : sources.length ? [
1699
+ {
1700
+ field: CRM_VIEW_SOURCE_FIELD,
1701
+ op: 'isAnyOf',
1702
+ value: sources.join(',')
1703
+ }
1704
+ ] : []
1705
+ ];
1706
+ }
1707
+ /**
1708
+ * The other direction: the segment a view's filters describe, or `null`
1709
+ * when the view carries no tag or source clause a segment could hold.
1710
+ *
1711
+ * Only the two dimensions a segment has are read, and only through the
1712
+ * operators that mean "has one of these"; a `name startsWith` or an owner
1713
+ * clause is not a segment's to keep. What comes back is what "Save as
1714
+ * segment" writes, so a campaign audience built from it selects exactly the
1715
+ * tags and sources the reader could see on the chips.
1716
+ */ export function crmViewSegmentFilters(filters) {
1717
+ const tags = new Set();
1718
+ const sources = new Set();
1719
+ const split = (value)=>value.split(',').map((entry)=>entry.trim()).filter(Boolean);
1720
+ for (const clause of filters){
1721
+ if (clause.field === CRM_VIEW_TAGS_FIELD) {
1722
+ if (clause.op === 'contains') tags.add(clause.value.trim().toLowerCase());
1723
+ else if (clause.op === 'isAnyOf') {
1724
+ for (const tag of split(clause.value))tags.add(tag.toLowerCase());
1725
+ }
1726
+ } else if (clause.field === CRM_VIEW_SOURCE_FIELD) {
1727
+ const values = clause.op === 'equals' ? [
1728
+ clause.value.trim()
1729
+ ] : clause.op === 'isAnyOf' ? split(clause.value) : [];
1730
+ for (const source of values){
1731
+ if (source in CONTACT_SOURCE_LABELS) sources.add(source);
1732
+ }
1733
+ }
1734
+ }
1735
+ tags.delete('');
1736
+ if (!tags.size && !sources.size) return null;
1737
+ return _extends({}, tags.size ? {
1738
+ tags: [
1739
+ ...tags
1740
+ ]
1741
+ } : {}, sources.size ? {
1742
+ sources: [
1743
+ ...sources
1744
+ ]
1745
+ } : {});
1746
+ }
1747
+ /**
1748
+ * `users/{uid}.crmDefaultViews` — `{ [orgId]: { [section]: viewId } }`.
1749
+ *
1750
+ * On the reader's own profile document, beside `notificationPrefs`, because
1751
+ * it is the same kind of fact: how one person wants their console to
1752
+ * behave, owned and written by them alone. Keyed by org first because one
1753
+ * account sits on several organizations and a view id is only meaningful
1754
+ * inside the one that holds it.
1755
+ */ export const CRM_DEFAULT_VIEWS_FIELD = 'crmDefaultViews';
1756
+ /** The view a section opens on for this reader in this org, or none. */ export function crmDefaultViewId(profile, orgId, section) {
1757
+ if (!profile || !orgId) return null;
1758
+ const byOrg = profile[CRM_DEFAULT_VIEWS_FIELD];
1759
+ if (!byOrg || typeof byOrg !== 'object' || Array.isArray(byOrg)) return null;
1760
+ const bySection = byOrg[orgId];
1761
+ if (!bySection || typeof bySection !== 'object' || Array.isArray(bySection)) {
1762
+ return null;
1763
+ }
1764
+ const viewId = bySection[section];
1765
+ return typeof viewId === 'string' && viewId.trim() ? viewId : null;
1766
+ }
1767
+ /**
1768
+ * The merge patch that sets — or, with `null`, clears — one default.
1769
+ *
1770
+ * Shaped for a merged write so the other organizations' and sections'
1771
+ * defaults on the same document survive it; `null` rather than a delete
1772
+ * sentinel because this module carries no Firestore, and the reader above
1773
+ * treats a null as no default.
1774
+ */ export function crmDefaultViewPatch(orgId, section, viewId) {
1775
+ return {
1776
+ [CRM_DEFAULT_VIEWS_FIELD]: {
1777
+ [orgId]: {
1778
+ [section]: viewId
1779
+ }
1780
+ }
1781
+ };
1782
+ }
1783
+ /*==========================================
1784
+ * FILES ON A RECORD (AGL-2662)
1785
+ *=========================================*/ /** The field a record's attached files are stored under, on all three. */ export const CRM_MEDIA_IDS_FIELD = 'mediaIds';
1786
+ /**
1787
+ * The most files one record may carry.
1788
+ *
1789
+ * A platform ceiling in the family of {@link CRM_ACTIVITIES_PER_RECORD_CEILING}
1790
+ * rather than a plan dimension: attachments are bounded by human effort, and
1791
+ * this is the bound. It is also what the Firestore rules can actually check
1792
+ * — a rule can assert a list and its size, and cannot walk one — so the
1793
+ * number is enforced rather than merely documented.
1794
+ */ export const CRM_MEDIA_IDS_MAX = 20;
1795
+ /**
1796
+ * A stored or submitted attachment list, cleaned.
1797
+ *
1798
+ * Ids rather than URLs, deduplicated, trimmed, non-empty and capped. Written
1799
+ * through by every path that sets the field — the console card, the REST
1800
+ * write — so a record cannot hold a list one of them would refuse.
1801
+ *
1802
+ * An id is a media DOCUMENT id, resolved against the organization's library
1803
+ * (`orgs/{orgId}/media/{mediaId}`) at read time. Storing the id and not the
1804
+ * URL is what lets a file move between folders, and what keeps a private
1805
+ * asset behind the signed CDN door rather than pinned to a raw storage URL
1806
+ * that names its current location.
1807
+ */ export function normalizeCrmMediaIds(value) {
1808
+ if (!Array.isArray(value)) return [];
1809
+ return [
1810
+ ...new Set(value.map((id)=>String(id != null ? id : '').trim()).filter((id)=>id.length > 0 && id.length <= 200))
1811
+ ].slice(0, CRM_MEDIA_IDS_MAX);
1812
+ }
1813
+
1814
+ //# sourceMappingURL=crm.js.map