@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 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/tenant/data/admin/src/lib/server/free-workspace-cap.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * THE FREE-WORKSPACE CEILING (AGL-2265).\n *\n * Every free cap in the product is enforced PER ORG, and nothing bounded how\n * many orgs one account could hold — so the free allowance multiplied by\n * workspaces: N orgs = N sites, N × 250 MB media, N × 5 GB bandwidth, N × 10\n * Assist messages a day. `/api/orgs/create` is rate limited per uid and per IP\n * (AGL-1534), which bounds the RATE and not the TOTAL.\n *\n * the decision, 2026-08-19: **three, with a control in the staff console.**\n * Three is the number; the number living in a Firestore document rather than a\n * constant is the other half of the decision, because the population this\n * refuses (a script minting workspaces) and the population it must not refuse\n * (an agency, a consultant, a customer support raises) are told apart by a\n * human, and a human must not need a deploy to say yes.\n *\n * ## What counts\n *\n * A FREE workspace ATTRIBUTED to the account. Three properties, each of which\n * is a bug if it is wrong:\n *\n * - **Paid workspaces do not count.** An agency's workspaces are paid, and\n * the abuse this closes is free-allowance multiplication. `plan` is read\n * through `resolveEffectivePlan`, so a workspace whose subscription died\n * counts again — correctly: it is free again.\n * - **Being INVITED to someone else's workspace never counts.** The count\n * comes off `orgs`, keyed by ownership and creation. It never reads\n * `users/{uid}/orgs`, which is a membership index — a contractor added to\n * ten client workspaces owns none of them.\n * - **Handing a workspace away does not free a slot.** See below; this is\n * the whole difficulty.\n *\n * ## Why the count is not launderable\n *\n * A create-time quota computed from a number the applicant can lower is not a\n * quota. The cheap laundering sequence here is not deletion — deleting a\n * workspace really does give up the workspace — it is **ownership transfer**,\n * which is free, instant and reversible:\n *\n * hold 3 → transfer #3 to an alt account → count reads 2 → create a 4th\n * → transfer #3 back → hold 4, having never been refused.\n *\n * So the count is the UNION of two sets: workspaces the account owns NOW\n * (`ownerUid`) and workspaces the account CREATED (`createdByUid`).\n * `createdByUid` is stamped once, inside the creating transaction, and no code\n * path anywhere mutates it — `transferOrgOwnership` moves `ownerUid` and does\n * not touch it. Transferring away therefore changes nothing about the count,\n * and the sequence above is refused at the fourth workspace exactly as it\n * would have been without the detour. Erasing a workspace removes the org\n * document from both sets, which is the one decrement that is honest: the\n * allowance it was multiplying went with it.\n *\n * (Orgs created before this shipped carry no `createdByUid`. They are counted\n * by `ownerUid` like always, so the union is never smaller than the old\n * behaviour; it only stops shrinking under a transfer.)\n *\n * ## Why the decision is atomic\n *\n * The count is read INSIDE the org-creation transaction, and the transaction\n * also reads-and-writes a per-owner marker document. Without that marker, two\n * `/api/orgs/create` requests in flight together would both observe three,\n * both find headroom and both commit a fourth and a fifth: the new org\n * documents are not in either transaction's read set, so nothing would make\n * them contend. The marker is a document they DO both read and both write, so\n * the second commit aborts, the callback re-runs, its queries re-read at the\n * new read time, they now see the org the first request committed, and it is\n * refused. That is the AGL-2267 lesson — a read-then-write quota must contend\n * on something.\n *\n * ## Storage, and why it needs no rules or index deploy\n *\n * The ceiling lives at `rateLimits/freeWorkspaceCapConfig` and the per-owner\n * marker at `rateLimits/freeWorkspaces_{uid}`, the same collection AGL-794's\n * counters and AGL-2409's send-rate ramp already use, and for the same\n * reason: it inherits the deny-all security rule and the `expiresAt` TTL\n * policy that already exist. Deny-all matters here — no client, staff\n * included, may write the ceiling; the audited console route is the only\n * writer.\n *\n * The config document **must never carry `expiresAt`**, or the TTL policy that\n * serves the counters would delete the ceiling and the platform would silently\n * revert to the compiled-in default. The marker document carries one on\n * purpose: it is disposable, its only job is contention, and a swept marker\n * costs nothing because the queries are the authority for the number.\n *\n * ## Failure posture: the DEFAULT, which is neither open nor closed\n *\n * An unreadable configuration resolves to the compiled-in 3 and reports\n * `ready: false`. Not zero — a Firestore blip must not refuse every signup on\n * the platform. Not unlimited — a Firestore blip must not be the way through\n * the control. `checkQuota(undefined)` resolving to the free tier is a bug\n * this codebase has already had; `freeWorkspaceCapVerdict` therefore takes\n * `ready` as an explicit input and a not-yet-loaded limit is never read as a\n * number.\n */\n\nimport { resolveEffectivePlan } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from './firebase-admin'\nimport { RATE_LIMIT_COLLECTION } from './rate-limit-store'\n\n/** the number, 2026-08-19. The floor the console can move off. */\nexport const DEFAULT_FREE_WORKSPACE_CAP = 3\n\n/** Document id of the live ceiling. NEVER written with `expiresAt`. */\nexport const FREE_WORKSPACE_CAP_CONFIG_DOC = 'freeWorkspaceCapConfig'\n\n/** Id prefix for the per-owner contention markers. */\nexport const FREE_WORKSPACE_MARKER_PREFIX = 'freeWorkspaces_'\n\n/** Bounds the console will accept. One is a real answer; zero is not. */\nexport const FREE_WORKSPACE_CAP_MIN = 1\nexport const FREE_WORKSPACE_CAP_MAX = 500\n\n/** Longest audited note the console may attach to a change. */\nexport const FREE_WORKSPACE_CAP_NOTE_MAX = 280\n\n/**\n * How many of an owner's org documents the count will read.\n *\n * The count filters by plan in memory (`plan` is not a queryable predicate\n * that survives `resolveEffectivePlan`'s subscription check), so the query\n * cannot be bounded at the ceiling. An account holding more orgs than this is\n * far past any ceiling staff would set and is a support conversation, not a\n * create-time decision.\n */\nexport const FREE_WORKSPACE_SCAN_LIMIT = 250\n\n/** How long a contention marker survives. Disposable — see the notes above. */\nexport const FREE_WORKSPACE_MARKER_TTL_MS = 24 * 60 * 60 * 1000\n\nexport interface FreeWorkspaceCapConfig {\n /** Free workspaces one account may hold. */\n limit: number\n /** False turns the ceiling OFF entirely (staff kill switch). */\n enabled: boolean\n /** Why it is where it is — shown on the card, written to the audit row. */\n note: string\n updatedAtMs: number | null\n updatedByEmail: string | null\n /**\n * Whether this is a value that was actually READ, or the compiled-in\n * default standing in for one that could not be.\n *\n * Exposed rather than swallowed because a loading default answering a\n * question as though it were a real value is a bug shape this codebase has\n * shipped before. Callers that must not act on a guess check this; the\n * verdict function below treats it as the difference between \"the operator\n * chose unlimited\" and \"we do not know yet\", and the second is never\n * unlimited.\n */\n ready: boolean\n}\n\n/** The marker document id for one owner. */\nexport function freeWorkspaceMarkerDocId(uid: string): string {\n return `${FREE_WORKSPACE_MARKER_PREFIX}${uid}`\n}\n\n/**\n * Coerces whatever is stored (or nothing) into a usable ceiling.\n *\n * A missing, non-numeric, zero, negative or absurd `limit` becomes the\n * compiled-in default rather than zero. Storing a broken number must not be a\n * way to refuse every signup, and it must not be a way to admit everyone\n * either — both are the same mistake with opposite signs.\n */\nexport function normalizeFreeWorkspaceCapConfig(\n data: Partial<FreeWorkspaceCapConfig> | null | undefined,\n options?: { ready?: boolean },\n): FreeWorkspaceCapConfig {\n const rawLimit = Number(data?.limit)\n const limit =\n Number.isFinite(rawLimit) && rawLimit >= FREE_WORKSPACE_CAP_MIN\n ? Math.min(FREE_WORKSPACE_CAP_MAX, Math.floor(rawLimit))\n : DEFAULT_FREE_WORKSPACE_CAP\n const updatedAtMs = Number(data?.updatedAtMs)\n return {\n limit,\n // Only an explicit `false` turns it off — an absent field is ON, so a\n // half-written document cannot silently disable the ceiling.\n enabled: data?.enabled !== false,\n note: typeof data?.note === 'string' ? data.note.slice(0, FREE_WORKSPACE_CAP_NOTE_MAX) : '',\n updatedAtMs: Number.isFinite(updatedAtMs) && updatedAtMs > 0 ? updatedAtMs : null,\n updatedByEmail:\n typeof data?.updatedByEmail === 'string' && data.updatedByEmail\n ? data.updatedByEmail\n : null,\n ready: options?.ready !== false,\n }\n}\n\nexport interface FreeWorkspaceCapVerdict {\n allowed: boolean\n /** The ceiling the decision was actually made against. */\n limit: number\n held: number\n remaining: number\n /** False when the ceiling was a stand-in rather than a value we read. */\n ready: boolean\n /** True when the ceiling is switched off and this granted for that reason. */\n disabled: boolean\n}\n\n/**\n * The whole decision, pure.\n *\n * The `ready` input is the point of the signature. A config that has not\n * loaded arrives here as `{ ready: false }` and is answered against the\n * compiled-in default — never as `limit: 0` (which would refuse every signup\n * on the platform during a blip) and never as \"no limit known, therefore no\n * limit\" (which would make an outage the way through the control).\n */\nexport function freeWorkspaceCapVerdict(input: {\n held: number\n limit?: number | null\n enabled?: boolean\n ready?: boolean\n}): FreeWorkspaceCapVerdict {\n const ready = input.ready !== false\n const rawHeld = Number(input.held)\n const held = Number.isFinite(rawHeld) && rawHeld > 0 ? Math.floor(rawHeld) : 0\n const rawLimit = Number(input.limit)\n // An unready config does not get to contribute a number at all, even if one\n // happens to be sitting in the field.\n const limit =\n ready && Number.isFinite(rawLimit) && rawLimit >= FREE_WORKSPACE_CAP_MIN\n ? Math.min(FREE_WORKSPACE_CAP_MAX, Math.floor(rawLimit))\n : DEFAULT_FREE_WORKSPACE_CAP\n const disabled = input.enabled === false\n return {\n allowed: disabled || held < limit,\n limit,\n held,\n remaining: Math.max(0, limit - held),\n ready,\n disabled,\n }\n}\n\n/**\n * Whether an org document is on the free plan for the purposes of this count.\n *\n * `resolveEffectivePlan` and not `data.plan`: a workspace whose subscription\n * is canceled or unpaid resolves back to free, which is right — it is\n * consuming the free allowance again, so it counts again.\n */\nexport function isFreeOrgDoc(data: unknown): boolean {\n return resolveEffectivePlan((data ?? {}) as never) === 'free'\n}\n\n/**\n * The two queries whose UNION is the attributed set. Exported so the spec can\n * assert the second one exists — the union IS the anti-laundering property,\n * and a future edit that drops `createdByUid` for being redundant would put\n * the transfer sequence back without changing any behaviour a happy-path test\n * observes.\n */\nexport function freeWorkspaceOwnerQueries(firestore: any, uid: string): any[] {\n const orgs = firestore.collection('orgs')\n return [\n orgs.where('ownerUid', '==', uid).limit(FREE_WORKSPACE_SCAN_LIMIT),\n orgs.where('createdByUid', '==', uid).limit(FREE_WORKSPACE_SCAN_LIMIT),\n ]\n}\n\nexport interface FreeWorkspaceCount {\n held: number\n orgIds: string[]\n}\n\n/**\n * How many free workspaces are attributed to `uid`.\n *\n * `readQuery` is how the caller runs each query, and it is the whole\n * difference between the two callers: outside a transaction a query runs\n * itself (`query.get()`), inside one it must run through the transaction\n * (`tx.get(query)`) or the count is not in the read set and the retry that\n * makes this atomic never happens. Passing a Firestore instance and calling\n * `firestore.get(query)` would silently be neither — that method does not\n * exist, and the count would come back as zero, admitting everyone.\n */\nasync function countAttributedFreeWorkspaces(\n readQuery: (query: any) => Promise<any>,\n firestore: any,\n uid: string,\n): Promise<FreeWorkspaceCount> {\n const seen = new Map<string, unknown>()\n for (const query of freeWorkspaceOwnerQueries(firestore, uid)) {\n const snapshot = await readQuery(query)\n for (const doc of snapshot?.docs ?? []) {\n // Deduplicated by id: the common case is one org in BOTH sets.\n if (!seen.has(doc.id)) seen.set(doc.id, doc.data())\n }\n }\n const orgIds = [...seen.entries()]\n .filter(([, data]) => isFreeOrgDoc(data))\n .map(([id]) => id)\n return { held: orgIds.length, orgIds }\n}\n\n/**\n * Read-only count, for the console and for anything that wants to explain a\n * refusal after the fact. The creation path does NOT use this — it counts\n * inside its own transaction.\n */\nexport async function countFreeWorkspacesForOwner(options: {\n uid: string\n firestore?: any\n}): Promise<FreeWorkspaceCount> {\n const firestore = options.firestore ?? firebaseAdmin.app().firestore()\n try {\n return await countAttributedFreeWorkspaces(\n (query) => query.get(),\n firestore,\n options.uid,\n )\n } catch (error) {\n console.error('[free-workspace-cap] count unavailable', error)\n return { held: 0, orgIds: [] }\n }\n}\n\n/**\n * Config cache TTL. 15s, the same number and reasoning as the lockdown doc\n * and the send-rate ramp: staff move this rarely and a warm process converges\n * within a quarter of a minute.\n */\nconst CONFIG_TTL_MS = 15_000\n\nlet configCache: { at: number; config: FreeWorkspaceCapConfig } | undefined\nlet configPending: Promise<FreeWorkspaceCapConfig> | undefined\n\n/** Drop the in-process config cache — called by the console after a write. */\nexport function invalidateFreeWorkspaceCapConfigCache(): void {\n configCache = undefined\n configPending = undefined\n}\n\n/**\n * The live ceiling.\n *\n * An unreachable document returns the compiled-in default with\n * `ready: false`, which every caller must carry rather than flatten — see the\n * failure-posture note at the top of the file.\n */\nexport async function readFreeWorkspaceCapConfig(options?: {\n firestore?: any\n now?: number\n}): Promise<FreeWorkspaceCapConfig> {\n const now = options?.now ?? Date.now()\n if (!options?.firestore && configCache && now - configCache.at < CONFIG_TTL_MS) {\n return configCache.config\n }\n const load = async (): Promise<FreeWorkspaceCapConfig> => {\n try {\n const firestore = options?.firestore ?? firebaseAdmin.app().firestore()\n const snapshot = await firestore\n .collection(RATE_LIMIT_COLLECTION)\n .doc(FREE_WORKSPACE_CAP_CONFIG_DOC)\n .get()\n // A document that does not exist is READY: nobody has changed the\n // number, and the compiled-in 3 is the answer, not a guess.\n return normalizeFreeWorkspaceCapConfig(\n snapshot?.exists\n ? (snapshot.data() as Partial<FreeWorkspaceCapConfig>)\n : null,\n { ready: true },\n )\n } catch {\n return normalizeFreeWorkspaceCapConfig(null, { ready: false })\n }\n }\n // An injected firestore is a test or a one-off read; never cached, so a\n // spec cannot poison the process cache for the next one.\n if (options?.firestore) return load()\n if (!configPending) {\n configPending = load()\n .then((config) => {\n // A degraded read is never cached — the next create should try again\n // rather than serve a stand-in for fifteen seconds.\n if (config.ready) configCache = { at: now, config }\n return config\n })\n .finally(() => {\n configPending = undefined\n })\n }\n return configPending\n}\n\n/**\n * The document the console writes when staff move the ceiling.\n *\n * Returned rather than written so the route owns the write (and the audit row\n * beside it), and so a spec can assert the SHAPE without a Firestore. The one\n * thing it must never contain is `expiresAt`.\n */\nexport function freeWorkspaceCapConfigWrite(input: {\n limit: number\n enabled: boolean\n actorEmail?: string | null\n note?: string\n now?: number\n}): Partial<FreeWorkspaceCapConfig> {\n const normalized = normalizeFreeWorkspaceCapConfig({\n limit: input.limit,\n enabled: input.enabled,\n note: input.note,\n updatedAtMs: input.now ?? Date.now(),\n updatedByEmail: input.actorEmail ?? null,\n })\n return {\n limit: normalized.limit,\n enabled: normalized.enabled,\n note: normalized.note,\n updatedAtMs: normalized.updatedAtMs,\n updatedByEmail: normalized.updatedByEmail,\n }\n}\n\n/**\n * Thrown by `createOrganization` when the ceiling refuses. Carries the numbers\n * so the API route can say which ceiling and how many, rather than \"no\".\n */\nexport class FreeWorkspaceCapError extends Error {\n readonly limit: number\n readonly held: number\n constructor(verdict: { limit: number; held: number }) {\n super(\n `Free workspace ceiling reached: ${verdict.held} of ${verdict.limit}`,\n )\n this.name = 'FreeWorkspaceCapError'\n this.limit = verdict.limit\n this.held = verdict.held\n }\n}\n\n/**\n * The create-time gate, run INSIDE the creating transaction.\n *\n * Reads the attributed count through `tx` (so it is part of the read set and\n * re-runs against fresh data on a retry) and reads-then-writes the per-owner\n * marker (so two concurrent creates by one account contend, and the loser\n * re-runs and sees the winner's org).\n *\n * Throws `FreeWorkspaceCapError` when it refuses. Firestore does not retry a\n * callback that threw, which is what we want: a refusal is a decision, not\n * contention.\n *\n * Call it AFTER the caller's other reads and BEFORE the caller's writes — it\n * both reads and writes, and Firestore requires all reads first.\n */\nexport async function enforceFreeWorkspaceCapInTransaction(options: {\n tx: any\n firestore: any\n uid: string\n config: FreeWorkspaceCapConfig\n now?: number\n}): Promise<FreeWorkspaceCapVerdict> {\n const { tx, firestore, uid, config } = options\n const now = options.now ?? Date.now()\n const markerRef = firestore\n .collection(RATE_LIMIT_COLLECTION)\n .doc(freeWorkspaceMarkerDocId(uid))\n\n const [count, marker] = await Promise.all([\n countAttributedFreeWorkspaces((query) => tx.get(query), firestore, uid),\n tx.get(markerRef),\n ])\n\n const verdict = freeWorkspaceCapVerdict({\n held: count.held,\n limit: config.limit,\n enabled: config.enabled,\n ready: config.ready,\n })\n if (!verdict.allowed) throw new FreeWorkspaceCapError(verdict)\n\n const priorCreates = Number(\n (marker?.exists ? marker.get('creates') : 0) ?? 0,\n )\n // An ABSOLUTE value derived from the read, not `FieldValue.increment`: the\n // read is what has to contend, and an increment is atomic on the number and\n // useless for the decision (AGL-2267).\n tx.set(\n markerRef,\n {\n creates: (Number.isFinite(priorCreates) ? priorCreates : 0) + 1,\n heldAtLastCreate: count.held,\n lastCreateAtMs: now,\n // Disposable. NOT on the config document — see the storage note.\n expiresAt: new Date(now + FREE_WORKSPACE_MARKER_TTL_MS),\n },\n { merge: true },\n )\n return verdict\n}\n\n/**\n * Turn a ceiling refusal into the 403 the creating routes return, or null when\n * the error is something else and must keep propagating to the 500.\n *\n * Lives here beside the policy, and mirrors `collaboratorSeatRefusalResponse`,\n * so a route's catch block is one line and cannot accidentally mask a real\n * fault. The copy names the number and the way out, because the person reading\n * it is far more often a consultant with three real workspaces than the script\n * this exists to stop.\n */\nexport function freeWorkspaceCapRefusalResponse(error: unknown): Response | null {\n if (!(error instanceof FreeWorkspaceCapError)) return null\n return Response.json(\n {\n error:\n `You already have ${error.held} free workspaces, which is the limit ` +\n `of ${error.limit}. Upgrade one of them, delete one you no longer ` +\n 'need, or contact support and we can raise the limit for your account.',\n code: 'free_workspace_limit',\n limit: error.limit,\n held: error.held,\n },\n { status: 403 },\n )\n}\n"],"names":["resolveEffectivePlan","firebaseAdmin","RATE_LIMIT_COLLECTION","DEFAULT_FREE_WORKSPACE_CAP","FREE_WORKSPACE_CAP_CONFIG_DOC","FREE_WORKSPACE_MARKER_PREFIX","FREE_WORKSPACE_CAP_MIN","FREE_WORKSPACE_CAP_MAX","FREE_WORKSPACE_CAP_NOTE_MAX","FREE_WORKSPACE_SCAN_LIMIT","FREE_WORKSPACE_MARKER_TTL_MS","freeWorkspaceMarkerDocId","uid","normalizeFreeWorkspaceCapConfig","data","options","rawLimit","Number","limit","isFinite","Math","min","floor","updatedAtMs","enabled","note","slice","updatedByEmail","ready","freeWorkspaceCapVerdict","input","rawHeld","held","disabled","allowed","remaining","max","isFreeOrgDoc","freeWorkspaceOwnerQueries","firestore","orgs","collection","where","countAttributedFreeWorkspaces","readQuery","seen","Map","query","snapshot","doc","docs","has","id","set","orgIds","entries","filter","map","length","countFreeWorkspacesForOwner","app","get","error","console","CONFIG_TTL_MS","configCache","configPending","invalidateFreeWorkspaceCapConfigCache","undefined","readFreeWorkspaceCapConfig","now","Date","at","config","load","exists","then","finally","freeWorkspaceCapConfigWrite","normalized","actorEmail","FreeWorkspaceCapError","Error","verdict","name","enforceFreeWorkspaceCapInTransaction","marker","tx","markerRef","count","Promise","all","priorCreates","creates","heldAtLastCreate","lastCreateAtMs","expiresAt","merge","freeWorkspaceCapRefusalResponse","Response","json","code","status"],"mappings":"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"}
@@ -0,0 +1,256 @@
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
+ export interface Ga4PurchaseItem {
18
+ item_id: string;
19
+ item_name: string;
20
+ item_category?: string;
21
+ price?: number;
22
+ quantity?: number;
23
+ }
24
+ export interface Ga4PurchaseInput {
25
+ /** Stripe object id — invoice or checkout session. GA de-duplicates on it. */
26
+ transactionId: string;
27
+ /** Whole currency units, NOT cents. */
28
+ value: number;
29
+ /** ISO 4217, upper-cased by the caller or here. */
30
+ currency: string;
31
+ items: Ga4PurchaseItem[];
32
+ billingInterval?: 'monthly' | 'annual';
33
+ /**
34
+ * The browser's GA `client_id`, captured at checkout start and carried on
35
+ * Stripe metadata. Absent for renewals and for customers whose gtag never
36
+ * ran; see the module comment.
37
+ */
38
+ clientId?: string | null;
39
+ /** Opaque Firebase uid. The one identifier GA is allowed to hold. */
40
+ userId?: string | null;
41
+ /** Stripe customer id — used ONLY to synthesize a fallback client id. */
42
+ stripeCustomerId?: string | null;
43
+ /**
44
+ * Whether this transaction is OURS — a staff or rehearsal purchase — rather
45
+ * than a customer's (AGL-1582). Carried from the browser that started
46
+ * checkout on Stripe metadata, the same way `clientId` is.
47
+ *
48
+ * Opt-in only, never inferred: wrongly flagging a real customer erases their
49
+ * revenue from every report, and a GA4 data filter is not retroactive.
50
+ */
51
+ internal?: boolean;
52
+ }
53
+ export interface Ga4SendResult {
54
+ sent: boolean;
55
+ /** True when no real browser client id was available. */
56
+ synthesizedClientId: boolean;
57
+ reason?: string;
58
+ }
59
+ /**
60
+ * A stable, opaque stand-in for a browser client id.
61
+ *
62
+ * GA expects the `<random>.<timestamp>` shape. Determinism matters more than
63
+ * realism: the same `seed` must map to the same synthetic user every time, or
64
+ * one paying customer becomes a crowd of one-purchase strangers and ARPA is
65
+ * nonsense. Derived by a cheap non-cryptographic hash — this is a bucketing
66
+ * key, not a secret, and the seed it comes from never leaves this function.
67
+ *
68
+ * The seed is whatever identifies the actor the events belong to on the
69
+ * surface doing the sending: the Stripe customer for revenue, the host id for
70
+ * a scheduled publish (AGL-1589). Both are opaque to GA — only the hash is
71
+ * ever transmitted.
72
+ */
73
+ export declare function synthesizeClientId(seed: string): string;
74
+ /**
75
+ * Send one `purchase` to GA4. Never throws.
76
+ *
77
+ * Returns a result rather than void so the caller can log the fallback rate;
78
+ * nothing about the return value should change billing behaviour.
79
+ */
80
+ export declare function sendGa4Purchase(input: Ga4PurchaseInput): Promise<Ga4SendResult>;
81
+ /**
82
+ * Send one GA4 `refund` — revenue that came back (AGL-1850). Never throws.
83
+ *
84
+ * Both `purchase` senders were one-directional, so GA revenue could only
85
+ * ever go UP: a refunded invoice or marketplace sale stayed on the books
86
+ * forever, drifting GA away from Stripe by exactly the refund volume. GA4's
87
+ * native `refund` event is built for this — sent with the ORIGINAL
88
+ * purchase's `transaction_id`, GA nets the two against each other in every
89
+ * revenue report.
90
+ *
91
+ * `transaction_id` is therefore the one field that carries the whole
92
+ * mechanism: the invoice id for a subscription refund, the checkout session
93
+ * id for a marketplace one — whatever the matching `purchase` reported,
94
+ * never the refund's own charge or event id.
95
+ *
96
+ * `value` is what actually came back, in the SAME accounting the purchase
97
+ * used. For a subscription that is `amount_refunded` (the purchase reported
98
+ * `amount_paid`, all ours); for a marketplace sale it is the platform-net
99
+ * share (the purchase reported our net per AGL-1639, so refunding the gross
100
+ * would net MORE than the sale ever reported). The caller owns that
101
+ * arithmetic because the caller holds the ledger; this sender ships whatever
102
+ * number it is handed.
103
+ *
104
+ * Same claiming rules as `purchase` (the caller discriminates, this module
105
+ * transmits), same client-id capture-or-synthesize fallback, same
106
+ * fire-and-forget posture — a throw would un-claim the Stripe event.
107
+ */
108
+ export declare function sendGa4Refund(input: Ga4PurchaseInput): Promise<Ga4SendResult>;
109
+ /**
110
+ * Send one `subscription_cancelled` — the churn half of the funnel
111
+ * (AGL-1851). Never throws.
112
+ *
113
+ * Every event instruments the way INTO revenue and nothing the way out, so
114
+ * GA could not answer churn rate, plan-tier churn mix or tenure at
115
+ * cancellation. Sent server-side for the same reason `purchase` is: a
116
+ * subscription ends with no browser present — portal cancellations at
117
+ * period end, dunning exhaustion, staff action — so a client event is not a
118
+ * weaker option, it is no option.
119
+ *
120
+ * A CUSTOM name, deliberately. GA4's only subscription-cancel vocabulary
121
+ * (`app_store_subscription_cancel`) is reserved for app-store data sources
122
+ * and a web hit wearing it is dropped, which is silence, not pollution —
123
+ * the worse failure. The params need dimension registration to report on
124
+ * (AGL-1637): `plan` — the plan being LEFT, never the `free` the org mirror
125
+ * writes; `billing_interval` — the churn half of the AGL-1640 annual-mix
126
+ * metric; `tenure_days` — whole days from the subscription's `created` to
127
+ * when it actually ended, the "how long do they stay" number.
128
+ */
129
+ export declare function sendGa4SubscriptionCancelled(input: {
130
+ /** The plan tier the org is LEAVING (metadata/price-derived, not `free`). */
131
+ plan: string;
132
+ /** `monthly` | `annual`, when the subscription's price interval said. */
133
+ billingInterval?: 'monthly' | 'annual';
134
+ /** Whole days the subscription lived; omitted when timestamps are absent. */
135
+ tenureDays?: number;
136
+ /** Same capture-or-synthesize contract as `purchase`. */
137
+ clientId?: string | null;
138
+ userId?: string | null;
139
+ stripeCustomerId?: string | null;
140
+ /** Ours rather than a customer's (AGL-1582) — see `Ga4PurchaseInput`. */
141
+ internal?: boolean;
142
+ }): Promise<Ga4SendResult>;
143
+ /**
144
+ * Send one `site_published` for a route that went live with no browser
145
+ * involved (AGL-1589). Never throws.
146
+ *
147
+ * ## Why this is allowed to be a synthetic user
148
+ *
149
+ * The client id is derived from the HOST — the site whose route went live —
150
+ * and not from the author, because the author is not present: a scheduled
151
+ * publish is applied by the cron beat minutes or hours after anybody clicked
152
+ * anything, and the browser that wrote the schedule is long gone. There is no
153
+ * session to join and nothing to attribute.
154
+ *
155
+ * Deriving it from the host rather than randomly is what keeps the metric
156
+ * honest in the one direction it can be dishonest. "% who publish a site"
157
+ * counts USERS, so a random id per publish would let one site scheduling ten
158
+ * publishes look like ten activated customers — the same inflation
159
+ * `publishScreenRoute` avoids by firing only when a route goes live. One host
160
+ * is one synthetic user, forever, however many of its screens go live on a
161
+ * timer.
162
+ *
163
+ * ## One param, deliberately
164
+ *
165
+ * `first_publish` and nothing else, matching the browser event (AGL-1588).
166
+ * The host id is a resource identifier bought for nothing, and the rest of the
167
+ * metric is answered by the event alone; the id is used only as the hash seed
168
+ * and never transmitted.
169
+ *
170
+ * The caller decides `first_publish` from the routing map it read before
171
+ * registering the entry, through the same `isFirstPublishedRoute` the console
172
+ * uses — a dimension is only worth registering if every sender means the same
173
+ * thing by it, and this sender is the one nobody can watch happen.
174
+ */
175
+ export declare function sendGa4SitePublished(input: {
176
+ /** Host uid the route went live on — hashed into a client id, never sent. */
177
+ hostId: string;
178
+ /**
179
+ * Whether the host had no live route at all before this one. Omit when it
180
+ * genuinely cannot be determined — the param is optional and an absent
181
+ * breakdown value beats an invented one.
182
+ */
183
+ firstPublish?: boolean;
184
+ /**
185
+ * Ours rather than a customer's (AGL-1582). A scheduled publish of our own
186
+ * marketing site or a demo host is an activation event for nobody, and
187
+ * `site_published` is the headline activation metric.
188
+ */
189
+ internal?: boolean;
190
+ }): Promise<Ga4SendResult>;
191
+ /**
192
+ * Send one `stripe_connected` for an account that became able to take
193
+ * payments with no browser present (AGL-1580). Never throws.
194
+ *
195
+ * ## Why this needs a server sender at all
196
+ *
197
+ * There are two client-side emitters for this event — the commerce payments
198
+ * card and the marketplace seller panel — and both are gated the same way:
199
+ *
200
+ * if (!chargesEnabled) trackEvent('stripe_connected')
201
+ *
202
+ * where `chargesEnabled` is the state read from the merchant's profile BEFORE
203
+ * the connect request. The gate is right in intent: the connect handler is a
204
+ * re-entrant create-or-resume that answers `chargesEnabled: true` on every
205
+ * later visit, so a bare event there would count one merchant once per click
206
+ * forever.
207
+ *
208
+ * What defeats it is AGL-1997. Stripe emits `account.updated` the moment
209
+ * hosted onboarding completes — while the merchant is still on Stripe's
210
+ * domain, before the `return_url` bounces them back — and
211
+ * {@link syncConnectAccountStatus} mirrors `charges_enabled` onto the profile
212
+ * from that webhook. So by the time the merchant lands back in the console
213
+ * the flag they are supposed to transition FROM already reads `true`, the
214
+ * client guard is false, and the event never fires. It is not a race that
215
+ * usually goes the wrong way; the webhook wins by an entire page load.
216
+ *
217
+ * ## The two senders cannot double-count
218
+ *
219
+ * Both key off the SAME stored flag, from opposite sides of it:
220
+ *
221
+ * - merchant clicks first → the connect route writes `true` → the later
222
+ * `account.updated` sees no transition → only the CLIENT event fires;
223
+ * - webhook lands first → the transition is here → the merchant's later click
224
+ * reads a pre-state of `true` → only the SERVER event fires.
225
+ *
226
+ * Exactly one of the two guards can be open for a given account, which is why
227
+ * this is added alongside the client emitters rather than replacing them —
228
+ * a deployment with no Connect webhook destination (the self-host default)
229
+ * still reports through the browser.
230
+ *
231
+ * ## One synthetic user per connected account
232
+ *
233
+ * The client id is hashed from the Stripe account id for the reason
234
+ * {@link sendGa4SitePublished} hashes the host: "% who connect Stripe" counts
235
+ * MERCHANTS, and a random id per hit would let one account that reconnects
236
+ * look like several activated customers. The account id is the hash seed and
237
+ * is never transmitted.
238
+ *
239
+ * ## No parameters, deliberately
240
+ *
241
+ * `stripe_connected` is declared as `Record<string, never>` in the client
242
+ * event contract, and a server sender that invented a param would create a
243
+ * dimension only half the hits carry.
244
+ */
245
+ export declare function sendGa4StripeConnected(input: {
246
+ /** Stripe account id — hashed into a client id, never sent. */
247
+ accountId: string;
248
+ /**
249
+ * Ours rather than a customer's (AGL-1582). Omitted by the webhook caller
250
+ * for the same reason the publish executor omits it: no server-side signal
251
+ * distinguishes our own connected account from a customer's, and guessing
252
+ * would stamp real merchants as internal — which a data filter then
253
+ * permanently discards.
254
+ */
255
+ internal?: boolean;
256
+ }): Promise<Ga4SendResult>;