@aglyn/tenant-data-admin 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 (374) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/jest.integration.config.d.ts +39 -0
  4. package/jest.integration.setup.d.ts +17 -0
  5. package/package.json +51 -0
  6. package/src/index.d.ts +17 -0
  7. package/src/index.js +18 -0
  8. package/src/index.js.map +1 -0
  9. package/src/lib/render-cache.d.ts +184 -0
  10. package/src/lib/render-cache.js +198 -0
  11. package/src/lib/render-cache.js.map +1 -0
  12. package/src/lib/server/account-addresses.d.ts +160 -0
  13. package/src/lib/server/account-addresses.js +311 -0
  14. package/src/lib/server/account-addresses.js.map +1 -0
  15. package/src/lib/server/account-emails.d.ts +219 -0
  16. package/src/lib/server/account-emails.js +640 -0
  17. package/src/lib/server/account-emails.js.map +1 -0
  18. package/src/lib/server/admin-audit.d.ts +180 -0
  19. package/src/lib/server/admin-audit.js +233 -0
  20. package/src/lib/server/admin-audit.js.map +1 -0
  21. package/src/lib/server/analytics-retention.d.ts +63 -0
  22. package/src/lib/server/analytics-retention.js +66 -0
  23. package/src/lib/server/analytics-retention.js.map +1 -0
  24. package/src/lib/server/api-http.d.ts +159 -0
  25. package/src/lib/server/api-http.js +230 -0
  26. package/src/lib/server/api-http.js.map +1 -0
  27. package/src/lib/server/api-keys.d.ts +117 -0
  28. package/src/lib/server/api-keys.js +298 -0
  29. package/src/lib/server/api-keys.js.map +1 -0
  30. package/src/lib/server/auth-handoff.d.ts +165 -0
  31. package/src/lib/server/auth-handoff.js +482 -0
  32. package/src/lib/server/auth-handoff.js.map +1 -0
  33. package/src/lib/server/auth-pools.d.ts +246 -0
  34. package/src/lib/server/auth-pools.js +551 -0
  35. package/src/lib/server/auth-pools.js.map +1 -0
  36. package/src/lib/server/billing-addons.d.ts +171 -0
  37. package/src/lib/server/billing-addons.js +277 -0
  38. package/src/lib/server/billing-addons.js.map +1 -0
  39. package/src/lib/server/campaign-attribution-store.d.ts +55 -0
  40. package/src/lib/server/campaign-attribution-store.js +95 -0
  41. package/src/lib/server/campaign-attribution-store.js.map +1 -0
  42. package/src/lib/server/campaign-conversion-attribution.d.ts +205 -0
  43. package/src/lib/server/campaign-conversion-attribution.js +279 -0
  44. package/src/lib/server/campaign-conversion-attribution.js.map +1 -0
  45. package/src/lib/server/client-error-report.d.ts +301 -0
  46. package/src/lib/server/client-error-report.js +755 -0
  47. package/src/lib/server/client-error-report.js.map +1 -0
  48. package/src/lib/server/connect-account-status.d.ts +74 -0
  49. package/src/lib/server/connect-account-status.js +94 -0
  50. package/src/lib/server/connect-account-status.js.map +1 -0
  51. package/src/lib/server/connect-payout-failure.d.ts +103 -0
  52. package/src/lib/server/connect-payout-failure.js +127 -0
  53. package/src/lib/server/connect-payout-failure.js.map +1 -0
  54. package/src/lib/server/console-api-rate-limit.d.ts +81 -0
  55. package/src/lib/server/console-api-rate-limit.js +111 -0
  56. package/src/lib/server/console-api-rate-limit.js.map +1 -0
  57. package/src/lib/server/console-domains.d.ts +326 -0
  58. package/src/lib/server/console-domains.js +779 -0
  59. package/src/lib/server/console-domains.js.map +1 -0
  60. package/src/lib/server/consume-once.d.ts +91 -0
  61. package/src/lib/server/consume-once.js +96 -0
  62. package/src/lib/server/consume-once.js.map +1 -0
  63. package/src/lib/server/contact-company-link.d.ts +85 -0
  64. package/src/lib/server/contact-company-link.js +105 -0
  65. package/src/lib/server/contact-company-link.js.map +1 -0
  66. package/src/lib/server/contact-email-engagement.d.ts +32 -0
  67. package/src/lib/server/contact-email-engagement.js +145 -0
  68. package/src/lib/server/contact-email-engagement.js.map +1 -0
  69. package/src/lib/server/contact-email-index.d.ts +56 -0
  70. package/src/lib/server/contact-email-index.js +158 -0
  71. package/src/lib/server/contact-email-index.js.map +1 -0
  72. package/src/lib/server/contact-lifecycle-floor.d.ts +89 -0
  73. package/src/lib/server/contact-lifecycle-floor.js +88 -0
  74. package/src/lib/server/contact-lifecycle-floor.js.map +1 -0
  75. package/src/lib/server/contact-merge.d.ts +55 -0
  76. package/src/lib/server/contact-merge.js +279 -0
  77. package/src/lib/server/contact-merge.js.map +1 -0
  78. package/src/lib/server/contact-suppression.d.ts +153 -0
  79. package/src/lib/server/contact-suppression.js +259 -0
  80. package/src/lib/server/contact-suppression.js.map +1 -0
  81. package/src/lib/server/crm-booking-activity.d.ts +86 -0
  82. package/src/lib/server/crm-booking-activity.js +251 -0
  83. package/src/lib/server/crm-booking-activity.js.map +1 -0
  84. package/src/lib/server/crm-email-activity.d.ts +112 -0
  85. package/src/lib/server/crm-email-activity.js +143 -0
  86. package/src/lib/server/crm-email-activity.js.map +1 -0
  87. package/src/lib/server/crm-inbound-email.d.ts +145 -0
  88. package/src/lib/server/crm-inbound-email.js +287 -0
  89. package/src/lib/server/crm-inbound-email.js.map +1 -0
  90. package/src/lib/server/crm-next-activity.d.ts +74 -0
  91. package/src/lib/server/crm-next-activity.js +194 -0
  92. package/src/lib/server/crm-next-activity.js.map +1 -0
  93. package/src/lib/server/crm-records.d.ts +144 -0
  94. package/src/lib/server/crm-records.js +218 -0
  95. package/src/lib/server/crm-records.js.map +1 -0
  96. package/src/lib/server/csp-aggregate.d.ts +62 -0
  97. package/src/lib/server/csp-aggregate.js +276 -0
  98. package/src/lib/server/csp-aggregate.js.map +1 -0
  99. package/src/lib/server/data-storage-gate.d.ts +66 -0
  100. package/src/lib/server/data-storage-gate.js +48 -0
  101. package/src/lib/server/data-storage-gate.js.map +1 -0
  102. package/src/lib/server/dataset-live-pages.d.ts +179 -0
  103. package/src/lib/server/dataset-live-pages.js +421 -0
  104. package/src/lib/server/dataset-live-pages.js.map +1 -0
  105. package/src/lib/server/dns-probe.d.ts +53 -0
  106. package/src/lib/server/dns-probe.js +184 -0
  107. package/src/lib/server/dns-probe.js.map +1 -0
  108. package/src/lib/server/document-id.d.ts +29 -0
  109. package/src/lib/server/document-id.js +100 -0
  110. package/src/lib/server/document-id.js.map +1 -0
  111. package/src/lib/server/domain-provider-vercel.d.ts +33 -0
  112. package/src/lib/server/domain-provider-vercel.js +298 -0
  113. package/src/lib/server/domain-provider-vercel.js.map +1 -0
  114. package/src/lib/server/domain-provider-webhook.d.ts +73 -0
  115. package/src/lib/server/domain-provider-webhook.js +223 -0
  116. package/src/lib/server/domain-provider-webhook.js.map +1 -0
  117. package/src/lib/server/domain-provider-wildcard.d.ts +54 -0
  118. package/src/lib/server/domain-provider-wildcard.js +163 -0
  119. package/src/lib/server/domain-provider-wildcard.js.map +1 -0
  120. package/src/lib/server/domain-provider.d.ts +197 -0
  121. package/src/lib/server/domain-provider.js +221 -0
  122. package/src/lib/server/domain-provider.js.map +1 -0
  123. package/src/lib/server/duplicate-activity.d.ts +54 -0
  124. package/src/lib/server/duplicate-activity.js +67 -0
  125. package/src/lib/server/duplicate-activity.js.map +1 -0
  126. package/src/lib/server/duplicate-resource.d.ts +55 -0
  127. package/src/lib/server/duplicate-resource.js +474 -0
  128. package/src/lib/server/duplicate-resource.js.map +1 -0
  129. package/src/lib/server/dynamic-list-materialize.d.ts +153 -0
  130. package/src/lib/server/dynamic-list-materialize.js +581 -0
  131. package/src/lib/server/dynamic-list-materialize.js.map +1 -0
  132. package/src/lib/server/edit-access-authz.d.ts +56 -0
  133. package/src/lib/server/edit-access-authz.js +107 -0
  134. package/src/lib/server/edit-access-authz.js.map +1 -0
  135. package/src/lib/server/edit-access-token.d.ts +72 -0
  136. package/src/lib/server/edit-access-token.js +116 -0
  137. package/src/lib/server/edit-access-token.js.map +1 -0
  138. package/src/lib/server/edit-hint-token.d.ts +83 -0
  139. package/src/lib/server/edit-hint-token.js +119 -0
  140. package/src/lib/server/edit-hint-token.js.map +1 -0
  141. package/src/lib/server/email-delivery-log.d.ts +509 -0
  142. package/src/lib/server/email-delivery-log.js +1043 -0
  143. package/src/lib/server/email-delivery-log.js.map +1 -0
  144. package/src/lib/server/email-flow-gate.d.ts +80 -0
  145. package/src/lib/server/email-flow-gate.js +153 -0
  146. package/src/lib/server/email-flow-gate.js.map +1 -0
  147. package/src/lib/server/email-marketing-gate.d.ts +333 -0
  148. package/src/lib/server/email-marketing-gate.js +639 -0
  149. package/src/lib/server/email-marketing-gate.js.map +1 -0
  150. package/src/lib/server/email-metering.d.ts +293 -0
  151. package/src/lib/server/email-metering.js +359 -0
  152. package/src/lib/server/email-metering.js.map +1 -0
  153. package/src/lib/server/email-revenue-attribution.d.ts +185 -0
  154. package/src/lib/server/email-revenue-attribution.js +300 -0
  155. package/src/lib/server/email-revenue-attribution.js.map +1 -0
  156. package/src/lib/server/email-send-rate.d.ts +232 -0
  157. package/src/lib/server/email-send-rate.js +417 -0
  158. package/src/lib/server/email-send-rate.js.map +1 -0
  159. package/src/lib/server/email-sender-reputation.d.ts +317 -0
  160. package/src/lib/server/email-sender-reputation.js +464 -0
  161. package/src/lib/server/email-sender-reputation.js.map +1 -0
  162. package/src/lib/server/email-suppression.d.ts +490 -0
  163. package/src/lib/server/email-suppression.js +648 -0
  164. package/src/lib/server/email-suppression.js.map +1 -0
  165. package/src/lib/server/email-topic-confirmation.d.ts +150 -0
  166. package/src/lib/server/email-topic-confirmation.js +272 -0
  167. package/src/lib/server/email-topic-confirmation.js.map +1 -0
  168. package/src/lib/server/email-unsubscribe-link.d.ts +174 -0
  169. package/src/lib/server/email-unsubscribe-link.js +236 -0
  170. package/src/lib/server/email-unsubscribe-link.js.map +1 -0
  171. package/src/lib/server/erase-person.d.ts +116 -0
  172. package/src/lib/server/erase-person.js +272 -0
  173. package/src/lib/server/erase-person.js.map +1 -0
  174. package/src/lib/server/erase.d.ts +458 -0
  175. package/src/lib/server/erase.js +1506 -0
  176. package/src/lib/server/erase.js.map +1 -0
  177. package/src/lib/server/firebase-admin.d.ts +71 -0
  178. package/src/lib/server/firebase-admin.js +343 -0
  179. package/src/lib/server/firebase-admin.js.map +1 -0
  180. package/src/lib/server/form-dataset-binding-token.d.ts +35 -0
  181. package/src/lib/server/form-dataset-binding-token.js +107 -0
  182. package/src/lib/server/form-dataset-binding-token.js.map +1 -0
  183. package/src/lib/server/free-workspace-cap.d.ts +201 -0
  184. package/src/lib/server/free-workspace-cap.js +404 -0
  185. package/src/lib/server/free-workspace-cap.js.map +1 -0
  186. package/src/lib/server/ga4-measurement-protocol.d.ts +256 -0
  187. package/src/lib/server/ga4-measurement-protocol.js +558 -0
  188. package/src/lib/server/ga4-measurement-protocol.js.map +1 -0
  189. package/src/lib/server/host-email-tokens.d.ts +47 -0
  190. package/src/lib/server/host-email-tokens.js +72 -0
  191. package/src/lib/server/host-email-tokens.js.map +1 -0
  192. package/src/lib/server/host-memberships.d.ts +54 -0
  193. package/src/lib/server/host-memberships.js +194 -0
  194. package/src/lib/server/host-memberships.js.map +1 -0
  195. package/src/lib/server/host-sending-domain.d.ts +292 -0
  196. package/src/lib/server/host-sending-domain.js +451 -0
  197. package/src/lib/server/host-sending-domain.js.map +1 -0
  198. package/src/lib/server/host-visitor-records.d.ts +150 -0
  199. package/src/lib/server/host-visitor-records.js +262 -0
  200. package/src/lib/server/host-visitor-records.js.map +1 -0
  201. package/src/lib/server/id-token-refusal.d.ts +28 -0
  202. package/src/lib/server/id-token-refusal.js +111 -0
  203. package/src/lib/server/id-token-refusal.js.map +1 -0
  204. package/src/lib/server/legal-acceptance.d.ts +214 -0
  205. package/src/lib/server/legal-acceptance.js +305 -0
  206. package/src/lib/server/legal-acceptance.js.map +1 -0
  207. package/src/lib/server/list-members.d.ts +211 -0
  208. package/src/lib/server/list-members.js +176 -0
  209. package/src/lib/server/list-members.js.map +1 -0
  210. package/src/lib/server/live-page-usage.d.ts +202 -0
  211. package/src/lib/server/live-page-usage.js +300 -0
  212. package/src/lib/server/live-page-usage.js.map +1 -0
  213. package/src/lib/server/lockdown.d.ts +313 -0
  214. package/src/lib/server/lockdown.js +643 -0
  215. package/src/lib/server/lockdown.js.map +1 -0
  216. package/src/lib/server/media-cdn-rate-limit.d.ts +188 -0
  217. package/src/lib/server/media-cdn-rate-limit.js +204 -0
  218. package/src/lib/server/media-cdn-rate-limit.js.map +1 -0
  219. package/src/lib/server/media-delivery.d.ts +267 -0
  220. package/src/lib/server/media-delivery.js +485 -0
  221. package/src/lib/server/media-delivery.js.map +1 -0
  222. package/src/lib/server/media-download-tokens.d.ts +161 -0
  223. package/src/lib/server/media-download-tokens.js +386 -0
  224. package/src/lib/server/media-download-tokens.js.map +1 -0
  225. package/src/lib/server/media-quarantine.d.ts +127 -0
  226. package/src/lib/server/media-quarantine.js +170 -0
  227. package/src/lib/server/media-quarantine.js.map +1 -0
  228. package/src/lib/server/media-signing.d.ts +126 -0
  229. package/src/lib/server/media-signing.js +159 -0
  230. package/src/lib/server/media-signing.js.map +1 -0
  231. package/src/lib/server/media-storage-path.d.ts +96 -0
  232. package/src/lib/server/media-storage-path.js +111 -0
  233. package/src/lib/server/media-storage-path.js.map +1 -0
  234. package/src/lib/server/media-strong-digest.d.ts +85 -0
  235. package/src/lib/server/media-strong-digest.js +190 -0
  236. package/src/lib/server/media-strong-digest.js.map +1 -0
  237. package/src/lib/server/media-tombstone.d.ts +276 -0
  238. package/src/lib/server/media-tombstone.js +421 -0
  239. package/src/lib/server/media-tombstone.js.map +1 -0
  240. package/src/lib/server/media-variants.d.ts +309 -0
  241. package/src/lib/server/media-variants.js +428 -0
  242. package/src/lib/server/media-variants.js.map +1 -0
  243. package/src/lib/server/member-email-aliases.d.ts +180 -0
  244. package/src/lib/server/member-email-aliases.js +420 -0
  245. package/src/lib/server/member-email-aliases.js.map +1 -0
  246. package/src/lib/server/member-photo.d.ts +88 -0
  247. package/src/lib/server/member-photo.js +185 -0
  248. package/src/lib/server/member-photo.js.map +1 -0
  249. package/src/lib/server/membership-recover-throttle.d.ts +211 -0
  250. package/src/lib/server/membership-recover-throttle.js +231 -0
  251. package/src/lib/server/membership-recover-throttle.js.map +1 -0
  252. package/src/lib/server/notifications.d.ts +55 -0
  253. package/src/lib/server/notifications.js +134 -0
  254. package/src/lib/server/notifications.js.map +1 -0
  255. package/src/lib/server/org-billing.d.ts +97 -0
  256. package/src/lib/server/org-billing.js +236 -0
  257. package/src/lib/server/org-billing.js.map +1 -0
  258. package/src/lib/server/organizations.d.ts +837 -0
  259. package/src/lib/server/organizations.js +1814 -0
  260. package/src/lib/server/organizations.js.map +1 -0
  261. package/src/lib/server/password-reset-throttle.d.ts +84 -0
  262. package/src/lib/server/password-reset-throttle.js +102 -0
  263. package/src/lib/server/password-reset-throttle.js.map +1 -0
  264. package/src/lib/server/personal-data-export.d.ts +241 -0
  265. package/src/lib/server/personal-data-export.js +858 -0
  266. package/src/lib/server/personal-data-export.js.map +1 -0
  267. package/src/lib/server/platform-domain-names.d.ts +62 -0
  268. package/src/lib/server/platform-domain-names.js +197 -0
  269. package/src/lib/server/platform-domain-names.js.map +1 -0
  270. package/src/lib/server/platform-marketing-consent.d.ts +133 -0
  271. package/src/lib/server/platform-marketing-consent.js +209 -0
  272. package/src/lib/server/platform-marketing-consent.js.map +1 -0
  273. package/src/lib/server/rate-limit-store.d.ts +702 -0
  274. package/src/lib/server/rate-limit-store.js +1220 -0
  275. package/src/lib/server/rate-limit-store.js.map +1 -0
  276. package/src/lib/server/realm-plugins.d.ts +67 -0
  277. package/src/lib/server/realm-plugins.js +250 -0
  278. package/src/lib/server/realm-plugins.js.map +1 -0
  279. package/src/lib/server/recaptcha-allowlist.d.ts +90 -0
  280. package/src/lib/server/recaptcha-allowlist.js +409 -0
  281. package/src/lib/server/recaptcha-allowlist.js.map +1 -0
  282. package/src/lib/server/release-flags.d.ts +105 -0
  283. package/src/lib/server/release-flags.js +183 -0
  284. package/src/lib/server/release-flags.js.map +1 -0
  285. package/src/lib/server/replay-erasures.d.ts +126 -0
  286. package/src/lib/server/replay-erasures.js +217 -0
  287. package/src/lib/server/replay-erasures.js.map +1 -0
  288. package/src/lib/server/resolve-people.d.ts +66 -0
  289. package/src/lib/server/resolve-people.js +112 -0
  290. package/src/lib/server/resolve-people.js.map +1 -0
  291. package/src/lib/server/safe-equal.d.ts +45 -0
  292. package/src/lib/server/safe-equal.js +58 -0
  293. package/src/lib/server/safe-equal.js.map +1 -0
  294. package/src/lib/server/sending-domain-debt.d.ts +127 -0
  295. package/src/lib/server/sending-domain-debt.js +268 -0
  296. package/src/lib/server/sending-domain-debt.js.map +1 -0
  297. package/src/lib/server/sending-domain-recheck.d.ts +151 -0
  298. package/src/lib/server/sending-domain-recheck.js +253 -0
  299. package/src/lib/server/sending-domain-recheck.js.map +1 -0
  300. package/src/lib/server/sending-domains.d.ts +364 -0
  301. package/src/lib/server/sending-domains.js +683 -0
  302. package/src/lib/server/sending-domains.js.map +1 -0
  303. package/src/lib/server/serve-media-cdn.d.ts +433 -0
  304. package/src/lib/server/serve-media-cdn.js +1370 -0
  305. package/src/lib/server/serve-media-cdn.js.map +1 -0
  306. package/src/lib/server/serve-plugin-fetch.d.ts +61 -0
  307. package/src/lib/server/serve-plugin-fetch.js +294 -0
  308. package/src/lib/server/serve-plugin-fetch.js.map +1 -0
  309. package/src/lib/server/sms-keywords.d.ts +63 -0
  310. package/src/lib/server/sms-keywords.js +146 -0
  311. package/src/lib/server/sms-keywords.js.map +1 -0
  312. package/src/lib/server/sso-break-glass-owners.d.ts +91 -0
  313. package/src/lib/server/sso-break-glass-owners.js +227 -0
  314. package/src/lib/server/sso-break-glass-owners.js.map +1 -0
  315. package/src/lib/server/sso-domain-policy.d.ts +140 -0
  316. package/src/lib/server/sso-domain-policy.js +239 -0
  317. package/src/lib/server/sso-domain-policy.js.map +1 -0
  318. package/src/lib/server/sso-drift-logic.d.ts +106 -0
  319. package/src/lib/server/sso-drift-logic.js +95 -0
  320. package/src/lib/server/sso-drift-logic.js.map +1 -0
  321. package/src/lib/server/sso-enforcement.d.ts +204 -0
  322. package/src/lib/server/sso-enforcement.js +309 -0
  323. package/src/lib/server/sso-enforcement.js.map +1 -0
  324. package/src/lib/server/sso-provisioning.d.ts +320 -0
  325. package/src/lib/server/sso-provisioning.js +715 -0
  326. package/src/lib/server/sso-provisioning.js.map +1 -0
  327. package/src/lib/server/staff-alert-email.d.ts +41 -0
  328. package/src/lib/server/staff-alert-email.js +63 -0
  329. package/src/lib/server/staff-alert-email.js.map +1 -0
  330. package/src/lib/server/stripe-account-mode.d.ts +156 -0
  331. package/src/lib/server/stripe-account-mode.js +162 -0
  332. package/src/lib/server/stripe-account-mode.js.map +1 -0
  333. package/src/lib/server/tenant-write-lockdown.d.ts +131 -0
  334. package/src/lib/server/tenant-write-lockdown.js +176 -0
  335. package/src/lib/server/tenant-write-lockdown.js.map +1 -0
  336. package/src/lib/server/test-firestore.d.ts +45 -0
  337. package/src/lib/server/test-firestore.js +124 -0
  338. package/src/lib/server/test-firestore.js.map +1 -0
  339. package/src/lib/server/token-revocation.d.ts +140 -0
  340. package/src/lib/server/token-revocation.js +255 -0
  341. package/src/lib/server/token-revocation.js.map +1 -0
  342. package/src/lib/server/update-existing.d.ts +32 -0
  343. package/src/lib/server/update-existing.js +73 -0
  344. package/src/lib/server/update-existing.js.map +1 -0
  345. package/src/lib/server/upload-cors-reconcile.d.ts +118 -0
  346. package/src/lib/server/upload-cors-reconcile.js +234 -0
  347. package/src/lib/server/upload-cors-reconcile.js.map +1 -0
  348. package/src/lib/server/upsert-contact.d.ts +262 -0
  349. package/src/lib/server/upsert-contact.js +546 -0
  350. package/src/lib/server/upsert-contact.js.map +1 -0
  351. package/src/lib/server/usage-invoice.d.ts +203 -0
  352. package/src/lib/server/usage-invoice.js +397 -0
  353. package/src/lib/server/usage-invoice.js.map +1 -0
  354. package/src/lib/server/user-profiles.d.ts +151 -0
  355. package/src/lib/server/user-profiles.js +364 -0
  356. package/src/lib/server/user-profiles.js.map +1 -0
  357. package/src/lib/server/vercel-drain-signature.d.ts +30 -0
  358. package/src/lib/server/vercel-drain-signature.js +61 -0
  359. package/src/lib/server/vercel-drain-signature.js.map +1 -0
  360. package/src/lib/server/vercel-log-drain.d.ts +259 -0
  361. package/src/lib/server/vercel-log-drain.js +479 -0
  362. package/src/lib/server/vercel-log-drain.js.map +1 -0
  363. package/src/lib/server/verify-email-cooldown.d.ts +102 -0
  364. package/src/lib/server/verify-email-cooldown.js +114 -0
  365. package/src/lib/server/verify-email-cooldown.js.map +1 -0
  366. package/src/lib/server/visitor-write-rate-limit.d.ts +87 -0
  367. package/src/lib/server/visitor-write-rate-limit.js +117 -0
  368. package/src/lib/server/visitor-write-rate-limit.js.map +1 -0
  369. package/src/lib/server/workspace-domains.d.ts +156 -0
  370. package/src/lib/server/workspace-domains.js +271 -0
  371. package/src/lib/server/workspace-domains.js.map +1 -0
  372. package/src/tenancy.d.ts +115 -0
  373. package/src/tenancy.js +142 -0
  374. package/src/tenancy.js.map +1 -0
