@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.
- package/LICENSE +201 -0
- package/README.md +7 -0
- package/jest.integration.config.d.ts +39 -0
- package/jest.integration.setup.d.ts +17 -0
- package/package.json +51 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/render-cache.d.ts +184 -0
- package/src/lib/render-cache.js +198 -0
- package/src/lib/render-cache.js.map +1 -0
- package/src/lib/server/account-addresses.d.ts +160 -0
- package/src/lib/server/account-addresses.js +311 -0
- package/src/lib/server/account-addresses.js.map +1 -0
- package/src/lib/server/account-emails.d.ts +219 -0
- package/src/lib/server/account-emails.js +640 -0
- package/src/lib/server/account-emails.js.map +1 -0
- package/src/lib/server/admin-audit.d.ts +180 -0
- package/src/lib/server/admin-audit.js +233 -0
- package/src/lib/server/admin-audit.js.map +1 -0
- package/src/lib/server/analytics-retention.d.ts +63 -0
- package/src/lib/server/analytics-retention.js +66 -0
- package/src/lib/server/analytics-retention.js.map +1 -0
- package/src/lib/server/api-http.d.ts +159 -0
- package/src/lib/server/api-http.js +230 -0
- package/src/lib/server/api-http.js.map +1 -0
- package/src/lib/server/api-keys.d.ts +117 -0
- package/src/lib/server/api-keys.js +298 -0
- package/src/lib/server/api-keys.js.map +1 -0
- package/src/lib/server/auth-handoff.d.ts +165 -0
- package/src/lib/server/auth-handoff.js +482 -0
- package/src/lib/server/auth-handoff.js.map +1 -0
- package/src/lib/server/auth-pools.d.ts +246 -0
- package/src/lib/server/auth-pools.js +551 -0
- package/src/lib/server/auth-pools.js.map +1 -0
- package/src/lib/server/billing-addons.d.ts +171 -0
- package/src/lib/server/billing-addons.js +277 -0
- package/src/lib/server/billing-addons.js.map +1 -0
- package/src/lib/server/campaign-attribution-store.d.ts +55 -0
- package/src/lib/server/campaign-attribution-store.js +95 -0
- package/src/lib/server/campaign-attribution-store.js.map +1 -0
- package/src/lib/server/campaign-conversion-attribution.d.ts +205 -0
- package/src/lib/server/campaign-conversion-attribution.js +279 -0
- package/src/lib/server/campaign-conversion-attribution.js.map +1 -0
- package/src/lib/server/client-error-report.d.ts +301 -0
- package/src/lib/server/client-error-report.js +755 -0
- package/src/lib/server/client-error-report.js.map +1 -0
- package/src/lib/server/connect-account-status.d.ts +74 -0
- package/src/lib/server/connect-account-status.js +94 -0
- package/src/lib/server/connect-account-status.js.map +1 -0
- package/src/lib/server/connect-payout-failure.d.ts +103 -0
- package/src/lib/server/connect-payout-failure.js +127 -0
- package/src/lib/server/connect-payout-failure.js.map +1 -0
- package/src/lib/server/console-api-rate-limit.d.ts +81 -0
- package/src/lib/server/console-api-rate-limit.js +111 -0
- package/src/lib/server/console-api-rate-limit.js.map +1 -0
- package/src/lib/server/console-domains.d.ts +326 -0
- package/src/lib/server/console-domains.js +779 -0
- package/src/lib/server/console-domains.js.map +1 -0
- package/src/lib/server/consume-once.d.ts +91 -0
- package/src/lib/server/consume-once.js +96 -0
- package/src/lib/server/consume-once.js.map +1 -0
- package/src/lib/server/contact-company-link.d.ts +85 -0
- package/src/lib/server/contact-company-link.js +105 -0
- package/src/lib/server/contact-company-link.js.map +1 -0
- package/src/lib/server/contact-email-engagement.d.ts +32 -0
- package/src/lib/server/contact-email-engagement.js +145 -0
- package/src/lib/server/contact-email-engagement.js.map +1 -0
- package/src/lib/server/contact-email-index.d.ts +56 -0
- package/src/lib/server/contact-email-index.js +158 -0
- package/src/lib/server/contact-email-index.js.map +1 -0
- package/src/lib/server/contact-lifecycle-floor.d.ts +89 -0
- package/src/lib/server/contact-lifecycle-floor.js +88 -0
- package/src/lib/server/contact-lifecycle-floor.js.map +1 -0
- package/src/lib/server/contact-merge.d.ts +55 -0
- package/src/lib/server/contact-merge.js +279 -0
- package/src/lib/server/contact-merge.js.map +1 -0
- package/src/lib/server/contact-suppression.d.ts +153 -0
- package/src/lib/server/contact-suppression.js +259 -0
- package/src/lib/server/contact-suppression.js.map +1 -0
- package/src/lib/server/crm-booking-activity.d.ts +86 -0
- package/src/lib/server/crm-booking-activity.js +251 -0
- package/src/lib/server/crm-booking-activity.js.map +1 -0
- package/src/lib/server/crm-email-activity.d.ts +112 -0
- package/src/lib/server/crm-email-activity.js +143 -0
- package/src/lib/server/crm-email-activity.js.map +1 -0
- package/src/lib/server/crm-inbound-email.d.ts +145 -0
- package/src/lib/server/crm-inbound-email.js +287 -0
- package/src/lib/server/crm-inbound-email.js.map +1 -0
- package/src/lib/server/crm-next-activity.d.ts +74 -0
- package/src/lib/server/crm-next-activity.js +194 -0
- package/src/lib/server/crm-next-activity.js.map +1 -0
- package/src/lib/server/crm-records.d.ts +144 -0
- package/src/lib/server/crm-records.js +218 -0
- package/src/lib/server/crm-records.js.map +1 -0
- package/src/lib/server/csp-aggregate.d.ts +62 -0
- package/src/lib/server/csp-aggregate.js +276 -0
- package/src/lib/server/csp-aggregate.js.map +1 -0
- package/src/lib/server/data-storage-gate.d.ts +66 -0
- package/src/lib/server/data-storage-gate.js +48 -0
- package/src/lib/server/data-storage-gate.js.map +1 -0
- package/src/lib/server/dataset-live-pages.d.ts +179 -0
- package/src/lib/server/dataset-live-pages.js +421 -0
- package/src/lib/server/dataset-live-pages.js.map +1 -0
- package/src/lib/server/dns-probe.d.ts +53 -0
- package/src/lib/server/dns-probe.js +184 -0
- package/src/lib/server/dns-probe.js.map +1 -0
- package/src/lib/server/document-id.d.ts +29 -0
- package/src/lib/server/document-id.js +100 -0
- package/src/lib/server/document-id.js.map +1 -0
- package/src/lib/server/domain-provider-vercel.d.ts +33 -0
- package/src/lib/server/domain-provider-vercel.js +298 -0
- package/src/lib/server/domain-provider-vercel.js.map +1 -0
- package/src/lib/server/domain-provider-webhook.d.ts +73 -0
- package/src/lib/server/domain-provider-webhook.js +223 -0
- package/src/lib/server/domain-provider-webhook.js.map +1 -0
- package/src/lib/server/domain-provider-wildcard.d.ts +54 -0
- package/src/lib/server/domain-provider-wildcard.js +163 -0
- package/src/lib/server/domain-provider-wildcard.js.map +1 -0
- package/src/lib/server/domain-provider.d.ts +197 -0
- package/src/lib/server/domain-provider.js +221 -0
- package/src/lib/server/domain-provider.js.map +1 -0
- package/src/lib/server/duplicate-activity.d.ts +54 -0
- package/src/lib/server/duplicate-activity.js +67 -0
- package/src/lib/server/duplicate-activity.js.map +1 -0
- package/src/lib/server/duplicate-resource.d.ts +55 -0
- package/src/lib/server/duplicate-resource.js +474 -0
- package/src/lib/server/duplicate-resource.js.map +1 -0
- package/src/lib/server/dynamic-list-materialize.d.ts +153 -0
- package/src/lib/server/dynamic-list-materialize.js +581 -0
- package/src/lib/server/dynamic-list-materialize.js.map +1 -0
- package/src/lib/server/edit-access-authz.d.ts +56 -0
- package/src/lib/server/edit-access-authz.js +107 -0
- package/src/lib/server/edit-access-authz.js.map +1 -0
- package/src/lib/server/edit-access-token.d.ts +72 -0
- package/src/lib/server/edit-access-token.js +116 -0
- package/src/lib/server/edit-access-token.js.map +1 -0
- package/src/lib/server/edit-hint-token.d.ts +83 -0
- package/src/lib/server/edit-hint-token.js +119 -0
- package/src/lib/server/edit-hint-token.js.map +1 -0
- package/src/lib/server/email-delivery-log.d.ts +509 -0
- package/src/lib/server/email-delivery-log.js +1043 -0
- package/src/lib/server/email-delivery-log.js.map +1 -0
- package/src/lib/server/email-flow-gate.d.ts +80 -0
- package/src/lib/server/email-flow-gate.js +153 -0
- package/src/lib/server/email-flow-gate.js.map +1 -0
- package/src/lib/server/email-marketing-gate.d.ts +333 -0
- package/src/lib/server/email-marketing-gate.js +639 -0
- package/src/lib/server/email-marketing-gate.js.map +1 -0
- package/src/lib/server/email-metering.d.ts +293 -0
- package/src/lib/server/email-metering.js +359 -0
- package/src/lib/server/email-metering.js.map +1 -0
- package/src/lib/server/email-revenue-attribution.d.ts +185 -0
- package/src/lib/server/email-revenue-attribution.js +300 -0
- package/src/lib/server/email-revenue-attribution.js.map +1 -0
- package/src/lib/server/email-send-rate.d.ts +232 -0
- package/src/lib/server/email-send-rate.js +417 -0
- package/src/lib/server/email-send-rate.js.map +1 -0
- package/src/lib/server/email-sender-reputation.d.ts +317 -0
- package/src/lib/server/email-sender-reputation.js +464 -0
- package/src/lib/server/email-sender-reputation.js.map +1 -0
- package/src/lib/server/email-suppression.d.ts +490 -0
- package/src/lib/server/email-suppression.js +648 -0
- package/src/lib/server/email-suppression.js.map +1 -0
- package/src/lib/server/email-topic-confirmation.d.ts +150 -0
- package/src/lib/server/email-topic-confirmation.js +272 -0
- package/src/lib/server/email-topic-confirmation.js.map +1 -0
- package/src/lib/server/email-unsubscribe-link.d.ts +174 -0
- package/src/lib/server/email-unsubscribe-link.js +236 -0
- package/src/lib/server/email-unsubscribe-link.js.map +1 -0
- package/src/lib/server/erase-person.d.ts +116 -0
- package/src/lib/server/erase-person.js +272 -0
- package/src/lib/server/erase-person.js.map +1 -0
- package/src/lib/server/erase.d.ts +458 -0
- package/src/lib/server/erase.js +1506 -0
- package/src/lib/server/erase.js.map +1 -0
- package/src/lib/server/firebase-admin.d.ts +71 -0
- package/src/lib/server/firebase-admin.js +343 -0
- package/src/lib/server/firebase-admin.js.map +1 -0
- package/src/lib/server/form-dataset-binding-token.d.ts +35 -0
- package/src/lib/server/form-dataset-binding-token.js +107 -0
- package/src/lib/server/form-dataset-binding-token.js.map +1 -0
- package/src/lib/server/free-workspace-cap.d.ts +201 -0
- package/src/lib/server/free-workspace-cap.js +404 -0
- package/src/lib/server/free-workspace-cap.js.map +1 -0
- package/src/lib/server/ga4-measurement-protocol.d.ts +256 -0
- package/src/lib/server/ga4-measurement-protocol.js +558 -0
- package/src/lib/server/ga4-measurement-protocol.js.map +1 -0
- package/src/lib/server/host-email-tokens.d.ts +47 -0
- package/src/lib/server/host-email-tokens.js +72 -0
- package/src/lib/server/host-email-tokens.js.map +1 -0
- package/src/lib/server/host-memberships.d.ts +54 -0
- package/src/lib/server/host-memberships.js +194 -0
- package/src/lib/server/host-memberships.js.map +1 -0
- package/src/lib/server/host-sending-domain.d.ts +292 -0
- package/src/lib/server/host-sending-domain.js +451 -0
- package/src/lib/server/host-sending-domain.js.map +1 -0
- package/src/lib/server/host-visitor-records.d.ts +150 -0
- package/src/lib/server/host-visitor-records.js +262 -0
- package/src/lib/server/host-visitor-records.js.map +1 -0
- package/src/lib/server/id-token-refusal.d.ts +28 -0
- package/src/lib/server/id-token-refusal.js +111 -0
- package/src/lib/server/id-token-refusal.js.map +1 -0
- package/src/lib/server/legal-acceptance.d.ts +214 -0
- package/src/lib/server/legal-acceptance.js +305 -0
- package/src/lib/server/legal-acceptance.js.map +1 -0
- package/src/lib/server/list-members.d.ts +211 -0
- package/src/lib/server/list-members.js +176 -0
- package/src/lib/server/list-members.js.map +1 -0
- package/src/lib/server/live-page-usage.d.ts +202 -0
- package/src/lib/server/live-page-usage.js +300 -0
- package/src/lib/server/live-page-usage.js.map +1 -0
- package/src/lib/server/lockdown.d.ts +313 -0
- package/src/lib/server/lockdown.js +643 -0
- package/src/lib/server/lockdown.js.map +1 -0
- package/src/lib/server/media-cdn-rate-limit.d.ts +188 -0
- package/src/lib/server/media-cdn-rate-limit.js +204 -0
- package/src/lib/server/media-cdn-rate-limit.js.map +1 -0
- package/src/lib/server/media-delivery.d.ts +267 -0
- package/src/lib/server/media-delivery.js +485 -0
- package/src/lib/server/media-delivery.js.map +1 -0
- package/src/lib/server/media-download-tokens.d.ts +161 -0
- package/src/lib/server/media-download-tokens.js +386 -0
- package/src/lib/server/media-download-tokens.js.map +1 -0
- package/src/lib/server/media-quarantine.d.ts +127 -0
- package/src/lib/server/media-quarantine.js +170 -0
- package/src/lib/server/media-quarantine.js.map +1 -0
- package/src/lib/server/media-signing.d.ts +126 -0
- package/src/lib/server/media-signing.js +159 -0
- package/src/lib/server/media-signing.js.map +1 -0
- package/src/lib/server/media-storage-path.d.ts +96 -0
- package/src/lib/server/media-storage-path.js +111 -0
- package/src/lib/server/media-storage-path.js.map +1 -0
- package/src/lib/server/media-strong-digest.d.ts +85 -0
- package/src/lib/server/media-strong-digest.js +190 -0
- package/src/lib/server/media-strong-digest.js.map +1 -0
- package/src/lib/server/media-tombstone.d.ts +276 -0
- package/src/lib/server/media-tombstone.js +421 -0
- package/src/lib/server/media-tombstone.js.map +1 -0
- package/src/lib/server/media-variants.d.ts +309 -0
- package/src/lib/server/media-variants.js +428 -0
- package/src/lib/server/media-variants.js.map +1 -0
- package/src/lib/server/member-email-aliases.d.ts +180 -0
- package/src/lib/server/member-email-aliases.js +420 -0
- package/src/lib/server/member-email-aliases.js.map +1 -0
- package/src/lib/server/member-photo.d.ts +88 -0
- package/src/lib/server/member-photo.js +185 -0
- package/src/lib/server/member-photo.js.map +1 -0
- package/src/lib/server/membership-recover-throttle.d.ts +211 -0
- package/src/lib/server/membership-recover-throttle.js +231 -0
- package/src/lib/server/membership-recover-throttle.js.map +1 -0
- package/src/lib/server/notifications.d.ts +55 -0
- package/src/lib/server/notifications.js +134 -0
- package/src/lib/server/notifications.js.map +1 -0
- package/src/lib/server/org-billing.d.ts +97 -0
- package/src/lib/server/org-billing.js +236 -0
- package/src/lib/server/org-billing.js.map +1 -0
- package/src/lib/server/organizations.d.ts +837 -0
- package/src/lib/server/organizations.js +1814 -0
- package/src/lib/server/organizations.js.map +1 -0
- package/src/lib/server/password-reset-throttle.d.ts +84 -0
- package/src/lib/server/password-reset-throttle.js +102 -0
- package/src/lib/server/password-reset-throttle.js.map +1 -0
- package/src/lib/server/personal-data-export.d.ts +241 -0
- package/src/lib/server/personal-data-export.js +858 -0
- package/src/lib/server/personal-data-export.js.map +1 -0
- package/src/lib/server/platform-domain-names.d.ts +62 -0
- package/src/lib/server/platform-domain-names.js +197 -0
- package/src/lib/server/platform-domain-names.js.map +1 -0
- package/src/lib/server/platform-marketing-consent.d.ts +133 -0
- package/src/lib/server/platform-marketing-consent.js +209 -0
- package/src/lib/server/platform-marketing-consent.js.map +1 -0
- package/src/lib/server/rate-limit-store.d.ts +702 -0
- package/src/lib/server/rate-limit-store.js +1220 -0
- package/src/lib/server/rate-limit-store.js.map +1 -0
- package/src/lib/server/realm-plugins.d.ts +67 -0
- package/src/lib/server/realm-plugins.js +250 -0
- package/src/lib/server/realm-plugins.js.map +1 -0
- package/src/lib/server/recaptcha-allowlist.d.ts +90 -0
- package/src/lib/server/recaptcha-allowlist.js +409 -0
- package/src/lib/server/recaptcha-allowlist.js.map +1 -0
- package/src/lib/server/release-flags.d.ts +105 -0
- package/src/lib/server/release-flags.js +183 -0
- package/src/lib/server/release-flags.js.map +1 -0
- package/src/lib/server/replay-erasures.d.ts +126 -0
- package/src/lib/server/replay-erasures.js +217 -0
- package/src/lib/server/replay-erasures.js.map +1 -0
- package/src/lib/server/resolve-people.d.ts +66 -0
- package/src/lib/server/resolve-people.js +112 -0
- package/src/lib/server/resolve-people.js.map +1 -0
- package/src/lib/server/safe-equal.d.ts +45 -0
- package/src/lib/server/safe-equal.js +58 -0
- package/src/lib/server/safe-equal.js.map +1 -0
- package/src/lib/server/sending-domain-debt.d.ts +127 -0
- package/src/lib/server/sending-domain-debt.js +268 -0
- package/src/lib/server/sending-domain-debt.js.map +1 -0
- package/src/lib/server/sending-domain-recheck.d.ts +151 -0
- package/src/lib/server/sending-domain-recheck.js +253 -0
- package/src/lib/server/sending-domain-recheck.js.map +1 -0
- package/src/lib/server/sending-domains.d.ts +364 -0
- package/src/lib/server/sending-domains.js +683 -0
- package/src/lib/server/sending-domains.js.map +1 -0
- package/src/lib/server/serve-media-cdn.d.ts +433 -0
- package/src/lib/server/serve-media-cdn.js +1370 -0
- package/src/lib/server/serve-media-cdn.js.map +1 -0
- package/src/lib/server/serve-plugin-fetch.d.ts +61 -0
- package/src/lib/server/serve-plugin-fetch.js +294 -0
- package/src/lib/server/serve-plugin-fetch.js.map +1 -0
- package/src/lib/server/sms-keywords.d.ts +63 -0
- package/src/lib/server/sms-keywords.js +146 -0
- package/src/lib/server/sms-keywords.js.map +1 -0
- package/src/lib/server/sso-break-glass-owners.d.ts +91 -0
- package/src/lib/server/sso-break-glass-owners.js +227 -0
- package/src/lib/server/sso-break-glass-owners.js.map +1 -0
- package/src/lib/server/sso-domain-policy.d.ts +140 -0
- package/src/lib/server/sso-domain-policy.js +239 -0
- package/src/lib/server/sso-domain-policy.js.map +1 -0
- package/src/lib/server/sso-drift-logic.d.ts +106 -0
- package/src/lib/server/sso-drift-logic.js +95 -0
- package/src/lib/server/sso-drift-logic.js.map +1 -0
- package/src/lib/server/sso-enforcement.d.ts +204 -0
- package/src/lib/server/sso-enforcement.js +309 -0
- package/src/lib/server/sso-enforcement.js.map +1 -0
- package/src/lib/server/sso-provisioning.d.ts +320 -0
- package/src/lib/server/sso-provisioning.js +715 -0
- package/src/lib/server/sso-provisioning.js.map +1 -0
- package/src/lib/server/staff-alert-email.d.ts +41 -0
- package/src/lib/server/staff-alert-email.js +63 -0
- package/src/lib/server/staff-alert-email.js.map +1 -0
- package/src/lib/server/stripe-account-mode.d.ts +156 -0
- package/src/lib/server/stripe-account-mode.js +162 -0
- package/src/lib/server/stripe-account-mode.js.map +1 -0
- package/src/lib/server/tenant-write-lockdown.d.ts +131 -0
- package/src/lib/server/tenant-write-lockdown.js +176 -0
- package/src/lib/server/tenant-write-lockdown.js.map +1 -0
- package/src/lib/server/test-firestore.d.ts +45 -0
- package/src/lib/server/test-firestore.js +124 -0
- package/src/lib/server/test-firestore.js.map +1 -0
- package/src/lib/server/token-revocation.d.ts +140 -0
- package/src/lib/server/token-revocation.js +255 -0
- package/src/lib/server/token-revocation.js.map +1 -0
- package/src/lib/server/update-existing.d.ts +32 -0
- package/src/lib/server/update-existing.js +73 -0
- package/src/lib/server/update-existing.js.map +1 -0
- package/src/lib/server/upload-cors-reconcile.d.ts +118 -0
- package/src/lib/server/upload-cors-reconcile.js +234 -0
- package/src/lib/server/upload-cors-reconcile.js.map +1 -0
- package/src/lib/server/upsert-contact.d.ts +262 -0
- package/src/lib/server/upsert-contact.js +546 -0
- package/src/lib/server/upsert-contact.js.map +1 -0
- package/src/lib/server/usage-invoice.d.ts +203 -0
- package/src/lib/server/usage-invoice.js +397 -0
- package/src/lib/server/usage-invoice.js.map +1 -0
- package/src/lib/server/user-profiles.d.ts +151 -0
- package/src/lib/server/user-profiles.js +364 -0
- package/src/lib/server/user-profiles.js.map +1 -0
- package/src/lib/server/vercel-drain-signature.d.ts +30 -0
- package/src/lib/server/vercel-drain-signature.js +61 -0
- package/src/lib/server/vercel-drain-signature.js.map +1 -0
- package/src/lib/server/vercel-log-drain.d.ts +259 -0
- package/src/lib/server/vercel-log-drain.js +479 -0
- package/src/lib/server/vercel-log-drain.js.map +1 -0
- package/src/lib/server/verify-email-cooldown.d.ts +102 -0
- package/src/lib/server/verify-email-cooldown.js +114 -0
- package/src/lib/server/verify-email-cooldown.js.map +1 -0
- package/src/lib/server/visitor-write-rate-limit.d.ts +87 -0
- package/src/lib/server/visitor-write-rate-limit.js +117 -0
- package/src/lib/server/visitor-write-rate-limit.js.map +1 -0
- package/src/lib/server/workspace-domains.d.ts +156 -0
- package/src/lib/server/workspace-domains.js +271 -0
- package/src/lib/server/workspace-domains.js.map +1 -0
- package/src/tenancy.d.ts +115 -0
- package/src/tenancy.js +142 -0
- package/src/tenancy.js.map +1 -0
|
@@ -0,0 +1,276 @@
|
|
|
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
|
+
import { Timestamp } from 'firebase-admin/firestore';
|
|
18
|
+
/**
|
|
19
|
+
* What a DAM delete has to leave behind for an undo to be possible at all
|
|
20
|
+
* (AGL-1467).
|
|
21
|
+
*
|
|
22
|
+
* ## The gap this closes
|
|
23
|
+
*
|
|
24
|
+
* The bucket has soft-delete on with a **seven-day** retention, so the bytes
|
|
25
|
+
* of a deleted asset really are still there. That was only ever half of an
|
|
26
|
+
* undo, and AGL-1461 shipped honest copy rather than a button because of the
|
|
27
|
+
* other half: `/api/media/upload`'s DELETE branch hard-deleted the Firestore
|
|
28
|
+
* document. After it ran, nothing in the product knew the asset's id, file
|
|
29
|
+
* name, folder, tags, alt text, description, custom metadata, `visibleTo`
|
|
30
|
+
* scope tokens, `cdnPath` or `variants` — and `File.restore()` needs a
|
|
31
|
+
* **generation number** that nobody had captured. Surviving bytes with no
|
|
32
|
+
* address are not a recovery story. On 2026-08-13 two files deleted in error
|
|
33
|
+
* came back only because an unrelated analysis document happened to have
|
|
34
|
+
* recorded their ids; a customer has no such document.
|
|
35
|
+
*
|
|
36
|
+
* A tombstone is the three facts that make the bytes addressable again:
|
|
37
|
+
*
|
|
38
|
+
* 1. the media document verbatim, as it was at the moment of the delete;
|
|
39
|
+
* 2. the **generation** of the storage object and of every CDN variant,
|
|
40
|
+
* read BEFORE the delete — afterwards there is no live object to ask;
|
|
41
|
+
* 3. `sizeBytes`, so the counter decrement can be reversed by exactly the
|
|
42
|
+
* amount it moved rather than by a recomputation that can drift.
|
|
43
|
+
*
|
|
44
|
+
* ## Where it lives, and why that is the whole erasure answer
|
|
45
|
+
*
|
|
46
|
+
* `{hosts|orgs}/{scopeId}/mediaTombstones/{mediaId}` — a subcollection of the
|
|
47
|
+
* scope that owned the asset, never a top-level collection keyed by media id.
|
|
48
|
+
*
|
|
49
|
+
* This is the load-bearing choice. `eraseHost` ends in
|
|
50
|
+
* `recursiveDelete(hostRef)` and `eraseOrg` ends in `recursiveDelete(orgRef)`,
|
|
51
|
+
* and a path-scoped cascade takes every subcollection under the path with it.
|
|
52
|
+
* Put the tombstones there and an erasure removes them with no new code — put
|
|
53
|
+
* them in a top-level `mediaTombstones/{id}` with an `orgId` field and they
|
|
54
|
+
* become exactly the shape AGL-1444 and AGL-1448 had to go back and wire by
|
|
55
|
+
* hand: a collection the cascade is structurally blind to, holding a verbatim
|
|
56
|
+
* copy of customer content, surviving the request that promised it was gone.
|
|
57
|
+
* A tombstone is customer data. It has to die with the customer.
|
|
58
|
+
*
|
|
59
|
+
* (The property is asserted rather than assumed —
|
|
60
|
+
* `erase-media-tombstones.emulator.spec.ts` erases a host and an org that each
|
|
61
|
+
* hold one and looks for the survivor.)
|
|
62
|
+
*
|
|
63
|
+
* ## Retention: the same seven days as the bytes, and not a day more
|
|
64
|
+
*
|
|
65
|
+
* `expiresAt` is stamped at `MEDIA_TOMBSTONE_RETENTION_MS` past the delete,
|
|
66
|
+
* which is the bucket's soft-delete window exactly. Both other numbers are
|
|
67
|
+
* wrong for the same reason from opposite directions: a shorter tombstone
|
|
68
|
+
* strands recoverable bytes with no address, which is today's defect made
|
|
69
|
+
* smaller, and a longer one can only ever produce a failed restore while
|
|
70
|
+
* holding a copy of a customer's asset for no reachable purpose. AGL-1443 is
|
|
71
|
+
* open on precisely that — a durable copy of customer data whose retention
|
|
72
|
+
* nobody chose — and this must not become a second instance of it.
|
|
73
|
+
*
|
|
74
|
+
* The field is enforced two ways, because neither alone is enough. A Firestore
|
|
75
|
+
* TTL policy on `mediaTombstones.expiresAt` reaps them (see
|
|
76
|
+
* `docs/FIRESTORE_MANUAL_CONFIG.md`), and TTL deletion is explicitly not
|
|
77
|
+
* prompt — so `restoreMediaFromTombstone` treats an expired tombstone as
|
|
78
|
+
* absent and deletes it on sight rather than trusting the sweeper.
|
|
79
|
+
*/
|
|
80
|
+
/** The subcollection, under the scope that owned the asset. */
|
|
81
|
+
export declare const MEDIA_TOMBSTONE_COLLECTION = "mediaTombstones";
|
|
82
|
+
/**
|
|
83
|
+
* How long a tombstone lives: the bucket's soft-delete retention, exactly.
|
|
84
|
+
*
|
|
85
|
+
* Changing this without changing the bucket policy breaks the invariant the
|
|
86
|
+
* whole module rests on — see the header.
|
|
87
|
+
*/
|
|
88
|
+
export declare const MEDIA_TOMBSTONE_RETENTION_MS: number;
|
|
89
|
+
/** Days, for the copy that has to name the window to a person. */
|
|
90
|
+
export declare const MEDIA_TOMBSTONE_RETENTION_DAYS: number;
|
|
91
|
+
/**
|
|
92
|
+
* One deleted object and the generation that addresses it.
|
|
93
|
+
*
|
|
94
|
+
* `generation` is nullable on purpose: reading it is a Storage round-trip that
|
|
95
|
+
* can fail, and an asset whose object was ALREADY missing (replaced, swept,
|
|
96
|
+
* never written) must still produce a tombstone — the document half of the
|
|
97
|
+
* restore is worth having on its own. A null generation means "nothing to
|
|
98
|
+
* restore here", not "restore failed".
|
|
99
|
+
*/
|
|
100
|
+
export interface MediaObjectGeneration {
|
|
101
|
+
path: string;
|
|
102
|
+
generation: string | null;
|
|
103
|
+
}
|
|
104
|
+
/** The stored tombstone document. */
|
|
105
|
+
export interface MediaTombstoneDoc {
|
|
106
|
+
/** The media document verbatim, exactly as the delete found it. */
|
|
107
|
+
media: Record<string, unknown>;
|
|
108
|
+
/** Primary object first, then every CDN variant. */
|
|
109
|
+
objects: MediaObjectGeneration[];
|
|
110
|
+
/** The counter decrement to reverse, taken from the document. */
|
|
111
|
+
sizeBytes: number;
|
|
112
|
+
fileName: string;
|
|
113
|
+
deletedBy: string;
|
|
114
|
+
deletedAt: Timestamp | number;
|
|
115
|
+
/**
|
|
116
|
+
* Hard bound — see the header. Written as a **Timestamp**, which the TTL
|
|
117
|
+
* policy requires (a number field cannot carry one, which is why
|
|
118
|
+
* `bookings.expiresAtMs` is documented as not a TTL target). Read through
|
|
119
|
+
* `isMediaTombstoneExpired`, which takes either form so a hand-written
|
|
120
|
+
* fixture and the real write are both legible.
|
|
121
|
+
*/
|
|
122
|
+
expiresAt: Timestamp | number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The slice of `File` this module needs; the real one satisfies it.
|
|
126
|
+
*
|
|
127
|
+
* `restore` takes a NUMBER because the SDK's `RestoreOptions` does, while the
|
|
128
|
+
* tombstone stores the generation as a string — a GCS generation is a
|
|
129
|
+
* microsecond timestamp (~1.7e15), comfortably inside a double, but a string
|
|
130
|
+
* is what survives JSON, a Firestore round-trip and a log line without anyone
|
|
131
|
+
* having to reason about that. The conversion happens once, at the call.
|
|
132
|
+
*/
|
|
133
|
+
export interface TombstoneStorageFile {
|
|
134
|
+
getMetadata(): Promise<any>;
|
|
135
|
+
delete(): Promise<any>;
|
|
136
|
+
exists(): Promise<any>;
|
|
137
|
+
restore(options: {
|
|
138
|
+
generation: number;
|
|
139
|
+
}): Promise<any>;
|
|
140
|
+
}
|
|
141
|
+
/** The slice of `Bucket` this module needs. */
|
|
142
|
+
export interface TombstoneStorageBucket {
|
|
143
|
+
file(path: string): TombstoneStorageFile;
|
|
144
|
+
}
|
|
145
|
+
/** When a tombstone written now stops being useful. */
|
|
146
|
+
export declare function mediaTombstoneExpiry(deletedAtMs: number): number;
|
|
147
|
+
/**
|
|
148
|
+
* Whether the bytes this tombstone addresses are past the bucket's window.
|
|
149
|
+
*
|
|
150
|
+
* Missing or unreadable reads as EXPIRED, which is the safe direction: the
|
|
151
|
+
* failure mode of a false positive is a refusal with a clear message, and the
|
|
152
|
+
* failure mode of a false negative is a restore that half-succeeds against
|
|
153
|
+
* bytes the bucket has already reaped.
|
|
154
|
+
*/
|
|
155
|
+
export declare function isMediaTombstoneExpired(tombstone: Pick<MediaTombstoneDoc, 'expiresAt'>, nowMs: number): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Read the generation of each object, best-effort (AGL-1467).
|
|
158
|
+
*
|
|
159
|
+
* Must run BEFORE the delete. Once the object is soft-deleted there is no live
|
|
160
|
+
* generation to read, and the number is the only handle `restore()` takes —
|
|
161
|
+
* this is the single fact whose absence made undo impossible rather than
|
|
162
|
+
* merely unbuilt.
|
|
163
|
+
*
|
|
164
|
+
* A failure here degrades the tombstone to its document half rather than
|
|
165
|
+
* failing the delete: an author who asked for a file to go must not be told
|
|
166
|
+
* "no" because a metadata read timed out.
|
|
167
|
+
*/
|
|
168
|
+
export declare function captureObjectGenerations(bucket: TombstoneStorageBucket, paths: readonly string[]): Promise<MediaObjectGeneration[]>;
|
|
169
|
+
export interface DeleteMediaResult {
|
|
170
|
+
/** False when there was no document to delete (already gone). */
|
|
171
|
+
deleted: boolean;
|
|
172
|
+
/** Present when a tombstone was written — the id is the media id. */
|
|
173
|
+
tombstone?: {
|
|
174
|
+
mediaId: string;
|
|
175
|
+
expiresAt: number;
|
|
176
|
+
fileName: string;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Delete a media document and leave a tombstone behind, in one commit.
|
|
181
|
+
*
|
|
182
|
+
* **The invariant: the media document is never destroyed except in the same
|
|
183
|
+
* transaction that writes its tombstone and moves the counter.** All three
|
|
184
|
+
* belong to one commit, so there is no interleaving in which the document is
|
|
185
|
+
* gone and the record of it is not — which is the state the product was
|
|
186
|
+
* permanently in before this issue.
|
|
187
|
+
*
|
|
188
|
+
* The object delete happens AFTER that commit, deliberately, and the ordering
|
|
189
|
+
* is a choice between two partial failures:
|
|
190
|
+
*
|
|
191
|
+
* - object first: a failed commit leaves a live document pointing at bytes
|
|
192
|
+
* that are already soft-deleted — a broken asset in the library that
|
|
193
|
+
* nothing detects;
|
|
194
|
+
* - commit first: a failed object delete leaves a tombstone whose object is
|
|
195
|
+
* still live, which `restoreMediaFromTombstone` handles by skipping the
|
|
196
|
+
* restore for an object that is already there.
|
|
197
|
+
*
|
|
198
|
+
* The second is recoverable by the code in this file. The first is not
|
|
199
|
+
* recoverable by anything.
|
|
200
|
+
*/
|
|
201
|
+
export declare function deleteMediaWithTombstone(options: {
|
|
202
|
+
scopeRef: FirebaseFirestore.DocumentReference;
|
|
203
|
+
bucket: TombstoneStorageBucket;
|
|
204
|
+
mediaId: string;
|
|
205
|
+
/** Path of the primary object, resolved by the caller (legacy fallback). */
|
|
206
|
+
objectPath: string;
|
|
207
|
+
/** Who asked — an erasure record with no actor is half a record. */
|
|
208
|
+
uid: string;
|
|
209
|
+
nowMs?: number;
|
|
210
|
+
}): Promise<DeleteMediaResult>;
|
|
211
|
+
export interface RestoreMediaResult {
|
|
212
|
+
ok: boolean;
|
|
213
|
+
/** HTTP status the route should answer with. */
|
|
214
|
+
status: number;
|
|
215
|
+
/** A real sentence for a person — never a bare code. */
|
|
216
|
+
message: string;
|
|
217
|
+
fileName?: string;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Why a restore cannot proceed, decided without touching Storage (AGL-1467).
|
|
221
|
+
*
|
|
222
|
+
* Pure, because these are the answers a person actually sees and the two
|
|
223
|
+
* interesting ones are cheap to get wrong: an expired tombstone must fail
|
|
224
|
+
* CLEANLY rather than half-succeed against bytes the bucket has already
|
|
225
|
+
* reaped, and a restore that would breach the plan must say so rather than
|
|
226
|
+
* push the counter past the limit in silence.
|
|
227
|
+
*
|
|
228
|
+
* ## The quota call
|
|
229
|
+
*
|
|
230
|
+
* A restore re-adds real bytes, so it is gated exactly like an upload —
|
|
231
|
+
* `storagePerHostMb`, same off-by-one — and REFUSED when it would breach the
|
|
232
|
+
* plan. Waiving it would let delete-then-restore launder an over-quota
|
|
233
|
+
* library, which is the AGL-1471/AGL-1279 shape (a limit evaluated at a moment
|
|
234
|
+
* the caller controls). Refusing is safe precisely because the tombstone
|
|
235
|
+
* outlives the refusal: the asset is still restorable for the rest of the
|
|
236
|
+
* window once space is freed, which is what makes "no, and here is why"
|
|
237
|
+
* an honest answer rather than a loss.
|
|
238
|
+
*
|
|
239
|
+
* Note what is NOT metered: the soft-deleted bytes themselves. They sit in the
|
|
240
|
+
* bucket for seven days at Aglyn's cost, and counting them would mean deleting
|
|
241
|
+
* a file did not free space until a week later — which breaks the one action
|
|
242
|
+
* an author takes when they hit the wall. The window is the price of offering
|
|
243
|
+
* undo, not an allocation to bill back.
|
|
244
|
+
*/
|
|
245
|
+
export declare function mediaRestoreRefusal(options: {
|
|
246
|
+
tombstone: Pick<MediaTombstoneDoc, 'expiresAt' | 'sizeBytes' | 'fileName'>;
|
|
247
|
+
nowMs: number;
|
|
248
|
+
/** Counter bytes as they stand now, with the asset already removed. */
|
|
249
|
+
usedBytes: number;
|
|
250
|
+
billing: Record<string, unknown> | undefined;
|
|
251
|
+
}): {
|
|
252
|
+
status: number;
|
|
253
|
+
message: string;
|
|
254
|
+
} | null;
|
|
255
|
+
/**
|
|
256
|
+
* Put a deleted asset back: object, variants, document and counters.
|
|
257
|
+
*
|
|
258
|
+
* Order is the same argument as the delete, run backwards. Bytes first, then
|
|
259
|
+
* the commit — so the only partial state this can leave is an object restored
|
|
260
|
+
* with no document, which the tombstone (still present, because the commit is
|
|
261
|
+
* what consumes it) makes a retry away from finished. The reverse order would
|
|
262
|
+
* publish a document whose bytes may never arrive.
|
|
263
|
+
*
|
|
264
|
+
* The commit itself carries the document write, the tombstone delete and both
|
|
265
|
+
* counter increments together, and it re-reads the tombstone inside the
|
|
266
|
+
* transaction. That re-read is what makes a double-click harmless: the second
|
|
267
|
+
* transaction finds no tombstone, commits nothing, and the caller is told the
|
|
268
|
+
* file is already back rather than being charged for it twice.
|
|
269
|
+
*/
|
|
270
|
+
export declare function restoreMediaFromTombstone(options: {
|
|
271
|
+
scopeRef: FirebaseFirestore.DocumentReference;
|
|
272
|
+
bucket: TombstoneStorageBucket;
|
|
273
|
+
mediaId: string;
|
|
274
|
+
billing: Record<string, unknown> | undefined;
|
|
275
|
+
nowMs?: number;
|
|
276
|
+
}): Promise<RestoreMediaResult>;
|