@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,474 @@
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
+ * Duplicating a site resource whole, as a draft (AGL-2936).
19
+ *
20
+ * One module for every kind that lives under a site — screens and email
21
+ * designs, reusable components, layouts, templates, forms and workflows —
22
+ * so the console route, the AI runtime's `duplicate_resource` tool and any
23
+ * later door make the same copy: the same fields, the same uniqueness
24
+ * rules, the same band arithmetic, the same activity rows. A caller that
25
+ * has verified who is asking and that they may write the site hands over
26
+ * the ids and gets back the copy's id, or a refusal it can answer with.
27
+ *
28
+ * WHAT MAKES THE COPY A DRAFT is different per kind, and each is the
29
+ * omission of exactly one thing the create paths would otherwise do:
30
+ *
31
+ * - a screen is reachable only through the host's routing map, so the
32
+ * copy gets no entry there — it has a slug of its own (`-copy`) but no
33
+ * address until somebody publishes it;
34
+ * - a collection's entry template renders only for the collection that
35
+ * points at it, and nothing points at the copy;
36
+ * - a layout, component or form is served only where a page places it,
37
+ * and nothing places the copy;
38
+ * - a workflow runs only when its trigger fires, and the copy's trigger
39
+ * is cleared;
40
+ * - a template is inert until it is used.
41
+ *
42
+ * COUNTED LIKE A CREATE. The copy is one more document in a collection the
43
+ * plan bands, so it meets the same counter the create route meets — for a
44
+ * screen that is not a page, the flat platform ceiling rather than a band —
45
+ * and meets it INSIDE the transaction that writes the copy (AGL-2231): a count
46
+ * taken before the write is a count N concurrent copies all pass. The
47
+ * siblings are read once and answer three questions — the count, the name
48
+ * the copy may take, and the slug — because three reads of one collection
49
+ * is the reason a route and its readout come to disagree.
50
+ *
51
+ * THE VERSION TRAVELS WITH THE DOCUMENT. A besigner resource is opened by
52
+ * its version, so the copy of a screen with no version is a screen nobody
53
+ * can open. The source's most recently saved version is copied into the
54
+ * copy's own `versions` as its first — no `versioning` entitlement is
55
+ * owed for a first version — with its stored node bytes carried across
56
+ * untouched: they are msgpack at rest, and re-encoding them is the
57
+ * double-encode `encodeStoredNodes` exists to avoid.
58
+ *
59
+ * THE ONE TREE THAT IS REWRITTEN is a form's (AGL-3024). A form's design
60
+ * names its own form inside itself, so carrying those bytes across hands the
61
+ * copy a design that files every submission under the SOURCE — silently,
62
+ * because the copy still renders and the row still lands. That binding is
63
+ * moved onto the copy below. No other kind embeds its own id in its design,
64
+ * so no other kind is decoded.
65
+ */ import { billableScreenIds, checkEntitlement, checkQuota, claimAttempt, createResourceUid, decodeStoredNodes, encodeStoredNodes, nameSearchKey, NON_PAGE_SCREEN_MAX_PER_HOST, nonPageScreenIds, SCREEN_KIND_EMAIL, SCREEN_KIND_TEMPLATE, screenClaimsToBeAPage } from "@aglyn/aglyn/server";
66
+ import { DUPLICABLE_RESOURCE_NOUNS, DUPLICATE_BUSY_MESSAGE, duplicateDisplayName, duplicateVersionNote, uniqueDuplicateName, uniqueDuplicateSlug } from "@aglyn/aglyn/app-utils/duplicate-resource";
67
+ import { formDesignReboundTo } from "@aglyn/aglyn/app-utils/forms";
68
+ import { Timestamp } from "firebase-admin/firestore";
69
+ import { logResourceDuplicated } from "./duplicate-activity.js";
70
+ import firebaseAdmin from "./firebase-admin.js";
71
+ /**
72
+ * Per kind, the same fields the create route's allow-list admits, less the
73
+ * ones a copy must not inherit: a screen's `versionId` (the copy mints its
74
+ * own), a template's `source` (stamped `authored` below — a copy of a
75
+ * marketplace template is the customer's own), a workflow's `trigger`
76
+ * (cleared, so the copy runs nothing until armed), and anything the server
77
+ * stamps on every create.
78
+ */ const RECIPES = {
79
+ screen: {
80
+ collection: 'screens',
81
+ nameField: 'displayName',
82
+ fields: [
83
+ 'description',
84
+ 'seo',
85
+ 'kind',
86
+ 'visibility',
87
+ 'locale',
88
+ 'protection',
89
+ // The shared-layout binding. A version inherits it from its screen, so
90
+ // a copy without it renders with no header or footer (AGL-3120).
91
+ 'layoutId'
92
+ ],
93
+ versionParentField: 'screenId',
94
+ quotaKey: 'screensPerHost',
95
+ slug: true
96
+ },
97
+ // No `quotaKey`: an email design is not a page, so it meets the flat
98
+ // platform ceiling on non-page screens below rather than the page band.
99
+ emailDesign: {
100
+ collection: 'screens',
101
+ nameField: 'displayName',
102
+ fields: [
103
+ 'description',
104
+ 'kind'
105
+ ],
106
+ versionParentField: 'screenId'
107
+ },
108
+ component: {
109
+ collection: 'components',
110
+ nameField: 'displayName',
111
+ fields: [
112
+ 'description',
113
+ 'icon',
114
+ 'rootId',
115
+ 'nodes',
116
+ 'props'
117
+ ],
118
+ versionParentField: 'componentId',
119
+ entitlement: 'reusableComponents'
120
+ },
121
+ layout: {
122
+ collection: 'layouts',
123
+ nameField: 'displayName',
124
+ fields: [
125
+ 'description'
126
+ ],
127
+ versionParentField: 'layoutId',
128
+ quotaKey: 'sharedLayoutsPerHost'
129
+ },
130
+ template: {
131
+ collection: 'templates',
132
+ nameField: 'displayName',
133
+ fields: [
134
+ 'kind',
135
+ 'description',
136
+ 'category',
137
+ 'placeholders',
138
+ 'nodes',
139
+ 'rootId',
140
+ 'props',
141
+ 'slug',
142
+ 'seo',
143
+ 'theme'
144
+ ],
145
+ quotaKey: 'templatesPerHost',
146
+ stamps: {
147
+ source: {
148
+ type: 'authored'
149
+ }
150
+ }
151
+ },
152
+ form: {
153
+ collection: 'forms',
154
+ nameField: 'displayName',
155
+ fields: [
156
+ 'fields',
157
+ 'consentFieldName',
158
+ 'routing',
159
+ 'legacyMatch',
160
+ 'rootId',
161
+ 'nodes'
162
+ ],
163
+ versionParentField: 'formId',
164
+ quotaKey: 'formsPerHost',
165
+ entitlement: 'reusableComponents',
166
+ slug: true
167
+ },
168
+ workflow: {
169
+ collection: 'workflows',
170
+ nameField: 'name',
171
+ fields: [
172
+ 'steps',
173
+ 'returnValue'
174
+ ],
175
+ quotaKey: 'workflowsPerHost',
176
+ entitlement: 'workflows',
177
+ stamps: {
178
+ trigger: null
179
+ }
180
+ }
181
+ };
182
+ const asRecord = (value)=>value && typeof value === 'object' && !Array.isArray(value) ? value : {};
183
+ /**
184
+ * Makes the copy. The caller has authenticated `uid` and verified that they
185
+ * may write content on `hostId`; this decides everything after that.
186
+ */ export async function duplicateResource(kind, options) {
187
+ var _options_sourceId, _options_attemptKey;
188
+ const recipe = RECIPES[kind];
189
+ const noun = DUPLICABLE_RESOURCE_NOUNS[kind];
190
+ const sourceId = String((_options_sourceId = options.sourceId) != null ? _options_sourceId : '').trim().slice(0, 64);
191
+ if (!sourceId) return {
192
+ ok: false,
193
+ status: 400,
194
+ error: `Missing the ${noun} to copy`
195
+ };
196
+ const firestore = firebaseAdmin.app().firestore();
197
+ const attemptKey = String((_options_attemptKey = options.attemptKey) != null ? _options_attemptKey : '').trim().slice(0, 200);
198
+ const claimed = attemptKey ? await claimAttempt(firestore, {
199
+ kind: `duplicate-${kind}`,
200
+ scopeId: `${options.hostId}:${sourceId}`,
201
+ orgId: options.orgId,
202
+ key: attemptKey,
203
+ busyMessage: DUPLICATE_BUSY_MESSAGE
204
+ }) : null;
205
+ if (claimed && 'replay' in claimed) {
206
+ return claimed.replay.body;
207
+ }
208
+ const claim = claimed && 'claim' in claimed ? claimed.claim : null;
209
+ try {
210
+ const result = await copy(firestore, kind, recipe, _extends({}, options, {
211
+ sourceId
212
+ }));
213
+ if (result.ok) {
214
+ var _options_email;
215
+ await logResourceDuplicated(kind, {
216
+ uid: options.uid,
217
+ email: (_options_email = options.email) != null ? _options_email : null
218
+ }, {
219
+ orgId: options.orgId,
220
+ hostId: options.hostId,
221
+ source: {
222
+ id: sourceId,
223
+ name: result.sourceName
224
+ },
225
+ target: {
226
+ id: result.id,
227
+ name: result.name,
228
+ versionId: result.versionId
229
+ }
230
+ });
231
+ const answer = {
232
+ ok: true,
233
+ id: result.id,
234
+ versionId: result.versionId,
235
+ name: result.name
236
+ };
237
+ await (claim == null ? void 0 : claim.record(200, answer));
238
+ return answer;
239
+ }
240
+ // A refusal releases the key: the person fixes the cause — frees a slot,
241
+ // picks another name — and presses the same button again.
242
+ await (claim == null ? void 0 : claim.release());
243
+ return result;
244
+ } catch (error) {
245
+ await (claim == null ? void 0 : claim.release());
246
+ throw error;
247
+ }
248
+ }
249
+ async function copy(firestore, kind, recipe, options) {
250
+ var _options_org, _data;
251
+ const { hostId, sourceId, uid } = options;
252
+ const noun = DUPLICABLE_RESOURCE_NOUNS[kind];
253
+ const hostRef = firestore.collection('hosts').doc(hostId);
254
+ const collectionRef = hostRef.collection(recipe.collection);
255
+ const sourceRef = collectionRef.doc(sourceId);
256
+ const org = (_options_org = options.org) != null ? _options_org : (_data = (await firestore.collection('orgs').doc(options.orgId).get()).data()) != null ? _data : null;
257
+ if (recipe.entitlement && !checkEntitlement(org, recipe.entitlement)) {
258
+ return {
259
+ ok: false,
260
+ status: 403,
261
+ error: 'This feature is not included in your plan — see Billing'
262
+ };
263
+ }
264
+ const id = createResourceUid();
265
+ const versionId = recipe.versionParentField ? createResourceUid() : null;
266
+ return firestore.runTransaction(async (tx)=>{
267
+ var _data_recipe_nameField, _options_name, _recipe_stamps;
268
+ // ALL READS BEFORE ANY WRITE, which Firestore requires. The host is read
269
+ // inside the transaction rather than passed in because its routing map
270
+ // is an input to the screen count and is ordinary client-writable.
271
+ const siblingFields = [
272
+ recipe.nameField,
273
+ 'slug',
274
+ 'kind',
275
+ 'deletedAt',
276
+ 'source.type'
277
+ ];
278
+ const [hostSnapshot, source, siblingsSnapshot] = await Promise.all([
279
+ tx.get(hostRef),
280
+ tx.get(sourceRef),
281
+ tx.get(collectionRef.select(...siblingFields))
282
+ ]);
283
+ if (!hostSnapshot.exists) return {
284
+ ok: false,
285
+ status: 404,
286
+ error: 'Unknown site'
287
+ };
288
+ if (!source.exists || source.get('deletedAt') != null) {
289
+ return {
290
+ ok: false,
291
+ status: 404,
292
+ error: `Unknown ${noun}`
293
+ };
294
+ }
295
+ const data = asRecord(source.data());
296
+ // The two screen kinds share a collection and are told apart by `kind`:
297
+ // an email design copied as a page would land on the Screens list, and
298
+ // the other way round would put a page on the Emails page.
299
+ //
300
+ // Of the screens that are not pages, only a collection's entry template
301
+ // may be copied as a screen (AGL-3102), and the copy stays a template:
302
+ // `kind` rides across with the recipe's fields, so it composes nothing
303
+ // until a collection points at it — which is how a second collection
304
+ // starts from the first one's design. An error screen is refused:
305
+ // `kind: 'error'` is the slot assignment's to stamp, because that write
306
+ // is what bounds how many a site holds, and a copy would stamp one
307
+ // outside it.
308
+ const sourceKind = data['kind'];
309
+ const nonPageScreen = recipe.collection === 'screens' && !screenClaimsToBeAPage({
310
+ kind: sourceKind
311
+ });
312
+ if (recipe.collection === 'screens') {
313
+ if (kind === 'emailDesign' && sourceKind !== SCREEN_KIND_EMAIL) {
314
+ return {
315
+ ok: false,
316
+ status: 400,
317
+ error: 'That screen is not an email design'
318
+ };
319
+ }
320
+ if (kind === 'screen' && nonPageScreen && sourceKind !== SCREEN_KIND_TEMPLATE) {
321
+ return {
322
+ ok: false,
323
+ status: 400,
324
+ error: 'Only a page or a collection entry template can be duplicated as a screen'
325
+ };
326
+ }
327
+ }
328
+ const siblings = siblingsSnapshot.docs.map((row)=>{
329
+ var _row_get, _row_get1;
330
+ return {
331
+ id: row.id,
332
+ name: String((_row_get = row.get(recipe.nameField)) != null ? _row_get : ''),
333
+ slug: String((_row_get1 = row.get('slug')) != null ? _row_get1 : ''),
334
+ kind: row.get('kind'),
335
+ deletedAt: row.get('deletedAt'),
336
+ sourceType: row.get('source.type')
337
+ };
338
+ });
339
+ const live = siblings.filter((row)=>row.deletedAt == null);
340
+ // THE BAND, met inside the transaction (AGL-2231) with the create route's
341
+ // own arithmetic: screens count what the routing map makes billable,
342
+ // templates exclude the platform's starters, everything else counts its
343
+ // live documents. A screen copy that is not a page — an email design or
344
+ // an entry template — meets the flat platform ceiling on non-page screens
345
+ // instead, the one an email design's create meets and a demoted template
346
+ // fills, and never the page band: it spends none of it.
347
+ const screenRows = siblings.map((row)=>({
348
+ id: row.id,
349
+ kind: row.kind,
350
+ deletedAt: row.deletedAt
351
+ }));
352
+ const routingMap = hostSnapshot.get('screens');
353
+ if (nonPageScreen) {
354
+ if (nonPageScreenIds(screenRows, routingMap).size >= NON_PAGE_SCREEN_MAX_PER_HOST) {
355
+ return {
356
+ ok: false,
357
+ status: 403,
358
+ error: 'This site is at its limit of ' + `${NON_PAGE_SCREEN_MAX_PER_HOST} email and template screens — ` + 'delete some to make room'
359
+ };
360
+ }
361
+ } else if (recipe.quotaKey) {
362
+ const used = kind === 'screen' ? billableScreenIds(screenRows, routingMap).size : kind === 'template' ? live.filter((row)=>row.sourceType !== 'starter').length : live.length;
363
+ const quota = checkQuota(org, recipe.quotaKey, used);
364
+ if (!quota.allowed) {
365
+ return {
366
+ ok: false,
367
+ status: 403,
368
+ error: `Your plan includes ${quota.limit} ${noun}s — ` + 'upgrade in Billing for more'
369
+ };
370
+ }
371
+ }
372
+ // THE NAME AND THE SLUG, unique among the live siblings. A deleted
373
+ // sibling's name is free: a person who deleted "Home" and copies
374
+ // "About" as "Home" is not confused by a tombstone.
375
+ const sourceName = String((_data_recipe_nameField = data[recipe.nameField]) != null ? _data_recipe_nameField : '').trim();
376
+ const requested = String((_options_name = options.name) != null ? _options_name : '').trim() || duplicateDisplayName(sourceName);
377
+ const name = uniqueDuplicateName(requested, live.map((row)=>row.name));
378
+ const slug = recipe.slug ? uniqueDuplicateSlug(data['slug'], live.map((row)=>row.slug)) : undefined;
379
+ // THE VERSION: the most recently saved one, else the one the document
380
+ // points at. Read inside the transaction so the copy is of what was
381
+ // saved when the count was taken.
382
+ let versionData = null;
383
+ let sourceVersionNumber = null;
384
+ if (recipe.versionParentField) {
385
+ var _newest_docs_, _data_versionId;
386
+ const versionsRef = sourceRef.collection('versions');
387
+ const [newest, all] = await Promise.all([
388
+ tx.get(versionsRef.orderBy('updatedAt', 'desc').limit(1)),
389
+ tx.get(versionsRef.select())
390
+ ]);
391
+ let found = (_newest_docs_ = newest.docs[0]) != null ? _newest_docs_ : null;
392
+ const pointer = String((_data_versionId = data['versionId']) != null ? _data_versionId : '');
393
+ if (!found && pointer) {
394
+ const pointed = await tx.get(versionsRef.doc(pointer));
395
+ if (pointed.exists) found = pointed;
396
+ }
397
+ if (found) {
398
+ versionData = asRecord(found.data());
399
+ sourceVersionNumber = all.size;
400
+ }
401
+ }
402
+ // THE DOCUMENT: the recipe's fields, the name, the slug, the stamps.
403
+ const doc = {};
404
+ for (const field of recipe.fields){
405
+ if (data[field] !== undefined) doc[field] = data[field];
406
+ }
407
+ doc[recipe.nameField] = name;
408
+ if (recipe.slug) {
409
+ if (slug) doc['slug'] = slug;
410
+ else delete doc['slug'];
411
+ }
412
+ /*
413
+ * THE FORM'S BINDING, moved onto the copy (AGL-3024).
414
+ *
415
+ * A form's design names its own form in a prop, and that name is what
416
+ * `/api/forms/submit` files a submission under. Copied verbatim it still
417
+ * names the SOURCE, so the copy renders, collects, and files everything
418
+ * it collects under the form it was copied from — while its own list
419
+ * stays empty and nothing anywhere reports an error. `checkFormContract`
420
+ * is what the console's form page banners it with; `formDesignReboundTo`
421
+ * is the write side of the same fact.
422
+ *
423
+ * This is the one place a copied tree is not carried across untouched,
424
+ * and the exception is narrow on purpose: no other kind here embeds its
425
+ * own id in its design. `formDesignReboundTo` answers `null` when there
426
+ * is nothing to move, so every other kind — and a form whose design is
427
+ * already correct — pays nothing for this.
428
+ */ const rebound = (raw)=>{
429
+ var _formDesignReboundTo;
430
+ if (kind !== 'form') return raw;
431
+ return (_formDesignReboundTo = formDesignReboundTo(decodeStoredNodes(raw), {
432
+ formId: id,
433
+ formName: name
434
+ })) != null ? _formDesignReboundTo : raw;
435
+ };
436
+ // The stored tree is msgpack at rest; `encodeStoredNodes` passes encoded
437
+ // bytes through and packs a plain map, so a legacy plain source lands
438
+ // compressed like every create does — and so does a rebound one, which
439
+ // comes back decoded.
440
+ const packed = encodeStoredNodes(rebound(doc['nodes']));
441
+ if (packed) doc['nodes'] = Buffer.from(packed);
442
+ tx.create(collectionRef.doc(id), _extends({}, doc, (_recipe_stamps = recipe.stamps) != null ? _recipe_stamps : {}, recipe.collection === 'screens' ? {
443
+ nameLower: nameSearchKey(name)
444
+ } : {}, versionData && versionId ? {
445
+ versionId
446
+ } : {}, {
447
+ createdAt: Timestamp.now(),
448
+ updatedAt: Timestamp.now(),
449
+ createdBy: uid
450
+ }));
451
+ if (versionData && versionId && recipe.versionParentField) {
452
+ const versionNodes = encodeStoredNodes(rebound(versionData['nodes']));
453
+ tx.create(collectionRef.doc(id).collection('versions').doc(versionId), _extends({}, versionData, versionNodes ? {
454
+ nodes: Buffer.from(versionNodes)
455
+ } : {}, {
456
+ [recipe.versionParentField]: id,
457
+ hostId,
458
+ displayName: duplicateVersionNote(sourceName, sourceVersionNumber),
459
+ createdAt: Timestamp.now(),
460
+ updatedAt: Timestamp.now(),
461
+ createdBy: uid
462
+ }));
463
+ }
464
+ return {
465
+ ok: true,
466
+ id,
467
+ versionId: versionData && versionId ? versionId : null,
468
+ name,
469
+ sourceName
470
+ };
471
+ });
472
+ }
473
+
474
+ //# sourceMappingURL=duplicate-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/tenant/data/admin/src/lib/server/duplicate-resource.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 * Duplicating a site resource whole, as a draft (AGL-2936).\n *\n * One module for every kind that lives under a site — screens and email\n * designs, reusable components, layouts, templates, forms and workflows —\n * so the console route, the AI runtime's `duplicate_resource` tool and any\n * later door make the same copy: the same fields, the same uniqueness\n * rules, the same band arithmetic, the same activity rows. A caller that\n * has verified who is asking and that they may write the site hands over\n * the ids and gets back the copy's id, or a refusal it can answer with.\n *\n * WHAT MAKES THE COPY A DRAFT is different per kind, and each is the\n * omission of exactly one thing the create paths would otherwise do:\n *\n * - a screen is reachable only through the host's routing map, so the\n * copy gets no entry there — it has a slug of its own (`-copy`) but no\n * address until somebody publishes it;\n * - a collection's entry template renders only for the collection that\n * points at it, and nothing points at the copy;\n * - a layout, component or form is served only where a page places it,\n * and nothing places the copy;\n * - a workflow runs only when its trigger fires, and the copy's trigger\n * is cleared;\n * - a template is inert until it is used.\n *\n * COUNTED LIKE A CREATE. The copy is one more document in a collection the\n * plan bands, so it meets the same counter the create route meets — for a\n * screen that is not a page, the flat platform ceiling rather than a band —\n * and meets it INSIDE the transaction that writes the copy (AGL-2231): a count\n * taken before the write is a count N concurrent copies all pass. The\n * siblings are read once and answer three questions — the count, the name\n * the copy may take, and the slug — because three reads of one collection\n * is the reason a route and its readout come to disagree.\n *\n * THE VERSION TRAVELS WITH THE DOCUMENT. A besigner resource is opened by\n * its version, so the copy of a screen with no version is a screen nobody\n * can open. The source's most recently saved version is copied into the\n * copy's own `versions` as its first — no `versioning` entitlement is\n * owed for a first version — with its stored node bytes carried across\n * untouched: they are msgpack at rest, and re-encoding them is the\n * double-encode `encodeStoredNodes` exists to avoid.\n *\n * THE ONE TREE THAT IS REWRITTEN is a form's (AGL-3024). A form's design\n * names its own form inside itself, so carrying those bytes across hands the\n * copy a design that files every submission under the SOURCE — silently,\n * because the copy still renders and the row still lands. That binding is\n * moved onto the copy below. No other kind embeds its own id in its design,\n * so no other kind is decoded.\n */\n\nimport {\n billableScreenIds,\n checkEntitlement,\n checkQuota,\n claimAttempt,\n createResourceUid,\n decodeStoredNodes,\n encodeStoredNodes,\n nameSearchKey,\n NON_PAGE_SCREEN_MAX_PER_HOST,\n nonPageScreenIds,\n SCREEN_KIND_EMAIL,\n SCREEN_KIND_TEMPLATE,\n screenClaimsToBeAPage,\n type BillableScreenSource,\n type OrgEntitlements,\n type OrgFeatureFlags,\n} from '@aglyn/aglyn/server'\nimport {\n DUPLICABLE_RESOURCE_NOUNS,\n DUPLICATE_BUSY_MESSAGE,\n duplicateDisplayName,\n duplicateVersionNote,\n uniqueDuplicateName,\n uniqueDuplicateSlug,\n type DuplicableHostResourceKind,\n} from '@aglyn/aglyn/app-utils/duplicate-resource'\nimport { formDesignReboundTo } from '@aglyn/aglyn/app-utils/forms'\nimport { Timestamp } from 'firebase-admin/firestore'\nimport { logResourceDuplicated } from './duplicate-activity'\nimport firebaseAdmin from './firebase-admin'\n\n/** How the copy of each kind is made. */\ninterface KindRecipe {\n collection: string\n /** The field the name lives in — `name` on a workflow, `displayName` elsewhere. */\n nameField: 'displayName' | 'name'\n /** The source fields carried onto the copy; everything else stays behind. */\n fields: readonly string[]\n /** The back-pointer a copied version carries, when the kind versions at all. */\n versionParentField?: 'screenId' | 'layoutId' | 'componentId' | 'formId'\n /** The plan counter the copy is charged to. */\n quotaKey?: keyof OrgEntitlements & string\n /** The feature the plan must include for the kind to exist at all. */\n entitlement?: keyof OrgFeatureFlags\n /** Whether a `slug` on the source becomes a unique `-copy` slug. */\n slug?: boolean\n /** What the copy carries beyond the source's fields. */\n stamps?: Record<string, unknown>\n}\n\n/**\n * Per kind, the same fields the create route's allow-list admits, less the\n * ones a copy must not inherit: a screen's `versionId` (the copy mints its\n * own), a template's `source` (stamped `authored` below — a copy of a\n * marketplace template is the customer's own), a workflow's `trigger`\n * (cleared, so the copy runs nothing until armed), and anything the server\n * stamps on every create.\n */\nconst RECIPES: Record<DuplicableHostResourceKind, KindRecipe> = {\n screen: {\n collection: 'screens',\n nameField: 'displayName',\n fields: [\n 'description',\n 'seo',\n 'kind',\n 'visibility',\n 'locale',\n 'protection',\n // The shared-layout binding. A version inherits it from its screen, so\n // a copy without it renders with no header or footer (AGL-3120).\n 'layoutId',\n ],\n versionParentField: 'screenId',\n quotaKey: 'screensPerHost',\n slug: true,\n },\n // No `quotaKey`: an email design is not a page, so it meets the flat\n // platform ceiling on non-page screens below rather than the page band.\n emailDesign: {\n collection: 'screens',\n nameField: 'displayName',\n fields: ['description', 'kind'],\n versionParentField: 'screenId',\n },\n component: {\n collection: 'components',\n nameField: 'displayName',\n fields: ['description', 'icon', 'rootId', 'nodes', 'props'],\n versionParentField: 'componentId',\n entitlement: 'reusableComponents',\n },\n layout: {\n collection: 'layouts',\n nameField: 'displayName',\n fields: ['description'],\n versionParentField: 'layoutId',\n quotaKey: 'sharedLayoutsPerHost',\n },\n template: {\n collection: 'templates',\n nameField: 'displayName',\n fields: [\n 'kind',\n 'description',\n 'category',\n 'placeholders',\n 'nodes',\n 'rootId',\n 'props',\n 'slug',\n 'seo',\n 'theme',\n ],\n quotaKey: 'templatesPerHost',\n stamps: { source: { type: 'authored' } },\n },\n form: {\n collection: 'forms',\n nameField: 'displayName',\n fields: [\n 'fields',\n 'consentFieldName',\n 'routing',\n 'legacyMatch',\n 'rootId',\n 'nodes',\n ],\n versionParentField: 'formId',\n quotaKey: 'formsPerHost',\n entitlement: 'reusableComponents',\n slug: true,\n },\n workflow: {\n collection: 'workflows',\n nameField: 'name',\n fields: ['steps', 'returnValue'],\n quotaKey: 'workflowsPerHost',\n entitlement: 'workflows',\n stamps: { trigger: null },\n },\n}\n\nexport interface DuplicateResourceOptions {\n orgId: string\n hostId: string\n sourceId: string\n /** The name the copy takes; blank means `Copy of <source>`. */\n name?: string | null\n /** The verified person making the copy. */\n uid: string\n email?: string | null\n /**\n * The owning org's document, when the caller already holds it; read\n * here otherwise. The bands are resolved from it.\n */\n org?: Record<string, unknown> | null\n /**\n * A client-minted key for this attempt, so a double click makes one copy\n * and a retry of a finished attempt answers what the first did. A caller\n * with no client behind it — the AI runtime — sends none and is not\n * claimed.\n */\n attemptKey?: string | null\n}\n\nexport type DuplicateResourceResult =\n | {\n ok: true\n id: string\n /** The copy's first version, for the kinds that version. */\n versionId: string | null\n name: string\n }\n | { ok: false; status: number; error: string }\n\n/** What a sibling contributes to the three answers the siblings give. */\ninterface SiblingRow {\n id: string\n name: string\n slug: string\n kind: unknown\n deletedAt: unknown\n sourceType: unknown\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> =>\n value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n\n/**\n * Makes the copy. The caller has authenticated `uid` and verified that they\n * may write content on `hostId`; this decides everything after that.\n */\nexport async function duplicateResource(\n kind: DuplicableHostResourceKind,\n options: DuplicateResourceOptions,\n): Promise<DuplicateResourceResult> {\n const recipe = RECIPES[kind]\n const noun = DUPLICABLE_RESOURCE_NOUNS[kind]\n const sourceId = String(options.sourceId ?? '').trim().slice(0, 64)\n if (!sourceId) return { ok: false, status: 400, error: `Missing the ${noun} to copy` }\n const firestore = firebaseAdmin.app().firestore()\n\n const attemptKey = String(options.attemptKey ?? '').trim().slice(0, 200)\n const claimed = attemptKey\n ? await claimAttempt(firestore as never, {\n kind: `duplicate-${kind}`,\n scopeId: `${options.hostId}:${sourceId}`,\n orgId: options.orgId,\n key: attemptKey,\n busyMessage: DUPLICATE_BUSY_MESSAGE,\n })\n : null\n if (claimed && 'replay' in claimed) {\n return claimed.replay.body as DuplicateResourceResult\n }\n const claim = claimed && 'claim' in claimed ? claimed.claim : null\n\n try {\n const result = await copy(firestore, kind, recipe, { ...options, sourceId })\n if (result.ok) {\n await logResourceDuplicated(\n kind,\n { uid: options.uid, email: options.email ?? null },\n {\n orgId: options.orgId,\n hostId: options.hostId,\n source: { id: sourceId, name: result.sourceName },\n target: { id: result.id, name: result.name, versionId: result.versionId },\n },\n )\n const answer: DuplicateResourceResult = {\n ok: true,\n id: result.id,\n versionId: result.versionId,\n name: result.name,\n }\n await claim?.record(200, answer)\n return answer\n }\n // A refusal releases the key: the person fixes the cause — frees a slot,\n // picks another name — and presses the same button again.\n await claim?.release()\n return result\n } catch (error) {\n await claim?.release()\n throw error\n }\n}\n\ntype CopyOutcome =\n | { ok: true; id: string; versionId: string | null; name: string; sourceName: string }\n | { ok: false; status: number; error: string }\n\nasync function copy(\n firestore: FirebaseFirestore.Firestore,\n kind: DuplicableHostResourceKind,\n recipe: KindRecipe,\n options: DuplicateResourceOptions & { sourceId: string },\n): Promise<CopyOutcome> {\n const { hostId, sourceId, uid } = options\n const noun = DUPLICABLE_RESOURCE_NOUNS[kind]\n const hostRef = firestore.collection('hosts').doc(hostId)\n const collectionRef = hostRef.collection(recipe.collection)\n const sourceRef = collectionRef.doc(sourceId)\n const org =\n options.org ??\n (((await firestore.collection('orgs').doc(options.orgId).get()).data() ??\n null) as Record<string, unknown> | null)\n\n if (recipe.entitlement && !checkEntitlement(org as never, recipe.entitlement)) {\n return {\n ok: false,\n status: 403,\n error: 'This feature is not included in your plan — see Billing',\n }\n }\n\n const id = createResourceUid()\n const versionId = recipe.versionParentField ? createResourceUid() : null\n\n return firestore.runTransaction(async (tx): Promise<CopyOutcome> => {\n // ALL READS BEFORE ANY WRITE, which Firestore requires. The host is read\n // inside the transaction rather than passed in because its routing map\n // is an input to the screen count and is ordinary client-writable.\n const siblingFields = [\n recipe.nameField,\n 'slug',\n 'kind',\n 'deletedAt',\n 'source.type',\n ]\n const [hostSnapshot, source, siblingsSnapshot] = await Promise.all([\n tx.get(hostRef),\n tx.get(sourceRef),\n tx.get(collectionRef.select(...siblingFields)),\n ])\n if (!hostSnapshot.exists) return { ok: false, status: 404, error: 'Unknown site' }\n if (!source.exists || source.get('deletedAt') != null) {\n return { ok: false, status: 404, error: `Unknown ${noun}` }\n }\n const data = asRecord(source.data())\n\n // The two screen kinds share a collection and are told apart by `kind`:\n // an email design copied as a page would land on the Screens list, and\n // the other way round would put a page on the Emails page.\n //\n // Of the screens that are not pages, only a collection's entry template\n // may be copied as a screen (AGL-3102), and the copy stays a template:\n // `kind` rides across with the recipe's fields, so it composes nothing\n // until a collection points at it — which is how a second collection\n // starts from the first one's design. An error screen is refused:\n // `kind: 'error'` is the slot assignment's to stamp, because that write\n // is what bounds how many a site holds, and a copy would stamp one\n // outside it.\n const sourceKind = data['kind']\n const nonPageScreen =\n recipe.collection === 'screens' &&\n !screenClaimsToBeAPage({ kind: sourceKind as string })\n if (recipe.collection === 'screens') {\n if (kind === 'emailDesign' && sourceKind !== SCREEN_KIND_EMAIL) {\n return { ok: false, status: 400, error: 'That screen is not an email design' }\n }\n if (kind === 'screen' && nonPageScreen && sourceKind !== SCREEN_KIND_TEMPLATE) {\n return {\n ok: false,\n status: 400,\n error: 'Only a page or a collection entry template can be duplicated as a screen',\n }\n }\n }\n\n const siblings: SiblingRow[] = siblingsSnapshot.docs.map((row) => ({\n id: row.id,\n name: String(row.get(recipe.nameField) ?? ''),\n slug: String(row.get('slug') ?? ''),\n kind: row.get('kind'),\n deletedAt: row.get('deletedAt'),\n sourceType: row.get('source.type'),\n }))\n const live = siblings.filter((row) => row.deletedAt == null)\n\n // THE BAND, met inside the transaction (AGL-2231) with the create route's\n // own arithmetic: screens count what the routing map makes billable,\n // templates exclude the platform's starters, everything else counts its\n // live documents. A screen copy that is not a page — an email design or\n // an entry template — meets the flat platform ceiling on non-page screens\n // instead, the one an email design's create meets and a demoted template\n // fills, and never the page band: it spends none of it.\n const screenRows: BillableScreenSource[] = siblings.map((row) => ({\n id: row.id,\n kind: row.kind,\n deletedAt: row.deletedAt,\n }))\n const routingMap = hostSnapshot.get('screens') as never\n if (nonPageScreen) {\n if (nonPageScreenIds(screenRows, routingMap).size >= NON_PAGE_SCREEN_MAX_PER_HOST) {\n return {\n ok: false,\n status: 403,\n error:\n 'This site is at its limit of ' +\n `${NON_PAGE_SCREEN_MAX_PER_HOST} email and template screens — ` +\n 'delete some to make room',\n }\n }\n } else if (recipe.quotaKey) {\n const used =\n kind === 'screen'\n ? billableScreenIds(screenRows, routingMap).size\n : kind === 'template'\n ? live.filter((row) => row.sourceType !== 'starter').length\n : live.length\n const quota = checkQuota(org as never, recipe.quotaKey as never, used)\n if (!quota.allowed) {\n return {\n ok: false,\n status: 403,\n error:\n `Your plan includes ${quota.limit} ${noun}s — ` +\n 'upgrade in Billing for more',\n }\n }\n }\n\n // THE NAME AND THE SLUG, unique among the live siblings. A deleted\n // sibling's name is free: a person who deleted \"Home\" and copies\n // \"About\" as \"Home\" is not confused by a tombstone.\n const sourceName = String(data[recipe.nameField] ?? '').trim()\n const requested = String(options.name ?? '').trim() || duplicateDisplayName(sourceName)\n const name = uniqueDuplicateName(\n requested,\n live.map((row) => row.name),\n )\n const slug = recipe.slug\n ? uniqueDuplicateSlug(\n data['slug'] as string | undefined,\n live.map((row) => row.slug),\n )\n : undefined\n\n // THE VERSION: the most recently saved one, else the one the document\n // points at. Read inside the transaction so the copy is of what was\n // saved when the count was taken.\n let versionData: Record<string, unknown> | null = null\n let sourceVersionNumber: number | null = null\n if (recipe.versionParentField) {\n const versionsRef = sourceRef.collection('versions')\n const [newest, all] = await Promise.all([\n tx.get(versionsRef.orderBy('updatedAt', 'desc').limit(1)),\n tx.get(versionsRef.select()),\n ])\n let found: FirebaseFirestore.DocumentSnapshot | null = newest.docs[0] ?? null\n const pointer = String(data['versionId'] ?? '')\n if (!found && pointer) {\n const pointed = await tx.get(versionsRef.doc(pointer))\n if (pointed.exists) found = pointed\n }\n if (found) {\n versionData = asRecord(found.data())\n sourceVersionNumber = all.size\n }\n }\n\n // THE DOCUMENT: the recipe's fields, the name, the slug, the stamps.\n const doc: Record<string, unknown> = {}\n for (const field of recipe.fields) {\n if (data[field] !== undefined) doc[field] = data[field]\n }\n doc[recipe.nameField] = name\n if (recipe.slug) {\n if (slug) doc['slug'] = slug\n else delete doc['slug']\n }\n /*\n * THE FORM'S BINDING, moved onto the copy (AGL-3024).\n *\n * A form's design names its own form in a prop, and that name is what\n * `/api/forms/submit` files a submission under. Copied verbatim it still\n * names the SOURCE, so the copy renders, collects, and files everything\n * it collects under the form it was copied from — while its own list\n * stays empty and nothing anywhere reports an error. `checkFormContract`\n * is what the console's form page banners it with; `formDesignReboundTo`\n * is the write side of the same fact.\n *\n * This is the one place a copied tree is not carried across untouched,\n * and the exception is narrow on purpose: no other kind here embeds its\n * own id in its design. `formDesignReboundTo` answers `null` when there\n * is nothing to move, so every other kind — and a form whose design is\n * already correct — pays nothing for this.\n */\n const rebound = (raw: unknown): unknown => {\n if (kind !== 'form') return raw\n return (\n formDesignReboundTo(decodeStoredNodes(raw), {\n formId: id,\n formName: name,\n }) ?? raw\n )\n }\n // The stored tree is msgpack at rest; `encodeStoredNodes` passes encoded\n // bytes through and packs a plain map, so a legacy plain source lands\n // compressed like every create does — and so does a rebound one, which\n // comes back decoded.\n const packed = encodeStoredNodes(rebound(doc['nodes']))\n if (packed) doc['nodes'] = Buffer.from(packed)\n tx.create(collectionRef.doc(id), {\n ...doc,\n ...(recipe.stamps ?? {}),\n ...(recipe.collection === 'screens' ? { nameLower: nameSearchKey(name) } : {}),\n ...(versionData && versionId ? { versionId } : {}),\n createdAt: Timestamp.now(),\n updatedAt: Timestamp.now(),\n createdBy: uid,\n })\n if (versionData && versionId && recipe.versionParentField) {\n const versionNodes = encodeStoredNodes(rebound(versionData['nodes']))\n tx.create(collectionRef.doc(id).collection('versions').doc(versionId), {\n ...versionData,\n ...(versionNodes ? { nodes: Buffer.from(versionNodes) } : {}),\n [recipe.versionParentField]: id,\n hostId,\n displayName: duplicateVersionNote(sourceName, sourceVersionNumber),\n createdAt: Timestamp.now(),\n updatedAt: Timestamp.now(),\n createdBy: uid,\n })\n }\n return {\n ok: true,\n id,\n versionId: versionData && versionId ? versionId : null,\n name,\n sourceName,\n }\n })\n}\n"],"names":["billableScreenIds","checkEntitlement","checkQuota","claimAttempt","createResourceUid","decodeStoredNodes","encodeStoredNodes","nameSearchKey","NON_PAGE_SCREEN_MAX_PER_HOST","nonPageScreenIds","SCREEN_KIND_EMAIL","SCREEN_KIND_TEMPLATE","screenClaimsToBeAPage","DUPLICABLE_RESOURCE_NOUNS","DUPLICATE_BUSY_MESSAGE","duplicateDisplayName","duplicateVersionNote","uniqueDuplicateName","uniqueDuplicateSlug","formDesignReboundTo","Timestamp","logResourceDuplicated","firebaseAdmin","RECIPES","screen","collection","nameField","fields","versionParentField","quotaKey","slug","emailDesign","component","entitlement","layout","template","stamps","source","type","form","workflow","trigger","asRecord","value","Array","isArray","duplicateResource","kind","options","recipe","noun","sourceId","String","trim","slice","ok","status","error","firestore","app","attemptKey","claimed","scopeId","hostId","orgId","key","busyMessage","replay","body","claim","result","copy","uid","email","id","name","sourceName","target","versionId","answer","record","release","hostRef","doc","collectionRef","sourceRef","org","get","data","runTransaction","tx","siblingFields","hostSnapshot","siblingsSnapshot","Promise","all","select","exists","sourceKind","nonPageScreen","siblings","docs","map","row","deletedAt","sourceType","live","filter","screenRows","routingMap","size","used","length","quota","allowed","limit","requested","undefined","versionData","sourceVersionNumber","newest","versionsRef","orderBy","found","pointer","pointed","field","rebound","raw","formId","formName","packed","Buffer","from","create","nameLower","createdAt","now","updatedAt","createdBy","versionNodes","nodes","displayName"],"mappings":"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"}