@@ -0,0 +1,546 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { CAPTURED_BY_HOST_FIELD, checkCrmRecordsQuota, consentGroupScope, CONTACT_FACETS_FIELD, CONTACT_FORM_IDS_CAP, CONTACT_FORM_IDS_FIELD, marketingConsentFieldsForGroup, mergeContactInteraction, normalizeCampaignIds, readContactFacet, normalizeContactEmail, ORG_SCOPE_TOKEN } from "@aglyn/aglyn/server";
18
+ import { FieldValue } from "firebase-admin/firestore";
19
+ import { firebaseAdmin } from "./firebase-admin.js";
20
+ import { countCrmRecords } from "./crm-records.js";
21
+ import { attributeOrderToEmail } from "./email-revenue-attribution.js";
22
+ import { hostRefusesCaptureForErasure } from "./email-suppression.js";
23
+ import { attributeCampaignConversion } from "./campaign-conversion-attribution.js";
24
+ import { nameSearchFields } from "@aglyn/aglyn/app-utils/name-search";
25
+ import { declineMarketingConsentFields, MARKETING_CONSENT_SOURCE_FIELD } from "@aglyn/aglyn/app-utils/marketing-consent";
26
+ /*
27
+ * The module paths, like `name-search` above, rather than the barrel: the
28
+ * pure helpers this door leans on are exactly the ones a spec of the door
29
+ * substitutes a fixture barrel for, and a fixture that has to re-export the
30
+ * whole of `@aglyn/aglyn` to keep a normalizer reachable is a fixture that
31
+ * drifts. A direct path is real in every harness.
32
+ */ import { advanceContactLifecycleStage, CONTACT_COMPANY_IDS_FIELD, CONTACT_FIELD_KEY_PATTERN, CRM_COLLECTIONS, isContactLifecycleStage, planContactCompanyLink, readContactCompanyLink } from "@aglyn/aglyn/app-utils/crm";
33
+ import { normalizeAddress, normalizePhone } from "@aglyn/aglyn/foundation/definitions/contact.types";
34
+ import { contactCompanyMirrorValue, settleCompanyContactsCounts } from "./contact-company-link.js";
35
+ import { emailIndexBeside, findContactByEmail, writeContactEmailIndex } from "./contact-email-index.js";
36
+ import { consentGroupForSite, getOrgForHost, orgDataCollectionForHost } from "./organizations.js";
37
+ /**
38
+ * The profile as it may be STORED: every value normalized, every unusable
39
+ * one dropped, and nothing present that was not given.
40
+ *
41
+ * Only the keys given come back, which is what lets a merge write this
42
+ * straight into the facet: a door that knows the phone number and nothing
43
+ * else leaves the title, the owner and the stage exactly as another door
44
+ * left them. An address given as `null` is a deliberate clearing and is kept
45
+ * as `null`; one that normalizes to nothing is the same thing.
46
+ */ function storableProfile(input) {
47
+ if (!input) return {};
48
+ const out = {};
49
+ if (input.phone !== undefined) {
50
+ const phone = normalizePhone(input.phone);
51
+ if (phone) out.phone = phone;
52
+ }
53
+ if (typeof input.jobTitle === 'string') {
54
+ const jobTitle = input.jobTitle.trim().slice(0, 120);
55
+ if (jobTitle) out.jobTitle = jobTitle;
56
+ }
57
+ if (input.address !== undefined) out.address = normalizeAddress(input.address);
58
+ if (typeof input.companyId === 'string' && input.companyId.trim()) {
59
+ out.companyId = input.companyId.trim().slice(0, 128);
60
+ }
61
+ if (typeof input.ownerUid === 'string' && input.ownerUid.trim()) {
62
+ out.ownerUid = input.ownerUid.trim().slice(0, 128);
63
+ }
64
+ if (isContactLifecycleStage(input.lifecycleStage)) {
65
+ out.lifecycleStage = input.lifecycleStage;
66
+ }
67
+ if (input.custom && typeof input.custom === 'object') {
68
+ /*
69
+ * Only a key a field definition could have, and only a value the field
70
+ * types can hold. A nested object here is a map the merge below would
71
+ * write as a subtree nobody can render; a key with a dot in it would be
72
+ * read as a PATH by the next dotted update to touch the facet. Nothing is
73
+ * coerced — a door that has a number should send one — and an empty map
74
+ * is left off rather than written as `{}` over a holder's values.
75
+ */ const custom = {};
76
+ for (const [key, value] of Object.entries(input.custom)){
77
+ if (!CONTACT_FIELD_KEY_PATTERN.test(key)) continue;
78
+ if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
79
+ custom[key] = typeof value === 'string' ? value.slice(0, 2000) : value;
80
+ }
81
+ }
82
+ if (Object.keys(custom).length) out.custom = custom;
83
+ }
84
+ return out;
85
+ }
86
+ /**
87
+ * The org's companies collection, beside its contacts one.
88
+ *
89
+ * Reached through the contacts reference's parent — the org document —
90
+ * because that is the one handle this function holds on the org. `parent`
91
+ * is `null` only for a root collection, which an org subcollection never
92
+ * is; answered as `null` rather than thrown so a count that has nowhere to
93
+ * land is skipped, and never costs the capture.
94
+ */ function companiesBeside(contactsRef) {
95
+ const parent = contactsRef.parent;
96
+ return parent ? parent.collection(CRM_COLLECTIONS.companies) : null;
97
+ }
98
+ /**
99
+ * Tags as the profile drawer stores them: trimmed, lowercased, deduplicated
100
+ * and capped at twenty — so an imported `VIP` and a typed `vip` are one tag.
101
+ */ function normalizeTags(tags) {
102
+ return [
103
+ ...new Set((tags != null ? tags : []).map((tag)=>String(tag != null ? tag : '').trim().toLowerCase()).filter(Boolean))
104
+ ].slice(0, 20);
105
+ }
106
+ export async function upsertHostContact(options) {
107
+ try {
108
+ var _options_interaction_atMs, _options_campaignIds, _ref, _contactsRef_parent, _ref1, _ref2;
109
+ var _options_facet, _orgBilling_org;
110
+ const email = normalizeContactEmail(options.email);
111
+ if (!email) return {
112
+ refused: 'invalid-email'
113
+ };
114
+ const tags = normalizeTags(options.tags);
115
+ /*==========================================
116
+ * THE PURCHASE DOOR, AND THEREFORE THE ATTRIBUTION DOOR.
117
+ *
118
+ * Every way of buying something in this product — the cart, buy-now, the
119
+ * POS register, a draft order, a reservation, a subscription renewal, a
120
+ * booking — announces itself here, in exactly one shape: source `order`,
121
+ * a `purchaseCents` amount, and a `refId` naming what was bought. That
122
+ * shape IS the purchase chokepoint, which is why the revenue join hangs
123
+ * off it rather than off seven call sites in a webhook.
124
+ *
125
+ * ABOVE the audience-band gate below, and deliberately. Contact creation
126
+ * is band gated, so a Free org past its included count drops the CRM
127
+ * record — and an attribution written inside that branch would drop the
128
+ * revenue with it. The join keys on the address hash, exactly as the
129
+ * touch and the suppression list do, so it never needs a contact document
130
+ * to exist: a guest checkout by somebody who is not and never becomes a
131
+ * contact still credits the campaign whose link they clicked.
132
+ *
133
+ * Its own `catch`, inside a function that already swallows: this is the
134
+ * least important write on the path, and a failure here must not cost the
135
+ * contact capture below it.
136
+ *=========================================*/ if (options.source === 'order' && options.interaction.refId) {
137
+ var _options_purchaseCents, _options_interaction_atMs1;
138
+ await attributeOrderToEmail(_extends({
139
+ hostId: options.hostId,
140
+ orderId: String(options.interaction.refId),
141
+ email,
142
+ amountCents: Number((_options_purchaseCents = options.purchaseCents) != null ? _options_purchaseCents : 0)
143
+ }, options.purchaseCurrency ? {
144
+ currency: options.purchaseCurrency
145
+ } : {}, {
146
+ orderedAtMs: (_options_interaction_atMs1 = options.interaction.atMs) != null ? _options_interaction_atMs1 : Date.now()
147
+ })).catch(()=>null);
148
+ }
149
+ const firestore = firebaseAdmin.app().firestore();
150
+ const hostRef = firestore.collection('hosts').doc(options.hostId);
151
+ // Contacts are org-scoped (AGL-237): every host in the org feeds one
152
+ // shared list.
153
+ const contactsRef = await orgDataCollectionForHost(options.hostId, 'contacts');
154
+ /*
155
+ * The consent group this capture belongs to — the sites declared to be
156
+ * one sender, or this site alone. Resolved once and used for three
157
+ * different decisions below, which must all agree: which controller the
158
+ * basis is recorded for, which sites the row becomes visible to, and
159
+ * whether the capture surface had to disclose anything.
160
+ */ const group = await consentGroupForSite(options.hostId);
161
+ /*
162
+ * THE CONSENT ENTRY THIS CAPTURE WRITES, decided once for both branches.
163
+ *
164
+ * A grant outranks a refusal flag set beside it — one door cannot mean
165
+ * both — and neither writes anything when the door carried no act, so
166
+ * an unticked box stays the third state. The provenance rides inside the
167
+ * per-host entry, where the reader looks for it, never at the top of a
168
+ * document every brand in the org shares.
169
+ */ const consentExtra = options.marketingConsentSource ? {
170
+ [MARKETING_CONSENT_SOURCE_FIELD]: options.marketingConsentSource
171
+ } : undefined;
172
+ const consentFields = options.marketingConsent ? marketingConsentFieldsForGroup(group, Date.now(), consentExtra) : options.declineMarketingConsent ? declineMarketingConsentFields(options.hostId, Date.now(), consentExtra) : {};
173
+ const interaction = _extends({
174
+ type: options.source,
175
+ atMs: (_options_interaction_atMs = options.interaction.atMs) != null ? _options_interaction_atMs : Date.now(),
176
+ // WHICH SITE this visit happened on. The row is shared; the history on
177
+ // it is not, and a timeline with no site cannot be split for an
178
+ // agency's client without showing them another client's activity.
179
+ hostId: options.hostId
180
+ }, options.interaction.refId ? {
181
+ refId: options.interaction.refId
182
+ } : {}, options.interaction.summary ? {
183
+ summary: options.interaction.summary.slice(0, 200)
184
+ } : {}, options.interaction.formId ? {
185
+ formId: String(options.interaction.formId).slice(0, 128)
186
+ } : {}, options.interaction.path ? {
187
+ path: String(options.interaction.path).slice(0, 500)
188
+ } : {});
189
+ /*
190
+ * THE CAMPAIGNS THIS CAPTURE FILES THE PERSON UNDER.
191
+ *
192
+ * Normalized here rather than trusted, because it reaches this function
193
+ * from a public endpoint's document read and every reader of the stored
194
+ * array goes through the same coercion.
195
+ */ const campaignIds = normalizeCampaignIds((_options_campaignIds = options.campaignIds) != null ? _options_campaignIds : []);
196
+ /*
197
+ * THE CUSTOM FIELD VALUES THIS CAPTURE CARRIES, as one nested map.
198
+ *
199
+ * Only the keys the door resolved. Written in the NESTED form because both
200
+ * writes below are merge-sets, which deep-merge a map one key at a time:
201
+ * `custom: { tier: 'Gold' }` lands beside an existing `custom.vip` and
202
+ * leaves it standing. A dotted `facets.h1.custom.tier` path would be a
203
+ * literal field name to a `set`, and a `custom` written whole would take
204
+ * every other key with it.
205
+ */ const customEntries = Object.entries((_ref = (_options_facet = options.facet) == null ? void 0 : _options_facet.custom) != null ? _ref : {});
206
+ const customFacet = customEntries.length ? {
207
+ custom: Object.fromEntries(customEntries)
208
+ } : {};
209
+ /*==========================================
210
+ * THE DEDUPE LOOKUP IS UNSCOPED, AND HAS TO BE.
211
+ *
212
+ * One human who touched two sites is ONE person. Narrowing this read to
213
+ * what the capturing site may already see would make a second submission
214
+ * on a sibling brand create a SECOND document for the same address —
215
+ * which loses the dedupe the shared address book exists for, and bills
216
+ * the org twice for one human.
217
+ *
218
+ * Recognizing somebody is not the same act as being allowed to read their
219
+ * row, and the two were the same query while every contact was stamped
220
+ * org-wide. They are separated here: this finds the person, and
221
+ * `visibleTo` below decides who may see them — widened by the capture
222
+ * that just happened, never by the lookup that found them.
223
+ *
224
+ * THROUGH THE ADDRESS INDEX FIRST (AGL-2625). A person whose two records
225
+ * were merged answers to two addresses, and only one of them is the
226
+ * document's `email`; the index is what lets a capture on the other one
227
+ * land on the survivor instead of minting the duplicate again. The query
228
+ * stays as the fallback, so a row the index has not seen costs one extra
229
+ * read once and needs no backfill.
230
+ *=========================================*/ const docSnapshot = await findContactByEmail(contactsRef, email);
231
+ if (docSnapshot) {
232
+ var _facet_name, _profile_lifecycleStage;
233
+ /*
234
+ * MERGED INTO THIS GROUP'S FACET, not into the top of the document.
235
+ *
236
+ * `sources`, `interactions`, the tags, the notes and every commercial
237
+ * figure are the HOLDER's own business records: a booking taken by one
238
+ * client of an agency is that client's, and while these lived at the
239
+ * top of a shared row every other client could read them. The identity
240
+ * — the address, and a canonical name for a holder that has set none of
241
+ * its own — stays shared, because that is what makes this one row.
242
+ */ const facet = readContactFacet(docSnapshot.data(), group.groupId);
243
+ const merged = mergeContactInteraction({
244
+ name: (_facet_name = facet.name) != null ? _facet_name : undefined,
245
+ sources: facet.sources,
246
+ interactions: facet.interactions
247
+ }, {
248
+ source: options.source,
249
+ interaction,
250
+ name: options.name
251
+ });
252
+ /*
253
+ * THE PROFILE, as this door knows it (AGL-2596).
254
+ *
255
+ * Given keys only, so the merge below leaves untouched whatever another
256
+ * door wrote. The stage is the one field with a rule of its own: the
257
+ * door's `initialLifecycleStage` fills an empty stage and advances an
258
+ * earlier one, and never moves anybody back —
259
+ * `advanceContactLifecycleStage` is that rule, applied to the stage
260
+ * this door asked for outright or, failing that, the one already
261
+ * stored. Written only when it comes back with something: a door that
262
+ * named no stage and found none leaves the key absent, which reads as
263
+ * "no stage" rather than as a stage somebody picked.
264
+ */ const profile = storableProfile(options.facet);
265
+ const advanced = advanceContactLifecycleStage((_profile_lifecycleStage = profile.lifecycleStage) != null ? _profile_lifecycleStage : facet.lifecycleStage, options.initialLifecycleStage);
266
+ if (advanced) profile.lifecycleStage = advanced;
267
+ /*
268
+ * THE FORM MIRROR, bounded (see `HostContact.formIds`).
269
+ *
270
+ * Read off the document the lookup already fetched, so the bound costs
271
+ * no extra read: a person who has come in through twenty forms keeps
272
+ * the twenty, and this capture's form stays on the interaction alone.
273
+ * `arrayUnion` for the add, so a concurrent capture on a sibling site
274
+ * cannot drop this one's id.
275
+ */ const heldFormIds = Array.isArray(docSnapshot.get(CONTACT_FORM_IDS_FIELD)) ? docSnapshot.get(CONTACT_FORM_IDS_FIELD) : [];
276
+ const formIdToAdd = interaction.formId && !heldFormIds.includes(interaction.formId) && heldFormIds.length < CONTACT_FORM_IDS_CAP ? interaction.formId : null;
277
+ /*
278
+ * THE COMPANY LINK, when the door carried one (AGL-2613).
279
+ *
280
+ * The facet's `companyId` is written with the rest of the profile
281
+ * below, but the facet is not the whole association: the top-level
282
+ * `companyIds` mirror is what the company page queries, and the
283
+ * company's `contactsCount` is what the companies list shows. The
284
+ * planner reads the row as it stands — this holder's previous link,
285
+ * the mirror, the other holders' ids — and says what the mirror
286
+ * becomes and which counts move; the mirror change rides in this same
287
+ * merge-set, and the counts settle after it.
288
+ */ const link = profile.companyId !== undefined ? planContactCompanyLink(readContactCompanyLink(docSnapshot.data(), group.groupId), profile.companyId) : null;
289
+ const mirror = link ? contactCompanyMirrorValue(link) : undefined;
290
+ await docSnapshot.ref.set(_extends({}, merged.name ? nameSearchFields(merged.name) : {}, profile.phone ? {
291
+ phone: profile.phone
292
+ } : {}, mirror !== undefined ? {
293
+ [CONTACT_COMPANY_IDS_FIELD]: mirror
294
+ } : {}, {
295
+ /*
296
+ * NESTED, not dot-pathed. This is a `set(…, { merge: true })`, and
297
+ * a merge-set treats a key containing dots as a literal field name
298
+ * — only `update()` reads them as paths. The nested form is what
299
+ * Firestore deep-merges, so this writes one holder's facet and
300
+ * leaves every other holder's untouched.
301
+ */ [CONTACT_FACETS_FIELD]: {
302
+ [group.groupId]: _extends({
303
+ sources: merged.sources,
304
+ interactions: merged.interactions
305
+ }, merged.name ? {
306
+ name: merged.name
307
+ } : {}, campaignIds.length ? {
308
+ campaignIds: FieldValue.arrayUnion(...campaignIds)
309
+ } : {}, tags.length ? {
310
+ tags: FieldValue.arrayUnion(...tags)
311
+ } : {}, profile, options.purchaseCents ? _extends({
312
+ ltvCents: FieldValue.increment(options.purchaseCents),
313
+ ordersCount: FieldValue.increment(1),
314
+ lastPurchaseAtMs: Date.now()
315
+ }, facet.firstPurchaseAtMs ? {} : {
316
+ firstPurchaseAtMs: Date.now()
317
+ }) : {})
318
+ },
319
+ /*
320
+ * ATTRIBUTION GROWS ON THE MERGE BRANCH, which the create-only
321
+ * `hostId` beside it never did — so a person the first site
322
+ * captured and the second site later met read as the first site's
323
+ * alone, forever.
324
+ *
325
+ * `arrayUnion`, so the audience filter "everyone captured on A, B
326
+ * or C" answers with the sites that actually met this person.
327
+ */ [CAPTURED_BY_HOST_FIELD]: FieldValue.arrayUnion(options.hostId)
328
+ }, formIdToAdd ? {
329
+ [CONTACT_FORM_IDS_FIELD]: FieldValue.arrayUnion(formIdToAdd)
330
+ } : {}, {
331
+ /*
332
+ * AND SO DOES VISIBILITY — by the capture, never by the lookup.
333
+ *
334
+ * This site just collected this person: it has its own relationship
335
+ * with them and may see the row. A site that has never captured
336
+ * them gains nothing here, which is what keeps an agency's clients
337
+ * apart on a document all of them share. The per-interaction
338
+ * `hostId` above is what keeps the HISTORY apart on the same row.
339
+ */ visibleTo: FieldValue.arrayUnion(...consentGroupScope(group))
340
+ }, consentFields, {
341
+ updatedAt: FieldValue.serverTimestamp()
342
+ }), {
343
+ merge: true
344
+ });
345
+ await settleCompanyContactsCounts(companiesBeside(contactsRef), link);
346
+ return {
347
+ contactId: docSnapshot.id,
348
+ created: false
349
+ };
350
+ }
351
+ /*
352
+ * THE ERASED PERSON DOES NOT COME BACK (AGL-2623).
353
+ *
354
+ * Before the band, on the CREATE branch only — the one read this adds
355
+ * is paid by a capture that would otherwise make a new row, never by
356
+ * the merge above. An erasure wrote a row on this site's suppression
357
+ * list with no address on it; finding that row here is what keeps the
358
+ * next form fill or checkout from rebuilding the record the workspace
359
+ * just erased. The order or booking that triggered the capture still
360
+ * succeeds, exactly as it does when the band refuses: the person bought
361
+ * something, and the merchant's record of the sale is not the CRM's
362
+ * record of the person.
363
+ */ if (await hostRefusesCaptureForErasure(options.hostId, email, firestore)) {
364
+ return {
365
+ refused: 'erased'
366
+ };
367
+ }
368
+ // New contact: records-band check via the aggregate counts (cheap; no
369
+ // doc reads) against the owning org's entitlements (AGL-238/890).
370
+ // Metered plans always pass (overage bills via the report-usage
371
+ // cron); only free's hard band drops the CRM record — visibly, via
372
+ // the counter and the console alert (AGL-891). The signup/order that
373
+ // triggered the capture always succeeds either way.
374
+ //
375
+ // THE RECORDS BAND, not the contacts headcount (AGL-2611): companies
376
+ // and deals share this band, so a capture is refused on a Free org
377
+ // whose hundred records are ninety companies and ten people — the same
378
+ // verdict the company drawer would give the ninety-first company.
379
+ // `contactsRef` is handed in so the contacts aggregate is the one this
380
+ // door already reads; the org reference is its parent.
381
+ const orgBilling = await getOrgForHost(options.hostId);
382
+ const orgRef = (_contactsRef_parent = contactsRef.parent) != null ? _contactsRef_parent : firestore.collection('orgs').doc(String((_ref1 = orgBilling == null ? void 0 : orgBilling.orgId) != null ? _ref1 : ''));
383
+ const { crmRecordsCount } = await countCrmRecords(orgRef, contactsRef);
384
+ const quota = checkCrmRecordsQuota((_ref2 = orgBilling == null ? void 0 : orgBilling.org) != null ? _ref2 : null, crmRecordsCount);
385
+ if (!quota.allowed) {
386
+ await hostRef.collection('counters').doc('contactsDropped').set({
387
+ total: FieldValue.increment(1)
388
+ }, {
389
+ merge: true
390
+ });
391
+ return {
392
+ refused: 'band'
393
+ };
394
+ }
395
+ /*
396
+ * The profile on a create, with the door's stage floor applied the same
397
+ * way as on a merge — there is no stored stage yet, so the floor is what
398
+ * a door that named one writes. A `null` address is dropped rather than
399
+ * written: there is nothing on a new document for it to clear.
400
+ */ const profile = storableProfile(options.facet);
401
+ const advanced = advanceContactLifecycleStage(profile.lifecycleStage, options.initialLifecycleStage);
402
+ if (advanced) profile.lifecycleStage = advanced;
403
+ if (profile.address === null) delete profile.address;
404
+ const created = await contactsRef.add(_extends({
405
+ hostId: options.hostId,
406
+ /*
407
+ * WHICH SITES HAVE MET THIS PERSON — attribution, and separate from
408
+ * consent above.
409
+ *
410
+ * The scalar `hostId` beside it names the FIRST capturing site and is
411
+ * never rewritten, which is provenance for the ROW. This array is the
412
+ * one that grows and the one an audience query can filter on.
413
+ */ [CAPTURED_BY_HOST_FIELD]: [
414
+ options.hostId
415
+ ]
416
+ }, interaction.formId ? {
417
+ [CONTACT_FORM_IDS_FIELD]: [
418
+ interaction.formId
419
+ ]
420
+ } : {}, {
421
+ /*
422
+ * THE CAPTURING GROUP, not the whole org.
423
+ *
424
+ * Stamping `['org']` here made every contact readable by every site in
425
+ * the account on the day it was created — so an agency's twelve clients
426
+ * shared one address book by default, and closing the missing-field
427
+ * fail-open would not have touched it, because the field was present
428
+ * and said so.
429
+ *
430
+ * A group of one — the default — is this site alone. A declared group
431
+ * is the sites that already present as one sender. Widening beyond that
432
+ * is available and is an ACT: an org may set `defaultResourceScope` to
433
+ * `'org'`, or a later capture on a sibling site unions that site in.
434
+ */ visibleTo: (orgBilling == null ? void 0 : (_orgBilling_org = orgBilling.org) == null ? void 0 : _orgBilling_org.defaultResourceScope) === 'org' ? [
435
+ ORG_SCOPE_TOKEN
436
+ ] : consentGroupScope(group),
437
+ email
438
+ }, options.name ? nameSearchFields(options.name.slice(0, 120)) : {}, profile.phone ? {
439
+ phone: profile.phone
440
+ } : {}, profile.companyId ? {
441
+ [CONTACT_COMPANY_IDS_FIELD]: [
442
+ profile.companyId
443
+ ]
444
+ } : {}, {
445
+ // The facet this capture creates. Everything a holder owns lives under
446
+ // its own group id; the address and the canonical name above are the
447
+ // only shared identity.
448
+ [CONTACT_FACETS_FIELD]: {
449
+ [group.groupId]: _extends({
450
+ sources: {
451
+ [options.source]: true
452
+ },
453
+ interactions: [
454
+ interaction
455
+ ],
456
+ tags
457
+ }, campaignIds.length ? {
458
+ campaignIds
459
+ } : {}, customFacet, options.name ? {
460
+ name: options.name.slice(0, 120)
461
+ } : {}, profile, options.purchaseCents ? {
462
+ ltvCents: options.purchaseCents,
463
+ ordersCount: 1,
464
+ lastPurchaseAtMs: Date.now(),
465
+ firstPurchaseAtMs: Date.now()
466
+ } : {})
467
+ }
468
+ }, consentFields, {
469
+ createdAt: FieldValue.serverTimestamp(),
470
+ updatedAt: FieldValue.serverTimestamp()
471
+ }));
472
+ // The address now resolves to this row (AGL-2625). Its own catch inside
473
+ // the writer, so an index the capture could not reach costs nothing.
474
+ await writeContactEmailIndex(emailIndexBeside(contactsRef), created.id, [
475
+ email
476
+ ]);
477
+ // The company the door named now has one more contact naming it
478
+ // (AGL-2613) — the fresh row's plan is the trivial one, nothing held
479
+ // before and nothing held elsewhere.
480
+ if (profile.companyId) {
481
+ await settleCompanyContactsCounts(companiesBeside(contactsRef), planContactCompanyLink({
482
+ companyId: null,
483
+ companyIds: [],
484
+ heldElsewhere: []
485
+ }, profile.companyId));
486
+ }
487
+ /*
488
+ * ATTRIBUTED ON CREATION ONLY, and therefore below the band gate rather
489
+ * than above it — the opposite placement to the order join at the top of
490
+ * this function, deliberately.
491
+ *
492
+ * The order join sits above because it credits MONEY, which is real
493
+ * whether or not a CRM record was kept for the buyer, and a Free org past
494
+ * its included band would otherwise silently drop the revenue with the
495
+ * contact. This credits a contact, which does not exist when the band
496
+ * dropped it: attributing one above the gate would report a campaign as
497
+ * having produced people the customer cannot see anywhere in the console.
498
+ *
499
+ * The existing-contact branch above returns without reaching here, which
500
+ * is the same rule `addHostLead` applies — an interaction appended to
501
+ * somebody the site already held is another visit, not a new person, and
502
+ * crediting it would let the most recent campaign re-earn the whole list.
503
+ */ if (options.campaignTouch) {
504
+ await attributeCampaignConversion({
505
+ hostId: options.hostId,
506
+ kind: 'contact',
507
+ refId: created.id,
508
+ touch: options.campaignTouch,
509
+ convertedAtMs: interaction.atMs
510
+ });
511
+ }
512
+ /*
513
+ * REPORTED ON CREATION ONLY, below the band gate for the reason the
514
+ * attribution above is: a contact the band dropped does not exist, and
515
+ * an automation told about it would act on a person the console cannot
516
+ * show. The merge branch returned long before this line, so a repeat
517
+ * visit by somebody already held is never announced as a new contact.
518
+ */ if (options.onCreated) {
519
+ await Promise.resolve(options.onCreated(_extends({
520
+ contactId: created.id,
521
+ hostId: options.hostId,
522
+ email
523
+ }, options.name ? {
524
+ name: options.name.slice(0, 120)
525
+ } : {}, {
526
+ source: options.source,
527
+ campaignIds
528
+ }, profile.lifecycleStage ? {
529
+ lifecycleStage: profile.lifecycleStage
530
+ } : {}))).catch((error)=>{
531
+ console.error('upsertHostContact onCreated failed', error);
532
+ });
533
+ }
534
+ return {
535
+ contactId: created.id,
536
+ created: true
537
+ };
538
+ } catch (error) {
539
+ console.error('upsertHostContact failed', error);
540
+ return {
541
+ refused: 'error'
542
+ };
543
+ }
544
+ }
545
+
546
+ //# sourceMappingURL=upsert-contact.js.map