@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,837 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Server-side organization operations (AGL-233/234). Everything here is
19
+ * Admin-SDK-only by design: org creation, slug reservation, membership
20
+ * and the projections the security rules authorize against are never
21
+ * client-writable (docs/MULTI_TENANT_FIRESTORE.md §8).
22
+ */
23
+ import { type ConsentGroup, type AglynOrganization, type AglynOrgBilling, type AglynOrgMember, type HostAccessRole, type OrgPermission, type OrgRole } from '@aglyn/aglyn/server';
24
+ import type { PluginActivityTargetType } from '@aglyn/aglyn/plugin-manager/plugin-activity-actions';
25
+ import type { HostActivityActor } from '@aglyn/aglyn/app-utils/activity-presenter';
26
+ export declare class OrgSlugTakenError extends Error {
27
+ constructor(slug: string);
28
+ }
29
+ /**
30
+ * ⛔ NOTHING WRITES A NEW `reservedUntil` ANY MORE — AND THE RULES THAT READ
31
+ * ONE STAY (AGL-2590).
32
+ *
33
+ * AGL-2585 gave a workspace created by an UNVERIFIED owner a held address
34
+ * rather than a granted one, because a signup could create a workspace before
35
+ * anything proved the email belonged to the person typing it. That is no
36
+ * longer possible: `/api/orgs/create` refuses an unverified caller outright,
37
+ * the sign-up form holds its typed name against the account instead, and the
38
+ * workspace is created on the first verified session. There is no path left
39
+ * that can produce an unproven address, so `createOrganization` writes the
40
+ * plain grant this collection has always held and the twenty-one-day
41
+ * reservation window is gone with the code that set it.
42
+ *
43
+ * The READ side below is deliberately kept, and it is not dead weight:
44
+ * production holds `orgSlugs` documents that WERE written with an expiry,
45
+ * before this. Deleting the lapse rules would silently promote every one of
46
+ * those squats to a permanent grant — the exact outcome AGL-2585 existed to
47
+ * end. They stay until `reap-unverified-orgs` has erased or promoted the last
48
+ * of them.
49
+ *
50
+ * Has a PENDING address reservation run out?
51
+ *
52
+ * A reservation with no `reservedUntil` is a GRANT and never lapses, which is
53
+ * what keeps every workspace made by a verified owner — and every one that
54
+ * predates the field — untouchable by this rule.
55
+ *
56
+ * A `reservedUntil` that is not a finite number never lapses either: a
57
+ * corrupt or half-written expiry is a reason to leave an address alone, not a
58
+ * reason to hand it to the next caller.
59
+ */
60
+ export declare function isSlugReservationLapsed(reservation: {
61
+ orgId?: unknown;
62
+ movedTo?: unknown;
63
+ reservedUntil?: unknown;
64
+ } | undefined, now?: number): boolean;
65
+ /**
66
+ * Whether an `orgSlugs/{slug}` reservation may be (re)claimed (AGL-585):
67
+ * free when the doc is missing, when the claimant already owns it, or when
68
+ * it is a tombstone (`movedTo` set) — a renamed-away slug keeps redirecting
69
+ * old URLs only until someone wants it, it is never reserved forever.
70
+ * Claiming writes a full-replace `{ orgId }`, which ends the redirect —
71
+ * links to a reclaimed slug resolve to the new owner from then on.
72
+ *
73
+ * A LAPSED PENDING RESERVATION is claimable too (AGL-2585). The reservation
74
+ * an unverified signup takes is a hold, not a grant, and a hold that never
75
+ * expires is the squat this rule exists to end.
76
+ *
77
+ * ⚠️ Claimable here is NOT the whole answer for a lapsed reservation — see
78
+ * {@link lapsedReservationIsStillHeld}, which both call sites consult before
79
+ * they act on a `true` that came from the lapse branch. This function is pure
80
+ * and cannot ask whether the owner has verified since; treating its answer as
81
+ * final would let a customer who verified on day one lose their address on
82
+ * day twenty-one because a sweep was down.
83
+ */
84
+ export declare function isSlugReservationClaimable(reservation: {
85
+ orgId?: unknown;
86
+ movedTo?: unknown;
87
+ reservedUntil?: unknown;
88
+ } | undefined, claimingOrgId: string | null, now?: number): boolean;
89
+ export interface CreateOrganizationOptions {
90
+ name: string;
91
+ slug: string;
92
+ ownerUid: string;
93
+ ownerEmail?: string | null;
94
+ ownerDisplayName?: string | null;
95
+ /**
96
+ * Skip the AGL-2265 free-workspace ceiling.
97
+ *
98
+ * For staff provisioning on a customer's behalf and for the migration and
99
+ * backfill scripts — a ceiling that stops support from fixing a workspace
100
+ * is a ceiling that produces the ticket it was meant to prevent. Never set
101
+ * from a self-serve path; `/api/orgs/create` passes the staff claim and
102
+ * nothing else.
103
+ */
104
+ bypassFreeWorkspaceCap?: boolean;
105
+ }
106
+ /**
107
+ * Creates an org in one transaction: slug reservation (uniqueness), org
108
+ * doc, owner membership, and the owner's reverse-index entry. Throws
109
+ * `OrgSlugTakenError` when the slug is reserved; slug validity is the
110
+ * caller's job (API routes return 400 with policy copy).
111
+ */
112
+ export declare function createOrganization(options: CreateOrganizationOptions): Promise<string>;
113
+ export interface OrgMembershipResolution {
114
+ orgId: string;
115
+ member: AglynOrgMember;
116
+ /**
117
+ * True only when THIS call provisioned the org, so a caller can report the
118
+ * activation (AGL-2587). `ensureOrgForUser` is the third org-creation door
119
+ * and the only server-side one, and it looked identical from outside to a
120
+ * resolution of an org that already existed — which is why `org_created`
121
+ * counted none of the workspaces it makes. Absent on `resolveOrgMembership`,
122
+ * which never creates anything.
123
+ */
124
+ created?: boolean;
125
+ }
126
+ /**
127
+ * The signed-in user's membership in one org, or null. When `orgId` is
128
+ * omitted, resolves the user's first org from the reverse index (the
129
+ * single-org case every pre-org account lands in after backfill).
130
+ */
131
+ export declare function resolveOrgMembership(uid: string, orgId?: string | null): Promise<OrgMembershipResolution | null>;
132
+ /**
133
+ * The user's org, creating a personal one on first need (signup flows and
134
+ * pre-backfill accounts): name from the display name or email local part,
135
+ * slug generated with numeric-suffix retries on collision.
136
+ */
137
+ export declare function ensureOrgForUser(uid: string, profile?: {
138
+ email?: string | null;
139
+ displayName?: string | null;
140
+ }): Promise<OrgMembershipResolution>;
141
+ /**
142
+ * Changes an org's workspace slug (AGL-236): reserves the new slug and
143
+ * updates the org doc in one transaction, leaving the old reservation as
144
+ * a tombstone (`movedTo`) so existing workspace URLs keep resolving —
145
+ * the middleware redirects them. Reverse-index slugs fan out after.
146
+ * Throws `OrgSlugTakenError` only when another org ACTIVELY holds the new
147
+ * slug — tombstones are claimable (AGL-585). Slug validity/authorization
148
+ * are the API route's job.
149
+ */
150
+ export declare function changeOrgSlug(orgId: string, newSlug: string): Promise<{
151
+ previousSlug: string | null;
152
+ }>;
153
+ /**
154
+ * Host → org resolution via the server-written `hostIndex` mirror.
155
+ *
156
+ * `React.cache`-deduped PER REQUEST (AGL-1302): one tenant render resolved
157
+ * this hop up to five times — org billing, datasets, plugin installs, realm
158
+ * installs and the publish-schedule executor each re-read the same
159
+ * `hostIndex/{hostId}` doc. Per-request memoization is zero-staleness by
160
+ * construction; outside a React render (route handlers, jest) `cache` is a
161
+ * pass-through, so nothing changes for the console's authz paths.
162
+ */
163
+ export declare const resolveOrgIdForHost: (hostId: string) => Promise<string | null>;
164
+ /**
165
+ * The org doc itself — billing, plan, entitlements and suspension (the
166
+ * shape the legacy tenants/{uid} doc carried; orgs are the only billing
167
+ * source since AGL-238). Null when the doc is missing.
168
+ */
169
+ /**
170
+ * `React.cache`-deduped per request like {@link resolveOrgIdForHost}
171
+ * (AGL-1302). NOTE: within one render every caller receives the SAME object
172
+ * — treat it as read-only, as every current caller already does.
173
+ */
174
+ export declare const getOrgDoc: (orgId: string) => Promise<Partial<AglynOrganization> | null>;
175
+ /**
176
+ * Billing/entitlement source for a host (AGL-238): the owning org's doc
177
+ * via the hostIndex mirror. Null for unindexed hosts — callers treat that
178
+ * as the pre-billing fail-open (every feature on), the same contract the
179
+ * legacy tenants/{uid} read had.
180
+ */
181
+ export declare function getOrgForHost(hostId: string): Promise<{
182
+ orgId: string;
183
+ org: Partial<AglynOrganization>;
184
+ } | null>;
185
+ /**
186
+ * The raw host doc, `React.cache`-deduped per request like
187
+ * {@link resolveOrgIdForHost}. Null when missing. Added for AGL-1506 so a
188
+ * dispatcher that already pays this read for the plugin deny-list can also
189
+ * feed the host's `suspendedAt` family to the lockdown verdict without a
190
+ * second get. Same read-only contract as {@link getOrgDoc}.
191
+ */
192
+ export declare const getHostDocAdmin: (hostId: string) => Promise<Record<string, unknown> | null>;
193
+ /**
194
+ * The host's per-site plugin deny-list (AGL-1014), for API dispatch and any
195
+ * other server consumer of `resolveHostEnabledPlugins`. Rides
196
+ * {@link getHostDocAdmin}'s request-cached read. Fail-open to [] — an absent
197
+ * host doc or field means "nothing disabled here", never a lockout.
198
+ */
199
+ export declare const getHostDisabledPlugins: (hostId: string) => Promise<string[]>;
200
+ /**
201
+ * Billing/entitlement source for a user without host context (account-
202
+ * level APIs): the explicit workspace org when given, else the first org
203
+ * from the reverse index. Null for accounts with no org yet.
204
+ */
205
+ export declare function getOrgForUser(uid: string, orgId?: string | null): Promise<{
206
+ orgId: string;
207
+ org: Partial<AglynOrganization>;
208
+ member: AglynOrgMember;
209
+ } | null>;
210
+ /**
211
+ * Org-scoped data collection for a host (AGL-237): datasets, contacts and
212
+ * contactSegments live on the org so every host shares them.
213
+ *
214
+ * The pre-migration fallback to `hosts/{hostId}/{name}` is GONE (AGL-1050).
215
+ * The AGL-1040 backfill counted the docs still on it in production and
216
+ * found zero, so it was dead code rather than a migration — and a second
217
+ * storage path that can still be WRITTEN is a second boundary to enforce
218
+ * forever, which undoes the premise of scoped sharing: one home per
219
+ * resource plus an explicit scope.
220
+ *
221
+ * A host with no org is now an error rather than a silent write into a
222
+ * collection nothing reads. Every host has an org; `hostIndex` is written
223
+ * by `registerOrgHost` at creation.
224
+ */
225
+ /**
226
+ * The org-owned collections a host reads in its own context. Every one of
227
+ * these carries `visibleTo` (AGL-1037) and so must go through
228
+ * `scopedToHost` on any Admin-SDK path — `media` and `mediaFolders` were
229
+ * added for the export route (AGL-1046), which had been reading the
230
+ * legacy host path and exporting nothing at all.
231
+ */
232
+ export type OrgDataCollection = 'datasets' | 'contacts' | 'contactSegments' | 'crmViews' | 'lists' | 'media' | 'mediaFolders';
233
+ export declare function orgDataCollectionForHost(hostId: string, name: OrgDataCollection): Promise<FirebaseFirestore.CollectionReference>;
234
+ /**
235
+ * Narrows an org-scoped collection to what ONE host may see (AGL-1039).
236
+ *
237
+ * The Admin SDK does not evaluate Firestore rules, so AGL-1041's
238
+ * `visibleTo.hasAny(...)` protects the console and nothing else — every
239
+ * server read has to filter for itself or a client site can render another
240
+ * client's data. Use this instead of the bare collection ref anywhere a
241
+ * request is being served in the context of a single host.
242
+ *
243
+ * Only the ORG path is filtered — but no longer because of the legacy
244
+ * `hosts/{hostId}/…` fallback, which AGL-1050 removed on both the server
245
+ * (above) and the client. What survives it is the reason stated at the
246
+ * check itself: callers may hand this helper a ref they built themselves,
247
+ * and a host-library ref must never be filtered, since its docs carry no
248
+ * `visibleTo` and the filter would match nothing and blank the site.
249
+ */
250
+ export declare function scopedToHost(ref: FirebaseFirestore.CollectionReference, hostId: string): FirebaseFirestore.Query;
251
+ /**
252
+ * `orgDataCollectionForHost` + `scopedToHost` in one call — the form every
253
+ * host-context read should use. Returns the collection ref too, for the
254
+ * writes and `doc()` lookups a Query cannot express.
255
+ */
256
+ export declare function orgDataQueryForHost(hostId: string, name: OrgDataCollection): Promise<{
257
+ ref: FirebaseFirestore.CollectionReference;
258
+ query: FirebaseFirestore.Query;
259
+ }>;
260
+ /**
261
+ * Server-side permission check (AGL-243): the member's org-role defaults
262
+ * refined by their custom role doc (one read, only when assigned). API
263
+ * routes call this before privileged mutations.
264
+ */
265
+ /**
266
+ * The member's FULL granular permission set, custom role and per-member
267
+ * overrides applied (AGL-2350).
268
+ *
269
+ * `memberHasOrgPermission` below is the single-permission form and now
270
+ * delegates here, so the two cannot answer differently. Split out because
271
+ * `resolveOrgPermissions` in `libs/tenant/runtime` needs the whole set to
272
+ * project onto the legacy flag map that the marketplace install and publish
273
+ * gates read — it previously derived those flags from the built-in role tier
274
+ * alone, which silently ignored both refinements.
275
+ *
276
+ * One conditional read, only when a custom role is actually assigned. A
277
+ * dangling `roleId` resolves to `null` and falls back to the role defaults
278
+ * rather than denying, matching what the console hook does with the same
279
+ * dangling id — a deleted role must not lock a member out of surfaces their
280
+ * base role allows.
281
+ */
282
+ export declare function resolveMemberOrgPermissions(orgId: string, member: Partial<AglynOrgMember> | null | undefined): Promise<Record<OrgPermission, boolean>>;
283
+ export declare function memberHasOrgPermission(orgId: string, member: Partial<AglynOrgMember> | null | undefined, permission: OrgPermission): Promise<boolean>;
284
+ /**
285
+ * May this member hold a catalog permission on this site (AGL-2927,
286
+ * AGL-2984)?
287
+ *
288
+ * The one resolver a door calls for a key a plugin declared with host-role
289
+ * defaults, so the two membership axes cannot be answered differently by two
290
+ * routes. An org-wide member is decided by the org catalog through
291
+ * `resolveMemberOrgPermissions` — custom role and overrides applied, one
292
+ * conditional read. A site collaborator is decided by the host role they hold
293
+ * on the site the request NAMES, refined by the per-site toggle on their
294
+ * member document; a collaborator whose request names no site is refused,
295
+ * because there is no host role to read a default from and omitting the site
296
+ * must not be a way around the toggle.
297
+ *
298
+ * `hostId` is whatever the body carried, trimmed by the caller or not — an
299
+ * empty string and `undefined` both mean "no site named".
300
+ */
301
+ export declare function memberHasPermissionOnHost(orgId: string, hostId: string | null | undefined, member: Partial<AglynOrgMember> | null | undefined, permission: OrgPermission): Promise<boolean>;
302
+ /**
303
+ * The 403 a door sends when `memberHasPermissionOnHost` says no: the same
304
+ * customer-safe shape the doors' other refusals use — one sentence, a
305
+ * `reason` a client can branch on — naming the permission by its catalog
306
+ * label so the reader can find it on the Team page, and who to ask.
307
+ */
308
+ export declare function permissionRefusal(permission: OrgPermission): Response;
309
+ /**
310
+ * An org-wide member's verdict for every key PLUGINS declared into the
311
+ * catalog, read fresh (AGL-2929, AGL-2984): what `memberHasPermissionOnHost`
312
+ * answers for them with no site named, as a whole map. `null` for a uid with
313
+ * no member document and for a site collaborator, whose per-site keys are
314
+ * decided per site by `setHostPermissions` and have no org-level verdict to
315
+ * compare. Read on either side of a membership write, it is how the members
316
+ * route tells which declared keys the write moved.
317
+ */
318
+ export declare function resolveMemberPluginPermissionsOnOrg(orgId: string, uid: string): Promise<Record<string, boolean> | null>;
319
+ /** A collaborator's per-site verdict on either side of a toggle write. */
320
+ export interface HostPermissionsWrite {
321
+ /** The verdict before the write; `null` when the member had no access to the site. */
322
+ before: Record<string, boolean> | null;
323
+ after: Record<string, boolean>;
324
+ }
325
+ /**
326
+ * Set a collaborator's per-site toggles (AGL-2927, AGL-2984) and re-project.
327
+ *
328
+ * A merge on the nested map, so the member's other sites and every other
329
+ * field stay untouched; keys no plugin declared as per-site are dropped
330
+ * rather than stored, and a non-boolean is ignored rather than coerced.
331
+ * Re-projection is scoped to the one host whose `memberPermissions` changed.
332
+ *
333
+ * The verdict before the write comes back beside the one after it, because
334
+ * the caller records one activity row per key that moved (AGL-2929) and a
335
+ * toggle set to the value it already had is not a change.
336
+ */
337
+ export declare function setHostPermissions(options: {
338
+ orgId: string;
339
+ uid: string;
340
+ hostId: string;
341
+ permissions: Partial<Record<string, unknown>>;
342
+ }): Promise<HostPermissionsWrite>;
343
+ export declare function listOrgMembers(orgId: string): Promise<AglynOrgMember[]>;
344
+ /**
345
+ * Recomputes the denormalized authorization projections after a membership
346
+ * change: `memberRoles` and `memberPermissions` on every host the org owns
347
+ * (or one host when given), and `scopeTokens` + `resolvedPermissions` on
348
+ * every member doc.
349
+ *
350
+ * The rules resolve a request from these reads — the host doc for host
351
+ * content (docs/MULTI_TENANT_FIRESTORE.md §5), the member doc for scoped
352
+ * org resources (AGL-1038) — so this is what makes a membership effective.
353
+ * They live here, in one writer called by every mutation below, because a
354
+ * grant path that updates one projection and forgets another silently over-
355
+ * or under-grants.
356
+ *
357
+ * Everything is recomputed for the whole roster rather than the changed
358
+ * member: the roster is already loaded for `memberRoles`, and a full pass
359
+ * self-heals rows that an earlier partial failure left stale.
360
+ *
361
+ * ## `resolvedPermissions`, and why the rules need it denormalized
362
+ *
363
+ * Security rules cannot resolve a custom role. `member.roleId` points at
364
+ * `orgs/{orgId}/roles/{roleId}`, and reproducing the three-layer precedence
365
+ * (per-member beats custom role beats role default) in CEL takes a second
366
+ * cross-document get() plus a correct handling of a dangling id — where a
367
+ * naive version over-denies and locks out paying customers. So the rules read
368
+ * the ANSWER instead of the inputs, which is the same trade `scopeTokens`
369
+ * already makes for a reason the rules language shares: it has no `.map()`
370
+ * either.
371
+ *
372
+ * The map is `projectMemberResolvedPermissions`: `resolveOrgPermissions`'
373
+ * own catalog verdict, plus the plugin-declared keys a custom role or an
374
+ * override set explicitly (AGL-2974), so the rules and every
375
+ * server route are reading one resolver's verdict rather than two
376
+ * implementations of it.
377
+ *
378
+ * ONE READ PER DISTINCT ROLE, not per member: an org assigns a handful of
379
+ * custom roles across a roster that can run to hundreds, and resolving each
380
+ * member independently would re-read the same few documents once each.
381
+ */
382
+ export declare function syncOrgAuthProjections(orgId: string, hostId?: string): Promise<void>;
383
+ /**
384
+ * @deprecated Renamed to `syncOrgAuthProjections` (AGL-1038) now that it
385
+ * also writes member `scopeTokens`. Kept as an alias for out-of-tree
386
+ * callers; delete once none remain.
387
+ */
388
+ export declare const syncHostMemberRoles: typeof syncOrgAuthProjections;
389
+ /** What an org activity entry points at; `id` lets detail views filter. */
390
+ export interface OrgActivityTarget {
391
+ /**
392
+ * `host` and `subscription` are the two facts about a workspace that no
393
+ * host feed can hold (AGL-118).
394
+ *
395
+ * A site's own log lives at `hosts/{hostId}/activity` and is destroyed with
396
+ * the site — `eraseHost` recursive-deletes the whole tree — so "this site
397
+ * was deleted" written there is an entry with no reader by construction.
398
+ * A subscription belongs to no single site at all. Both are org-level
399
+ * events, and this is the only feed that outlives them.
400
+ */
401
+ type: 'org' | 'member' | 'invite' | 'host' | 'subscription' | 'contact' | 'company' | 'deal' | 'lead' | 'task' | 'aiJob' | 'role' | 'screen' | 'layout' | 'component' | 'template' | 'workflow' | 'content' | 'theme' | PluginActivityTargetType;
402
+ id?: string;
403
+ name?: string;
404
+ /** Present on a generated screen output so the deep link can hit the exact version. */
405
+ versionId?: string;
406
+ }
407
+ /**
408
+ * Org-level counterpart to the host activity log (AGL-118): fire-and-
409
+ * forget append to `orgs/{orgId}/activity` from the org API routes. Never
410
+ * throws — an audit miss must not break the mutation that triggered it.
411
+ * Admin-SDK-only, like the rest of this file; the rules deny client writes.
412
+ */
413
+ export declare function logOrgActivity(orgId: string,
414
+ /**
415
+ * `uid` is nullable because some org events HAVE no actor (AGL-118). Stripe
416
+ * cancels a subscription after a month of failed retries with nobody
417
+ * present, and the honest record of that says so. Naming the last person
418
+ * who touched billing instead would put a real name on an act nobody
419
+ * performed — and `actorId` is a filterable field, so the invented
420
+ * attribution would then show up under that person when somebody asks what
421
+ * they have done.
422
+ */
423
+ actor: {
424
+ uid: string | null;
425
+ email?: string | null;
426
+ }, action: string, target: OrgActivityTarget): Promise<void>;
427
+ /** What a host activity entry points at. Mirrors `HostActivityTarget`. */
428
+ export interface HostActivityTarget {
429
+ type: 'host' | 'screen' | 'layout' | 'theme' | 'media' | 'content' | 'variable' | 'function' | 'workflow' | 'member' | 'component' | 'template' | 'contact' | 'company' | 'deal' | 'lead';
430
+ id?: string;
431
+ name?: string;
432
+ versionId?: string;
433
+ }
434
+ /**
435
+ * Append to `hosts/{hostId}/activity` with the ADMIN SDK (AGL-118).
436
+ *
437
+ * The host log's twin of {@link logOrgActivity}, and the beginning of the
438
+ * migration off the browser. Every entry in this collection has been written
439
+ * by the client since the log existed, which makes it an audit trail its
440
+ * subject can decline to write: three template surfaces created screens,
441
+ * layouts and components while calling no logger at all, and nothing noticed
442
+ * for months because a log that is missing an entry looks exactly like a
443
+ * person who did nothing.
444
+ *
445
+ * A route that already authenticated the caller has the two things the client
446
+ * cannot be trusted for — a VERIFIED uid, and the certainty that the write it
447
+ * is recording actually happened, because it performed it. So an entry from
448
+ * here is worth more than the one it replaces, not merely more reliable.
449
+ *
450
+ * Never throws, for the reason the client logger never throws: an audit miss
451
+ * must not turn a successful create into a failed request. It is `await`ed
452
+ * rather than floated because a serverless response ending cancels in-flight
453
+ * work, which would make the drop the common case rather than the rare one.
454
+ */
455
+ export declare function logHostActivity(hostId: string, actor: HostActivityActor, action: string, target: HostActivityTarget): Promise<void>;
456
+ /**
457
+ * A collaborator seat refusal, raised from INSIDE the grant transaction
458
+ * (AGL-2068).
459
+ *
460
+ * An exception rather than a return value because it has to travel out of
461
+ * `upsertOrgMember` / `grantHostAccess`, whose contract is "make it so" and
462
+ * which four routes already call as a bare `await`. Returning a verdict would
463
+ * have let every existing call site ignore it silently, which is the shape of
464
+ * the bug being fixed.
465
+ */
466
+ export declare class CollaboratorSeatLimitError extends Error {
467
+ readonly hostId: string;
468
+ readonly limit: number;
469
+ readonly upgradeRequired: boolean;
470
+ readonly addonPriceUsd: number | null;
471
+ /**
472
+ * Seats this site holds ABOVE `limit` (AGL-2439). Non-zero means the site
473
+ * is GRANDFATHERED: those collaborators keep their access, and the refusal
474
+ * is only of the NEXT one. Carried on the error so the refusal copy can say
475
+ * that rather than letting the admin read a 403 as "somebody was removed".
476
+ */
477
+ readonly retainedOverCap: number;
478
+ constructor(hostId: string, quota: {
479
+ limit: number;
480
+ upgradeRequired: boolean;
481
+ addonPriceUsd: number | null;
482
+ retainedOverCap?: number;
483
+ });
484
+ }
485
+ /**
486
+ * Turn a seat refusal into the 403 the four admitting routes return, or null
487
+ * when the error is something else and must keep propagating to the 500.
488
+ *
489
+ * Lives here beside `emailUnverifiedResponse` and `lockdownRefusal` so a
490
+ * route's catch block is one line and cannot accidentally mask a real fault.
491
+ */
492
+ export declare function collaboratorSeatRefusalResponse(error: unknown): Response | null;
493
+ /**
494
+ * The same cap, asked BEFORE anything is written (AGL-2068).
495
+ *
496
+ * Not the enforcement — the transaction inside the grant is. This exists so
497
+ * the two doors that only ever create an INVITE (`/api/hosts/members` for an
498
+ * address with no account yet, and `/api/orgs/invites` create) refuse at the
499
+ * point the admin is looking at, rather than mailing someone a link that will
500
+ * be refused when they click it. A race here over-reserves invites; it cannot
501
+ * over-grant access, because access is only ever granted through the
502
+ * transactional path.
503
+ */
504
+ export declare function collaboratorSeatRefusal(options: {
505
+ orgId: string;
506
+ org: Partial<AglynOrgBilling>;
507
+ hostIds: string[];
508
+ self?: {
509
+ uid?: string | null;
510
+ email?: string | null;
511
+ };
512
+ }): Promise<Response | null>;
513
+ /**
514
+ * A manager seat refused, thrown rather than returned, for the reason
515
+ * {@link CollaboratorSeatLimitError} is thrown: it has to travel out of
516
+ * `upsertOrgMember`, whose contract is "make it so" and which three routes
517
+ * already call as a bare `await`. A verdict would be silently discarded by
518
+ * every one of them, which is the shape of the bug being fixed.
519
+ */
520
+ export declare class ManagerSeatLimitError extends Error {
521
+ readonly limit: number;
522
+ readonly upgradeRequired: boolean;
523
+ readonly addonPriceUsd: number | null;
524
+ /**
525
+ * Seats the org holds ABOVE `limit`. Non-zero means it is GRANDFATHERED:
526
+ * those managers keep their access and only the NEXT one is refused, so the
527
+ * console can say that instead of letting an admin read a 403 as "somebody
528
+ * was removed".
529
+ */
530
+ readonly retainedOverCap: number;
531
+ constructor(quota: {
532
+ limit: number;
533
+ upgradeRequired: boolean;
534
+ addonPriceUsd: number | null;
535
+ retainedOverCap?: number;
536
+ });
537
+ }
538
+ /**
539
+ * Turn a manager-seat refusal into the 403 the admitting routes return, or
540
+ * null when the error is something else and must keep propagating to the 500.
541
+ *
542
+ * Sits beside `collaboratorSeatRefusalResponse` and stacks with it in a
543
+ * route's catch block, each returning null for a non-match.
544
+ */
545
+ export declare function managerSeatRefusalResponse(error: unknown): Response | null;
546
+ /**
547
+ * The same cap, asked BEFORE anything is written.
548
+ *
549
+ * Not the enforcement — the transaction inside `upsertOrgMember` is. This
550
+ * exists for the one door that never calls it: `/api/orgs/invites` create
551
+ * writes an invite document directly, so it refuses at the point the admin is
552
+ * looking at rather than mailing someone a link that will be refused when
553
+ * they click it. A race here over-reserves invites; it cannot over-grant
554
+ * access, because access is only ever granted through the transactional path.
555
+ */
556
+ export declare function managerSeatRefusal(options: {
557
+ orgId: string;
558
+ org: Partial<AglynOrgBilling>;
559
+ becomesManager: boolean;
560
+ self?: {
561
+ uid?: string | null;
562
+ email?: string | null;
563
+ };
564
+ }): Promise<Response | null>;
565
+ export interface UpsertOrgMemberOptions {
566
+ orgId: string;
567
+ uid: string;
568
+ role: OrgRole;
569
+ allHosts?: boolean;
570
+ /** Per-site grants. `author` (AGL-2334) rides the shared union. */
571
+ hostAccess?: Record<string, HostAccessRole>;
572
+ /**
573
+ * Further CONFIRMED addresses on the joining account (AGL-2486), so a
574
+ * pending invite addressed to a secondary is recognised as this same
575
+ * person and does not bill them a second collaborator seat. Must contain
576
+ * only addresses proven to belong to `uid`.
577
+ */
578
+ seatAliasEmails?: readonly (string | null | undefined)[] | null;
579
+ /** Custom role reference (AGL-243); null clears it. */
580
+ roleId?: string | null;
581
+ email?: string | null;
582
+ displayName?: string | null;
583
+ /**
584
+ * The member's provider photo, mirrored onto the roster (AGL-1126).
585
+ *
586
+ * Every member surface reads the roster; none of them can read Firebase
587
+ * Auth for an SSO member, whose record lives in a per-org tenant pool
588
+ * (AGL-1122). Without this the console falls back to drawn initials for
589
+ * everyone — fine, but it means a member who HAS a picture still never
590
+ * shows it. This is the ONLY source of a real face now that the Gravatar
591
+ * fallback is gone (AGL-1683), so keeping it populated matters more than
592
+ * it did. Display data only: never an identity or authorization source.
593
+ */
594
+ photoURL?: string | null;
595
+ /** Job title shown on the roster/member page (AGL-364). */
596
+ title?: string | null;
597
+ invitedBy?: string | null;
598
+ }
599
+ /**
600
+ * The owner seat is not writable through the membership door (AGL-1888).
601
+ *
602
+ * An exception, and modelled on {@link CollaboratorSeatLimitError}, for the
603
+ * same reason: it has to travel out of a function whose contract is "make it
604
+ * so" and which three routes call as a bare `await`. A returned verdict would
605
+ * be ignorable at every one of them, which is the shape of the bug.
606
+ */
607
+ export declare class OrgOwnerSeatError extends Error {
608
+ /** Which invariant refused, for the log and the tests. */
609
+ readonly reason: 'grant' | 'demote';
610
+ constructor(reason: 'grant' | 'demote');
611
+ }
612
+ /**
613
+ * Turn an owner-seat refusal into a 409, or null when the error is something
614
+ * else and must keep propagating to the 500.
615
+ *
616
+ * Beside {@link collaboratorSeatRefusalResponse} so a route's catch block
617
+ * stays one line and cannot accidentally mask a real fault.
618
+ */
619
+ export declare function orgOwnerSeatRefusalResponse(error: unknown): Response | null;
620
+ /**
621
+ * Creates or updates a member transactionally with its reverse-index
622
+ * entry, then re-syncs host projections.
623
+ *
624
+ * ## The owner seat is refused here, not only in the routes (AGL-1888)
625
+ *
626
+ * It used to say "owner-role guards live in the API routes — this is the
627
+ * mechanism", and that was the defect. Both halves of the org-owner invariant
628
+ * were enforced only at the doors an admin clicks, and invite ACCEPTANCE is a
629
+ * door that re-validates neither:
630
+ *
631
+ * - **Granting.** `/api/orgs/members` and `/api/orgs/invites` create both
632
+ * refuse `role === 'owner'` outright, but acceptance passes the invite
633
+ * doc's STORED role straight through (`/api/orgs/invites` accept, and
634
+ * `/api/auth/sso-jit`). That is safe today only because every writer of an
635
+ * invite doc refuses `owner` and the collection is `allow write: if false`
636
+ * — a latent escalation the moment a fourth invite-writer forgets, and the
637
+ * invariant that an org has exactly ONE owner is what the whole SSO
638
+ * break-glass guarantee rests on ({@link transferOrgOwnership} MOVES the
639
+ * seat; nothing else may create one).
640
+ * - **Demoting**, which was reachable, self-serve, and irreversible. Invite
641
+ * creation never checked that the address is already a member, and
642
+ * acceptance accommodates an existing member re-accepting. So any admin
643
+ * could invite the OWNER'S own verified address as `viewer`; the owner
644
+ * clicks a normal-looking invitation to their own organization; this
645
+ * function merge-writes `role: 'viewer'`, `allHosts: false` onto the owner's
646
+ * member doc. `orgs/{orgId}.ownerUid` still names them, but every
647
+ * authorization read goes through the member doc — so `canManageOrg` is
648
+ * now false, `transfer-ownership` checks `membership.member.role ===
649
+ * 'owner'` and refuses them, `/api/orgs/members` refuses to edit the owner's
650
+ * membership at all, and `findBreakGlassOrgOwners` (`where role == owner`)
651
+ * finds nobody. The org loses its owner permanently, recoverable only by
652
+ * staff. It is the AGL-1375 one-way door rebuilt out of the invite path,
653
+ * and it needs no SSO to reach.
654
+ *
655
+ * Both checks live HERE because this is the single transaction every door
656
+ * funnels through, and the org doc and the existing member doc are already in
657
+ * its read set — so it costs nothing and cannot be forgotten by a fifth
658
+ * caller. The route-level refusals stay: they are better error messages at
659
+ * the point the admin is looking, not the control.
660
+ *
661
+ * The demotion guard asks BOTH `org.ownerUid` and the stored role, rather
662
+ * than trusting either to stand for the other. They are supposed to agree;
663
+ * an org where they have already diverged is exactly the one that most needs
664
+ * the write refused.
665
+ *
666
+ * {@link createOrganization} and {@link transferOrgOwnership} are unaffected —
667
+ * both write `role: 'owner'` with their own `tx.set`, and remain the only two
668
+ * producers of an owner in the product.
669
+ */
670
+ export declare function upsertOrgMember(options: UpsertOrgMemberOptions): Promise<void>;
671
+ /**
672
+ * Fill in a roster row's display identity from an identity provider, writing
673
+ * ONLY the fields that are currently blank (AGL-1131).
674
+ *
675
+ * Separate from `upsertOrgMember` because the caller is the SSO sign-in path
676
+ * on its already-a-member branch, where the member's role, host access and
677
+ * invite state are settled and must not be touched. `upsertOrgMember`
678
+ * requires a `role` and re-asserts it, so reusing it here would let an SSO
679
+ * sign-in quietly reset an admin to the org's `sso.defaultRole`.
680
+ *
681
+ * Absent-only, so it is safe on every sign-in: it backfills the rows that
682
+ * predate the IdP mapping and then never writes again, and it can never
683
+ * overwrite a name or photo a person chose.
684
+ *
685
+ * @returns the field names it wrote, for logging and tests.
686
+ */
687
+ export declare function backfillMemberIdentity(orgId: string, uid: string, identity: {
688
+ displayName?: string | null;
689
+ photoURL?: string | null;
690
+ }, db?: FirebaseFirestore.Firestore): Promise<string[]>;
691
+ /**
692
+ * The same absent-only backfill, across every roster row that names `uid`.
693
+ *
694
+ * ## The hole this closes
695
+ *
696
+ * `orgs/{orgId}/members/{uid}.photoURL` is the ONLY avatar a member surface
697
+ * can read — a colleague's auth record is unreadable from another member's
698
+ * session, and an SSO member's lives in a pool the project cannot see at all
699
+ * (AGL-1122). Three writers filled it, and between them they missed the
700
+ * commonest account there is:
701
+ *
702
+ * - `upsertOrgMember` — someone ADDED you, so the adder's lookup had a record
703
+ * to copy from.
704
+ * - `backfillMemberIdentity` via the SSO sign-in (AGL-1131) — enterprise only.
705
+ * - `propagateMemberPhoto` via Manage Account → Profile image (AGL-1976) — a
706
+ * photo the person typed or browsed to.
707
+ *
708
+ * Nobody adds the person who CREATES a workspace, `createOrganization` writes
709
+ * their row with a name and an email and no photo, and a Google sign-in never
710
+ * visits the other two. So the owner of a workspace saw their own face in the
711
+ * app bar, which reads the live auth record, and a grey initial in their own
712
+ * Team list — measured on both rows of `test-org`, each with `photoURL` absent
713
+ * while the auth record and `users/{uid}.photoUrl` carried the picture.
714
+ *
715
+ * ## Absent-only, like the function it fans out
716
+ *
717
+ * It runs on EVERY sign-in, so the reasoning in `backfillMemberIdentity`
718
+ * applies unchanged and is the reason this is a fan-out of that function
719
+ * rather than a second writer: an overwriting version would replace a photo
720
+ * the person chose in Manage Account with their provider thumbnail on their
721
+ * next sign-in, silently, forever. `propagateMemberPhoto` is the overwriting
722
+ * direction and stays the only one, because its input is a choice the person
723
+ * made rather than an assertion a directory made about them.
724
+ *
725
+ * Memberships come from `users/{uid}/orgs`, the reverse index — never a
726
+ * collection-group query over `members`, which would read every workspace's
727
+ * roster in the estate to find one person's rows.
728
+ *
729
+ * @returns the org ids whose row was written, for logging and tests.
730
+ */
731
+ export declare function backfillMemberIdentityEverywhere(uid: string, identity: {
732
+ displayName?: string | null;
733
+ photoURL?: string | null;
734
+ }, db?: FirebaseFirestore.Firestore): Promise<string[]>;
735
+ /**
736
+ * Transfers org ownership (AGL-232): the target must already be on the
737
+ * roster; the previous owner steps down to admin. One transaction across
738
+ * the org doc, both member docs and both reverse-index entries, then the
739
+ * host projections re-sync.
740
+ *
741
+ * **It moves `ownerUid` and must never touch `createdByUid`** (AGL-2265).
742
+ * That field is the creator attribution the free-workspace ceiling counts
743
+ * against, and it is what stops a transfer from being a way to launder the
744
+ * count: hand a workspace to an alt account, create a fourth, take it back.
745
+ * Nothing here writes it, and `free-workspace-cap.spec.ts` runs exactly that
746
+ * sequence to keep it that way.
747
+ */
748
+ export declare function transferOrgOwnership(orgId: string, fromUid: string, toUid: string): Promise<void>;
749
+ /**
750
+ * Grants (or updates) per-host access for a uid without disturbing an
751
+ * existing membership's org role or allHosts flag (AGL-238: the host user
752
+ * manager rides org membership). Creates a viewer membership scoped to
753
+ * just this host when the uid is not on the roster yet.
754
+ */
755
+ export declare function grantHostAccess(options: {
756
+ orgId: string;
757
+ uid: string;
758
+ hostId: string;
759
+ /** `author` (AGL-2334) edits content and cannot publish. */
760
+ role: HostAccessRole;
761
+ email?: string | null;
762
+ displayName?: string | null;
763
+ invitedBy?: string;
764
+ }): Promise<void>;
765
+ /**
766
+ * Drops one host from a member's hostAccess map, then re-projects.
767
+ *
768
+ * `updateExisting`, not a merge-set (AGL-1766). A merge-set whose entire
769
+ * payload is a delete sentinel still CREATES the document when it is absent,
770
+ * and the row it minted here is not merely untidy — it is a MEMBERSHIP, and
771
+ * one that reads as org-wide. `isOrgWideMember` treats "no `role`, no
772
+ * `allHosts`, empty `hostAccess`" as the pre-`allHosts` LEGACY shape and
773
+ * answers true (deliberately: reading it as "scoped, with access to nothing"
774
+ * would lock real members out). A genuine site collaborator never looks like
775
+ * that — `grantHostAccess` always writes `allHosts: false` — but a document
776
+ * conjured from this patch alone does, exactly.
777
+ *
778
+ * So the consequences land away from here, which is what made it hard to see:
779
+ * `resolveOrgMembership` finds the doc and returns a membership for someone
780
+ * who was removed from the org; `syncOrgAuthProjections` on the next line
781
+ * stamps it `scopeTokens: ['org']`, the read set the rules and every
782
+ * Admin-SDK `memberCanSee` resolve from; and `countManagerSeats` bills it as
783
+ * a manager seat. (It does NOT reach `hosts/*.memberRoles`, as AGL-1763
784
+ * supposed — `hostRoleFor` requires an `isOrgRole(role)` and the phantom has
785
+ * none.)
786
+ *
787
+ * Reachable without any race: `removeOrgMember` deletes the org member doc
788
+ * but leaves the `hosts/{hostId}/members` roster row, which is what this is
789
+ * called from. Deleting that leftover row re-created the membership it was
790
+ * meant to finish removing. (AGL-1766's "stale double-submit" is NOT a route:
791
+ * the caller 404s on the missing roster row before reaching here.)
792
+ *
793
+ * DOTTED FIELD PATH, not the nested map: `update()` accepts a delete sentinel
794
+ * only at the top level of its patch (`@google-cloud/firestore` serializer,
795
+ * `allowDeletes: 'root'`), so the nested form would throw INVALID_ARGUMENT.
796
+ * The dotted path is top-level and clears the one key while leaving the rest
797
+ * of `hostAccess` alone — the same field-by-field semantics the merge had.
798
+ * Safe as a string path because host ids are `createResourceUid()` nanoids
799
+ * (`A-Za-z0-9_-`), so none can contain the `.` the SDK splits on.
800
+ *
801
+ * REFUSE, and ignore the answer: revoking a grant that is not there is a
802
+ * no-op and discards nothing (AGL-1760). The projections still run — they are
803
+ * recomputed from the roster, so a pass that finds no member doc is exactly
804
+ * the self-heal a stale row needs.
805
+ */
806
+ export declare function revokeHostAccess(orgId: string, uid: string, hostId: string): Promise<void>;
807
+ /**
808
+ * Removes a member + reverse index entry, then re-syncs projections.
809
+ *
810
+ * The addresses the member added in this workspace (AGL-2975) go in the
811
+ * same batch. They sit beside the roster row rather than under it, so no
812
+ * delete of the row reaches them, and an erasure of the person runs through
813
+ * here once per workspace.
814
+ */
815
+ export declare function removeOrgMember(orgId: string, uid: string): Promise<void>;
816
+ /**
817
+ * Registers a host under its org: org directory entry, hostIndex mirror,
818
+ * and the initial memberRoles projection on the host doc.
819
+ */
820
+ export declare function registerOrgHost(orgId: string, hostId: string, subdomain?: string): Promise<void>;
821
+ /**
822
+ * The consent group a site belongs to, read off its owning org.
823
+ *
824
+ * The ONE server-side door to pooling. Every capture surface and every send
825
+ * path resolves a group through this rather than reading
826
+ * `CONSENT_GROUPS_FIELD` itself, so there is one place that decides what a
827
+ * site's consent covers and one place a mistake could live.
828
+ *
829
+ * FAILS TO THE GROUP OF ONE. An org that cannot be resolved, or a read that
830
+ * throws, answers "this site alone" — which withholds mail from an org that
831
+ * had legitimately pooled and never sends mail on a pooling nobody could
832
+ * confirm. That is the only direction a failure here may fall.
833
+ *
834
+ * The org read is `React.cache`-deduped per request by {@link getOrgForHost},
835
+ * so a send that already resolved the org for its policy pays nothing extra.
836
+ */
837
+ export declare function consentGroupForSite(hostId: string, org?: Record<string, unknown> | null): Promise<ConsentGroup>;