@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,643 @@
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
+ */ /**
18
+ * Server half of the lockdown system (AGL-1501): the verdict every
19
+ * enforcement chokepoint asks for. The pure shape/precedence logic lives in
20
+ * `@aglyn/aglyn` `app-utils/lockdown.ts`; this module adds the Admin-SDK
21
+ * reads and the two properties only the server can hold:
22
+ *
23
+ * **The un-panic invariant.** A verified `staff` claim bypasses EVERY scope,
24
+ * unconditionally, before any read happens. A platform-wide lockdown must
25
+ * never lock out the staff who can lift it — a panic button that panics its
26
+ * own operator is worse than none. Nothing may be added to
27
+ * `getLockdownVerdict` above the staff check.
28
+ *
29
+ * **Fail-open on infrastructure error.** If the `lockdowns/platform` read
30
+ * throws (Firestore outage, emulator without the collection), the verdict is
31
+ * "not locked": an infrastructure blip must not weld the whole platform
32
+ * shut. The same posture as the sanctions gate on an absent geo signal
33
+ * (AGL-1492) and the release-flag reader on a missing template.
34
+ *
35
+ * **…except for takedowns (AGL-1621).** One class of lock inverts that cost
36
+ * function: a legal or abuse takedown must keep holding when Firestore is
37
+ * unreachable, because "we served it, our database was down" answers no
38
+ * court order. The class is an EXPLICIT stored field (`enforcement`), never
39
+ * inferred from scope or reason, and absent means `standard` — so every
40
+ * lock that exists today, and every lock an operator does not classify,
41
+ * keeps failing open exactly as before. See the takedown ledger below for
42
+ * how a classification survives the read that loses it.
43
+ */ import { featureLockdownDocId, orgFeatureLockdownDocId, isLockdownActive, isTakedownLockdown, lockdownFeatureStaffBypass, LOCKDOWNS_COLLECTION, lockdownBlocks, lockdownIntentForMethod, lockdownNotice, lockdownRetryAfterSeconds, domainLockdownDocId, normalizeHostLockdown, normalizeLockdownDoc, normalizeOrgLockdown, PLATFORM_LOCKDOWN_DOC_ID, resolveLockdown, userLockdownDocId } from "@aglyn/aglyn/server";
44
+ import { getApp } from "firebase-admin/app";
45
+ import firebaseAdmin from "./firebase-admin.js";
46
+ /**
47
+ * Platform-doc TTL. Short on purpose: this is the panic path, and 15s is the
48
+ * worst-case lag between staff pressing the button and a warm server process
49
+ * refusing its next request. Per-request reads would be ~1 Firestore read
50
+ * per API call platform-wide, which AGL-1302 showed is real money at scale.
51
+ */ const PLATFORM_TTL_MS = 15000;
52
+ /**
53
+ * ===================== THE TAKEDOWN LEDGER (AGL-1621) =====================
54
+ *
55
+ * Lockdown fails open, and that stays true for ordinary locks: an
56
+ * unreachable Firestore is an outage, not a lockdown, and a blip must never
57
+ * weld every customer site shut. But a legal or abuse TAKEDOWN has the
58
+ * opposite cost function — "we served the infringing content because our
59
+ * database was down" is not an answer to a court order. So takedown-class
60
+ * locks (`enforcement: 'takedown'`) hold through a failed read, and
61
+ * everything else keeps today's behaviour exactly.
62
+ *
63
+ * ## The ordering problem this exists to solve
64
+ *
65
+ * The classification is stored ON the lock document. When the read throws
66
+ * there IS no document, so the class cannot be consulted at failure time —
67
+ * the obvious implementation ("if the lock is a takedown, fail closed") is
68
+ * unimplementable as written, because the failure is precisely the loss of
69
+ * the thing it wants to branch on.
70
+ *
71
+ * The only honest source is what this process last SUCCESSFULLY read. So
72
+ * every successful read records its verdict here: a takedown is remembered,
73
+ * and anything else RETIRES the entry. A subsequent failed read consults
74
+ * the ledger instead of falling to null.
75
+ *
76
+ * ## What this does and does not guarantee — stated, not implied
77
+ *
78
+ * HOLDS: a takedown that a process has already observed keeps being
79
+ * enforced by that process for as long as Firestore is unreachable. That is
80
+ * the real incident shape — a takedown placed hours or days ago, then a
81
+ * Firestore blip — and it is what the decision asks for.
82
+ *
83
+ * DOES NOT HOLD: a COLD process that has never once read the takedown has
84
+ * nothing to remember and fails open, like everything else. Closing that
85
+ * gap needs a second carrier more available than Firestore (edge config or
86
+ * similar), which is a different and much larger change; pretending
87
+ * otherwise here would be worse than naming it. A takedown placed DURING a
88
+ * total Firestore outage is likewise not enforceable — the write itself
89
+ * cannot land.
90
+ *
91
+ * ## Two things it deliberately does not do
92
+ *
93
+ * It is NOT cleared by `invalidate*LockdownCache`. Those run after a staff
94
+ * write, and clearing the ledger there would mean a lock-then-outage
95
+ * sequence forgot the takedown at the exact moment it mattered. The next
96
+ * successful read is what retires an entry, and a lift IS such a read.
97
+ *
98
+ * It does not outlive the lock's own expiry: a held takedown is still
99
+ * checked against `isLockdownActive`, so a `untilMs` that has passed
100
+ * releases on schedule even while Firestore is down. A dead-man expiry must
101
+ * not become un-liftable by being classified.
102
+ */ const takedownLedger = new Map();
103
+ /**
104
+ * Bounded like the user and domain caches, and for the same reason: two of
105
+ * the four keyed readers take their key from caller-controlled input.
106
+ * Eviction is least-recently-USED.
107
+ */ export const TAKEDOWN_LEDGER_MAX = 5000;
108
+ /**
109
+ * Record what a SUCCESSFUL read saw. A takedown is remembered; anything
110
+ * else — no lock, an ordinary lock, or a lock whose class this build cannot
111
+ * interpret — retires the entry, which is how a lift takes effect.
112
+ */ function rememberTakedown(key, state) {
113
+ if (!state || !isTakedownLockdown(state)) {
114
+ takedownLedger.delete(key);
115
+ return;
116
+ }
117
+ // Re-insert to refresh recency before the LRU trim below.
118
+ takedownLedger.delete(key);
119
+ takedownLedger.set(key, state);
120
+ while(takedownLedger.size > TAKEDOWN_LEDGER_MAX){
121
+ const oldest = takedownLedger.keys().next().value;
122
+ if (oldest === undefined) break;
123
+ takedownLedger.delete(oldest);
124
+ }
125
+ }
126
+ /**
127
+ * What a FAILED read should serve: a remembered, still-active takedown, or
128
+ * null — which is the shipped fail-open answer and therefore the default
129
+ * for every lock that is not an observed takedown.
130
+ */ function heldTakedown(key, nowMs) {
131
+ const state = takedownLedger.get(key);
132
+ if (!state) return null;
133
+ if (!isLockdownActive(state, nowMs)) {
134
+ takedownLedger.delete(key);
135
+ return null;
136
+ }
137
+ return state;
138
+ }
139
+ /**
140
+ * Forget every remembered takedown. NOT part of the panic path and not
141
+ * called by the admin route — this exists for process-boundary and test
142
+ * setup, where a ledger surviving between cases would make one test's lock
143
+ * another test's fail-closed verdict.
144
+ */ export function resetTakedownLedger() {
145
+ takedownLedger.clear();
146
+ }
147
+ /** Ledger keys. Disjoint by construction — the doc-id prefixes already are. */ const PLATFORM_LEDGER_KEY = 'platform';
148
+ const featureLedgerKey = (feature)=>featureLockdownDocId(feature);
149
+ const userLedgerKey = (uid)=>userLockdownDocId(uid);
150
+ const domainLedgerKey = (hostname)=>domainLockdownDocId(hostname);
151
+ /**
152
+ * ORG and HOST scope (AGL-1881). These two locks have no document in
153
+ * `lockdowns/*` — they live as the `suspended*` family ON the org and host
154
+ * documents — so they never passed through a ledgered reader, and
155
+ * `getSiteLockdown` answered `null` flat when its reads threw. The route
156
+ * persists `suspendedEnforcement: 'takedown'` for both scopes all the same,
157
+ * from a control that promises the lock "keeps holding if Aglyn cannot reach
158
+ * the database". A court-ordered host takedown plus a partial Firestore
159
+ * outage therefore served the infringing site for the duration of the
160
+ * outage, which is the precise failure the mode exists to prevent.
161
+ *
162
+ * Keyed by HOST ID, both of them, including the org one. Every reader on
163
+ * this path is host-addressed, and on a failed read the org id is exactly as
164
+ * unreadable as the lock — `getOrgForHost` is the read that just threw. So
165
+ * "the org lock as seen through this host" is the only thing a failed read
166
+ * can look up, and it matches the ledger's existing warm-process semantics:
167
+ * an org takedown holds for each site a process has already read once.
168
+ *
169
+ * Distinct prefixes keep them disjoint from the four doc-id keys above
170
+ * (`platform`, `feature--`, `user--`, `domain--`).
171
+ */ const orgForHostLedgerKey = (hostId)=>`org--for-host--${hostId}`;
172
+ const hostLedgerKey = (hostId)=>`host--${hostId}`;
173
+ /**
174
+ * Record what a SUCCESSFUL site read saw, per scope. Same contract as the
175
+ * four `lockdowns/*` readers: a takedown is remembered, and anything else —
176
+ * no lock, an ordinary lock, a takedown DOWNGRADED to one — retires the
177
+ * entry, which is how a lift takes effect.
178
+ */ export function rememberSiteTakedown(hostId, states) {
179
+ rememberTakedown(orgForHostLedgerKey(hostId), states.org);
180
+ rememberTakedown(hostLedgerKey(hostId), states.host);
181
+ }
182
+ /**
183
+ * What a FAILED site read may still serve: the remembered, still-active
184
+ * takedowns at org and host scope, or nulls — which is the shipped fail-open
185
+ * answer and therefore the default for every lock that is not an observed
186
+ * takedown.
187
+ */ export function heldSiteTakedown(hostId, nowMs) {
188
+ return {
189
+ org: heldTakedown(orgForHostLedgerKey(hostId), nowMs),
190
+ host: heldTakedown(hostLedgerKey(hostId), nowMs)
191
+ };
192
+ }
193
+ let platformCache;
194
+ let platformPending;
195
+ /**
196
+ * Drop the in-process platform cache. Called by /api/admin/lockdown after a
197
+ * platform write so the process that took the action serves fresh verdicts
198
+ * immediately; other processes converge within PLATFORM_TTL_MS.
199
+ */ export function invalidatePlatformLockdownCache() {
200
+ platformCache = undefined;
201
+ platformPending = undefined;
202
+ }
203
+ /** `lockdowns/platform`, normalized; null = not locked (incl. on error). */ export async function getPlatformLockdown() {
204
+ if (platformCache && Date.now() - platformCache.at < PLATFORM_TTL_MS) {
205
+ return platformCache.state;
206
+ }
207
+ if (!platformPending) {
208
+ platformPending = (async ()=>{
209
+ let state;
210
+ try {
211
+ const snapshot = await firebaseAdmin.app().firestore().collection(LOCKDOWNS_COLLECTION).doc(PLATFORM_LOCKDOWN_DOC_ID).get();
212
+ state = snapshot.exists ? normalizeLockdownDoc(snapshot.data(), 'platform') : null;
213
+ rememberTakedown(PLATFORM_LEDGER_KEY, state);
214
+ } catch (unused) {
215
+ // Fail open: an unreachable Firestore is an outage, not a lockdown
216
+ // — UNLESS this process has already seen a takedown here, which is
217
+ // the one class that must survive the read failing (AGL-1621).
218
+ state = heldTakedown(PLATFORM_LEDGER_KEY, Date.now());
219
+ }
220
+ platformCache = {
221
+ at: Date.now(),
222
+ state
223
+ };
224
+ return state;
225
+ })().finally(()=>{
226
+ platformPending = undefined;
227
+ });
228
+ }
229
+ return platformPending;
230
+ }
231
+ /**
232
+ * Feature-doc cache (AGL-1510): same TTL and the same reasoning as the
233
+ * platform doc — feature gates sit on hot chokepoints (the session mint,
234
+ * every media ingress, the plugin dispatcher), and 15s is the worst-case
235
+ * lag between staff flipping a feature switch and a warm process enforcing
236
+ * it. One map for all keys; the admin route invalidates after every write.
237
+ */ /**
238
+ * Keyed by DOCUMENT ID rather than by feature key since AGL-2927, so the
239
+ * platform-wide `feature--{key}` entry and each workspace's
240
+ * `feature--{key}--org--{orgId}` entry share one map, one TTL and one
241
+ * invalidation — the admin route's write clears both kinds at once.
242
+ */ const featureCache = new Map();
243
+ const featurePending = new Map();
244
+ /** Drop the in-process feature cache (all keys) after an admin write. */ export function invalidateFeatureLockdownCache() {
245
+ featureCache.clear();
246
+ featurePending.clear();
247
+ }
248
+ /** One feature-scope carrier, by document id — see `getFeatureLockdown`. */ async function readFeatureLockdownDoc(docId) {
249
+ const cached = featureCache.get(docId);
250
+ if (cached && Date.now() - cached.at < PLATFORM_TTL_MS) return cached.state;
251
+ let pending = featurePending.get(docId);
252
+ if (!pending) {
253
+ pending = (async ()=>{
254
+ let state;
255
+ try {
256
+ const snapshot = await firebaseAdmin.app().firestore().collection(LOCKDOWNS_COLLECTION).doc(docId).get();
257
+ state = snapshot.exists ? normalizeLockdownDoc(snapshot.data(), 'feature') : null;
258
+ rememberTakedown(docId, state);
259
+ } catch (unused) {
260
+ // Fail open, matching the platform read: an unreachable Firestore is
261
+ // an outage, not a feature lockdown. A takedown-class feature lock
262
+ // this process has already observed still holds (AGL-1621).
263
+ state = heldTakedown(docId, Date.now());
264
+ }
265
+ featureCache.set(docId, {
266
+ at: Date.now(),
267
+ state
268
+ });
269
+ return state;
270
+ })().finally(()=>{
271
+ featurePending.delete(docId);
272
+ });
273
+ featurePending.set(docId, pending);
274
+ }
275
+ return pending;
276
+ }
277
+ /** `lockdowns/feature--{key}`, normalized; null = not locked (incl. error). */ export async function getFeatureLockdown(feature) {
278
+ return readFeatureLockdownDoc(featureLedgerKey(feature));
279
+ }
280
+ /**
281
+ * `lockdowns/feature--{key}--org--{orgId}` (AGL-2927): the same capability
282
+ * paused for ONE workspace. Same cache, same TTL, same fail-open posture as
283
+ * the platform-wide document; null = not paused for that org.
284
+ */ export async function getOrgFeatureLockdown(feature, orgId) {
285
+ return readFeatureLockdownDoc(orgFeatureLockdownDocId(feature, orgId));
286
+ }
287
+ /**
288
+ * The feature verdict and refusal in one call (AGL-1510) — the one-line
289
+ * wiring a feature chokepoint carries:
290
+ *
291
+ * const locked = await featureLockdownRefusal({ feature: 'checkout', staff })
292
+ * if (locked) return locked
293
+ *
294
+ * Composition, not ranking: a PLATFORM lock implies every feature, so it is
295
+ * checked first (TTL-cached — routes that already ran the scope verdict pay
296
+ * no extra read), and the platform-scope staff bypass there is UNCHANGED
297
+ * and unconditional. The feature doc is checked second, and its staff
298
+ * bypass is per-feature (`lockdownFeatureStaffBypass`): granted where a
299
+ * staff action aids incident response (uploads, installs, ai-assist),
300
+ * withheld where it would BE the incident (checkout — a staff checkout
301
+ * session is still a real charge). A feature lock implies nothing about the
302
+ * org/host/user scopes — those stay with `lockdownRefusal` at the routes
303
+ * that carry it.
304
+ *
305
+ * A door that names the org it serves passes `orgId` (AGL-2927), and the
306
+ * workspace-scoped carrier for the same feature is checked third, under the
307
+ * same per-feature staff bypass: the staff AI pause is a spend stop on one
308
+ * customer, and a staff call made to verify the pause is ours to spend. A
309
+ * door that names no org — the plugin dispatcher, which gates by path
310
+ * before the body is read — sees the platform-wide document only, which is
311
+ * what it saw before.
312
+ */ export async function featureLockdownRefusal(options) {
313
+ var _options_nowMs;
314
+ var _options_orgId;
315
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
316
+ const platform = await getPlatformLockdown();
317
+ if (isLockdownActive(platform, nowMs)) {
318
+ // The un-panic invariant at the platform scope, unchanged.
319
+ if (options.staff === true) return null;
320
+ return lockdownJsonResponse(platform);
321
+ }
322
+ const bypass = options.staff === true && lockdownFeatureStaffBypass(options.feature);
323
+ const state = await getFeatureLockdown(options.feature);
324
+ if (isLockdownActive(state, nowMs)) {
325
+ return bypass ? null : lockdownJsonResponse(state);
326
+ }
327
+ const orgId = (_options_orgId = options.orgId) == null ? void 0 : _options_orgId.trim();
328
+ if (!orgId) return null;
329
+ const paused = await getOrgFeatureLockdown(options.feature, orgId);
330
+ if (!isLockdownActive(paused, nowMs)) return null;
331
+ return bypass ? null : lockdownJsonResponse(paused);
332
+ }
333
+ /**
334
+ * User-doc cache (AGL-1522): the last per-call read on the verdict path.
335
+ * AGL-1506 wired the verdict into ~36 routes plus the session mint/exchange,
336
+ * and every call carrying a `uid` paid one Firestore get on
337
+ * `lockdowns/user--{uid}` — an active console editor generated one read per
338
+ * wired mutation, against the AGL-1302 read budget. Same TTL, same pending
339
+ * dedupe, same fail-open posture as the platform and feature caches above —
340
+ * ONE cache pattern in this module, not three implementations.
341
+ *
342
+ * The staleness tradeoff, stated: a user locked mid-window keeps passing
343
+ * this check for up to PLATFORM_TTL_MS (15s) plus the caller's polling
344
+ * cadence — on every process EXCEPT the one that took the action, which
345
+ * refuses immediately because /api/admin/lockdown invalidates this uid's
346
+ * entry after the write (the platform/feature invalidation hook, mirrored).
347
+ * That bound is acceptable here for the same reason `media/sign` omits the
348
+ * user scope entirely: the hard kill never rode this read. A user lock also
349
+ * disables the Auth account and revokes refresh tokens, so the ID token
350
+ * stops refreshing and the session cookie dies at its next
351
+ * `verifySessionCookie(…, true)` — the cache can only delay the DISTINCT
352
+ * 423 body, not access itself, and 15s matches the platform scope's stated
353
+ * worst case and the drill's measured flip times.
354
+ *
355
+ * Bounded so a scan of uids cannot balloon a warm process: past
356
+ * USER_LOCKDOWN_CACHE_MAX entries the least-recently-USED is evicted (a
357
+ * cache hit refreshes recency, so active sessions survive a scan).
358
+ */ export const USER_LOCKDOWN_CACHE_MAX = 5000;
359
+ const userCache = new Map();
360
+ const userPending = new Map();
361
+ /**
362
+ * Drop one uid's cached verdict (after a user lock/unlock write), or the
363
+ * whole cache when called bare. The acting process serves a fresh verdict
364
+ * immediately; other processes converge within PLATFORM_TTL_MS.
365
+ */ export function invalidateUserLockdownCache(uid) {
366
+ if (uid === undefined) {
367
+ userCache.clear();
368
+ userPending.clear();
369
+ return;
370
+ }
371
+ userCache.delete(uid);
372
+ userPending.delete(uid);
373
+ }
374
+ /** `lockdowns/user--{uid}`, normalized; null = not locked (incl. on error). */ export async function getUserLockdown(uid) {
375
+ const cached = userCache.get(uid);
376
+ if (cached && Date.now() - cached.at < PLATFORM_TTL_MS) {
377
+ // Re-insert to refresh recency: eviction is by least-recently-used, and
378
+ // an ACTIVE session must not be the one a uid scan pushes out.
379
+ userCache.delete(uid);
380
+ userCache.set(uid, cached);
381
+ return cached.state;
382
+ }
383
+ let pending = userPending.get(uid);
384
+ if (!pending) {
385
+ pending = (async ()=>{
386
+ let state;
387
+ try {
388
+ const snapshot = await firebaseAdmin.app().firestore().collection(LOCKDOWNS_COLLECTION).doc(userLockdownDocId(uid)).get();
389
+ state = snapshot.exists ? normalizeLockdownDoc(snapshot.data(), 'user') : null;
390
+ rememberTakedown(userLedgerKey(uid), state);
391
+ } catch (unused) {
392
+ // Fail open, matching the platform and feature reads: an unreachable
393
+ // Firestore is an outage, not a lockdown. An observed takedown-class
394
+ // user lock holds through it (AGL-1621).
395
+ state = heldTakedown(userLedgerKey(uid), Date.now());
396
+ }
397
+ userCache.delete(uid);
398
+ userCache.set(uid, {
399
+ at: Date.now(),
400
+ state
401
+ });
402
+ while(userCache.size > USER_LOCKDOWN_CACHE_MAX){
403
+ const oldest = userCache.keys().next().value;
404
+ if (oldest === undefined) break;
405
+ userCache.delete(oldest);
406
+ }
407
+ return state;
408
+ })().finally(()=>{
409
+ userPending.delete(uid);
410
+ });
411
+ userPending.set(uid, pending);
412
+ }
413
+ return pending;
414
+ }
415
+ /**
416
+ * DOMAIN-lock cache (AGL-1513), same shape and same TTL as the user cache.
417
+ *
418
+ * Bounded for the same reason and one more: the key is a HOSTNAME taken from
419
+ * the request, so an unbounded map here would be attacker-keyed by anyone who
420
+ * can point a DNS record at us — which, for the hijack incident this scope
421
+ * exists for, is the adversary by definition.
422
+ */ export const DOMAIN_LOCKDOWN_CACHE_MAX = 5000;
423
+ const domainCache = new Map();
424
+ const domainPending = new Map();
425
+ /**
426
+ * Drop one hostname's cached verdict (after a domain lock/unlock write), or
427
+ * the whole cache when called bare.
428
+ */ export function invalidateDomainLockdownCache(hostname) {
429
+ if (hostname === undefined) {
430
+ domainCache.clear();
431
+ domainPending.clear();
432
+ return;
433
+ }
434
+ const key = hostname.trim().toLowerCase();
435
+ domainCache.delete(key);
436
+ domainPending.delete(key);
437
+ }
438
+ /**
439
+ * `lockdowns/domain--{hostname}`, normalized; null = not locked (incl. on
440
+ * error), matching every other reader here — an unreachable Firestore is an
441
+ * outage, not a lockdown.
442
+ */ export async function getDomainLockdown(hostname) {
443
+ const key = String(hostname != null ? hostname : '').trim().toLowerCase();
444
+ if (!key) return null;
445
+ const cached = domainCache.get(key);
446
+ if (cached && Date.now() - cached.at < PLATFORM_TTL_MS) {
447
+ // Re-insert to refresh recency, like the user cache: eviction is
448
+ // least-recently-USED, and a domain under active dispute is exactly the
449
+ // one a scan must not push out.
450
+ domainCache.delete(key);
451
+ domainCache.set(key, cached);
452
+ return cached.state;
453
+ }
454
+ let pending = domainPending.get(key);
455
+ if (!pending) {
456
+ pending = (async ()=>{
457
+ let state;
458
+ try {
459
+ const snapshot = await firebaseAdmin.app().firestore().collection(LOCKDOWNS_COLLECTION).doc(domainLockdownDocId(key)).get();
460
+ state = snapshot.exists ? normalizeLockdownDoc(snapshot.data(), 'domain') : null;
461
+ rememberTakedown(domainLedgerKey(key), state);
462
+ } catch (unused) {
463
+ // Fail open, as above — and, as above, an observed takedown holds.
464
+ // This is the scope where that matters most: AGL-1513's hijack and
465
+ // dispute incidents are takedowns almost by definition.
466
+ state = heldTakedown(domainLedgerKey(key), Date.now());
467
+ }
468
+ domainCache.delete(key);
469
+ domainCache.set(key, {
470
+ at: Date.now(),
471
+ state
472
+ });
473
+ while(domainCache.size > DOMAIN_LOCKDOWN_CACHE_MAX){
474
+ const oldest = domainCache.keys().next().value;
475
+ if (oldest === undefined) break;
476
+ domainCache.delete(oldest);
477
+ }
478
+ return state;
479
+ })().finally(()=>{
480
+ domainPending.delete(key);
481
+ });
482
+ domainPending.set(key, pending);
483
+ }
484
+ return pending;
485
+ }
486
+ /** The declared or derived intent of a verdict request; `write` by default. */ function verdictIntent(options) {
487
+ if (options.intent) return options.intent;
488
+ if (options.request) return lockdownIntentForMethod(options.request.method);
489
+ return 'write';
490
+ }
491
+ /**
492
+ * The one verdict: the lockdown that REFUSES this caller's request, or null.
493
+ * Precedence platform > org > host > user, strictness before width (from
494
+ * `resolveLockdown`).
495
+ *
496
+ * "Refuses this request" rather than "covers this caller" since AGL-1511: a
497
+ * read-only lock is active but does not refuse a read, and returning it
498
+ * anyway would make every wired chokepoint 423 a GET — a read-only mode that
499
+ * behaves exactly like a full one. The active state is still what
500
+ * `resolveLockdown` chose, so the staff probe and the notice copy see the
501
+ * real lock; only the ANSWER is intent-aware.
502
+ */ export async function getLockdownVerdict(options) {
503
+ var _options_nowMs;
504
+ // THE UN-PANIC INVARIANT. Staff are never locked out, by any scope, ever
505
+ // — they are the only ones who can lift a lockdown. Keep this line first:
506
+ // everything below it may read Firestore, and a staff verdict must not
507
+ // depend on any read succeeding.
508
+ //
509
+ // This line is also the whole of AGL-1511's "staff writes bypass
510
+ // read-only": staff bypass every scope AND every mode, unconditionally,
511
+ // and read-only exists precisely so staff can work while the world reads.
512
+ // A mode-aware staff rule below would be a second bypass to keep correct.
513
+ if (options.staff === true) return null;
514
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
515
+ const [platform, user] = await Promise.all([
516
+ getPlatformLockdown(),
517
+ options.uid ? getUserLockdown(options.uid) : Promise.resolve(null)
518
+ ]);
519
+ const state = resolveLockdown({
520
+ platform,
521
+ org: normalizeOrgLockdown(options.org),
522
+ host: normalizeHostLockdown(options.host),
523
+ user
524
+ }, nowMs);
525
+ return lockdownBlocks(state, verdictIntent(options)) ? state : null;
526
+ }
527
+ /**
528
+ * The refusal an API route returns for a locked caller: **423 Locked** with
529
+ * a machine-readable body, so an API consumer sees "suspended: billing" and
530
+ * not a mystery 403. Carries only the sanitized, user-facing subset — never
531
+ * the actor uid or staff rationale.
532
+ */ /**
533
+ * Verdict and refusal in one call — the two-line wiring every org-scoped
534
+ * API route carries (AGL-1506):
535
+ *
536
+ * const locked = await lockdownRefusal({ staff, uid, org, host })
537
+ * if (locked) return locked
538
+ *
539
+ * Null means "not locked, proceed". One mechanism: this delegates to
540
+ * `getLockdownVerdict` (so the un-panic invariant and fail-open posture are
541
+ * inherited, never re-implemented) and to `lockdownJsonResponse` for the
542
+ * distinct 423 body. Routes with a richer flow (the session mint clears
543
+ * cookies on refusal) keep calling the two halves directly.
544
+ */ export async function lockdownRefusal(options) {
545
+ const state = await getLockdownVerdict(options);
546
+ return state ? lockdownJsonResponse(state, {
547
+ notice: options.notice
548
+ }) : null;
549
+ }
550
+ export function lockdownJsonResponse(state, options) {
551
+ var _ref;
552
+ const notice = (_ref = options == null ? void 0 : options.notice) != null ? _ref : lockdownNotice(state);
553
+ const retryAfter = lockdownRetryAfterSeconds(state, Date.now());
554
+ return Response.json(_extends({
555
+ error: 'locked',
556
+ scope: state.scope
557
+ }, state.mode ? {
558
+ mode: state.mode
559
+ } : {}, state.feature ? {
560
+ feature: state.feature
561
+ } : {}, {
562
+ reason: state.reason,
563
+ title: notice.title,
564
+ message: notice.body
565
+ }, notice.contact ? {
566
+ contact: notice.contact
567
+ } : {}, typeof state.untilMs === 'number' ? {
568
+ untilMs: state.untilMs
569
+ } : {}), {
570
+ status: 423,
571
+ headers: _extends({
572
+ 'Cache-Control': 'no-store'
573
+ }, retryAfter ? {
574
+ 'Retry-After': String(retryAfter)
575
+ } : {})
576
+ });
577
+ }
578
+ /** Bounded: the panic page must render even when this call is the slow one. */ const IDENTITY_CONFIG_TIMEOUT_MS = 4000;
579
+ export async function readSignupsCreationTriggerStatus() {
580
+ let token;
581
+ let projectId;
582
+ try {
583
+ var _app_options_projectId;
584
+ var _this, _app_options_credential;
585
+ // `getApp()`, not `firebaseAdmin.app()`: the local shim narrows the app
586
+ // to its four accessors and drops `options`, which is where the
587
+ // credential and the project id live. Same acquisition path as the
588
+ // error-beacon target (`client-error-report.ts`).
589
+ const app = getApp();
590
+ projectId = (_app_options_projectId = app.options.projectId) != null ? _app_options_projectId : process.env['NEXT_PUBLIC_FIREBASE_PROJECT_ID'];
591
+ token = (_this = await ((_app_options_credential = app.options.credential) == null ? void 0 : _app_options_credential.getAccessToken())) == null ? void 0 : _this.access_token;
592
+ } catch (unused) {
593
+ token = undefined;
594
+ }
595
+ if (!token || !projectId) {
596
+ return {
597
+ status: 'unknown',
598
+ reason: 'No admin credential or project id on this deployment, so the ' + 'Identity Platform config could not be read.'
599
+ };
600
+ }
601
+ const controller = new AbortController();
602
+ const timer = setTimeout(()=>controller.abort(), IDENTITY_CONFIG_TIMEOUT_MS);
603
+ try {
604
+ var _trigger_functionUri, _trigger_updateTime;
605
+ var _payload_blockingFunctions_triggers, _payload_blockingFunctions;
606
+ const response = await fetch(`https://identitytoolkit.googleapis.com/admin/v2/projects/${encodeURIComponent(projectId)}/config`, {
607
+ headers: {
608
+ Authorization: `Bearer ${token}`
609
+ },
610
+ signal: controller.signal
611
+ });
612
+ if (!response.ok) {
613
+ return {
614
+ status: 'unknown',
615
+ reason: `Identity Platform config read returned ${response.status}.`
616
+ };
617
+ }
618
+ const payload = await response.json();
619
+ // The trigger key Identity Platform uses is `beforeCreate`; the Firebase
620
+ // SDK's `beforeUserCreated` is what registers it. Absent means the valve
621
+ // is not deployed OR was deployed and never registered — indistinguishable
622
+ // from here, and both mean the same thing to an operator: creation is not
623
+ // being refused.
624
+ const trigger = (_payload_blockingFunctions = payload.blockingFunctions) == null ? void 0 : (_payload_blockingFunctions_triggers = _payload_blockingFunctions.triggers) == null ? void 0 : _payload_blockingFunctions_triggers['beforeCreate'];
625
+ if (!trigger) return {
626
+ status: 'absent'
627
+ };
628
+ return {
629
+ status: 'armed',
630
+ functionUri: (_trigger_functionUri = trigger.functionUri) != null ? _trigger_functionUri : null,
631
+ updateTime: (_trigger_updateTime = trigger.updateTime) != null ? _trigger_updateTime : null
632
+ };
633
+ } catch (error) {
634
+ return {
635
+ status: 'unknown',
636
+ reason: (error == null ? void 0 : error.name) === 'AbortError' ? 'Identity Platform config read timed out.' : 'Identity Platform config could not be read.'
637
+ };
638
+ } finally{
639
+ clearTimeout(timer);
640
+ }
641
+ }
642
+
643
+ //# sourceMappingURL=lockdown.js.map