@aglyn/shared-util-email 1.0.0-beta.218 → 1.0.0-beta.220

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 (53) hide show
  1. package/README.md +58 -19
  2. package/package.json +3 -3
  3. package/src/index.d.ts +2 -0
  4. package/src/index.js +9 -1
  5. package/src/index.js.map +1 -1
  6. package/src/lib/email-delivery-events.d.ts +41 -48
  7. package/src/lib/email-delivery-events.js +18 -247
  8. package/src/lib/email-delivery-events.js.map +1 -1
  9. package/src/lib/email-health.d.ts +30 -43
  10. package/src/lib/email-health.js +45 -141
  11. package/src/lib/email-health.js.map +1 -1
  12. package/src/lib/hosted-page-screen.d.ts +27 -0
  13. package/src/lib/hosted-page-screen.js +228 -23
  14. package/src/lib/hosted-page-screen.js.map +1 -1
  15. package/src/lib/mail-provider-resend.d.ts +194 -0
  16. package/src/lib/mail-provider-resend.js +649 -0
  17. package/src/lib/mail-provider-resend.js.map +1 -0
  18. package/src/lib/mail-provider-webhook.d.ts +80 -0
  19. package/src/lib/mail-provider-webhook.js +156 -0
  20. package/src/lib/mail-provider-webhook.js.map +1 -0
  21. package/src/lib/mail-provider.d.ts +148 -0
  22. package/src/lib/mail-provider.js +84 -0
  23. package/src/lib/mail-provider.js.map +1 -0
  24. package/src/lib/mail-providers.d.ts +99 -0
  25. package/src/lib/mail-providers.js +182 -0
  26. package/src/lib/mail-providers.js.map +1 -0
  27. package/src/lib/outbound-phishing-screen.d.ts +80 -3
  28. package/src/lib/outbound-phishing-screen.js +457 -29
  29. package/src/lib/outbound-phishing-screen.js.map +1 -1
  30. package/src/lib/received-email.d.ts +7 -44
  31. package/src/lib/received-email.js +8 -104
  32. package/src/lib/received-email.js.map +1 -1
  33. package/src/lib/risk-notice-catalog.d.ts +32 -2
  34. package/src/lib/risk-notice-catalog.js +86 -55
  35. package/src/lib/risk-notice-catalog.js.map +1 -1
  36. package/src/lib/send-ceilings.d.ts +0 -57
  37. package/src/lib/send-ceilings.js +0 -47
  38. package/src/lib/send-ceilings.js.map +1 -1
  39. package/src/lib/send-email.d.ts +52 -58
  40. package/src/lib/send-email.js +128 -134
  41. package/src/lib/send-email.js.map +1 -1
  42. package/src/lib/send-rate.js +4 -3
  43. package/src/lib/send-rate.js.map +1 -1
  44. package/src/lib/sending-domain.d.ts +15 -0
  45. package/src/lib/sending-domain.js.map +1 -1
  46. package/src/lib/system-email-catalog.js +37 -11
  47. package/src/lib/system-email-catalog.js.map +1 -1
  48. package/src/lib/tenant-email-catalog.d.ts +7 -0
  49. package/src/lib/tenant-email-catalog.js +10 -591
  50. package/src/lib/tenant-email-catalog.js.map +1 -1
  51. package/src/lib/tenant-emails.generated.d.ts +11 -0
  52. package/src/lib/tenant-emails.generated.js +649 -0
  53. package/src/lib/tenant-emails.generated.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/risk-notice-catalog.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * THE RISK NOTICE CATALOG (AGL-3368).\n *\n * Every event where the platform holds, flags, locks or pauses something on\n * a workspace, and what each audience is told about it. One entry per kind,\n * read by three consumers that must never disagree:\n *\n * - `notifyRiskEvent` (`@aglyn/tenant-data-admin/server/risk-notice`), which\n * renders the entry into the in-app notification, the owner email and the\n * staff alert;\n * - the console: the workspace's Holds & reviews page renders an owner's\n * notices from it, and the staff abuse queue renders a row's staff half;\n * - the customer help page and the System emails catalog, which list every\n * kind.\n *\n * ## Two audiences, two vocabularies\n *\n * The OWNER half is read by the workspace's owners and admins — and a\n * fraud actor is a workspace owner too. So it describes the OUTCOME and the\n * way to a human (what was held, what that means, how to ask for a review),\n * never the detection: no rule, no threshold, no brand the screen matched,\n * no count of anything. `risk-notice-catalog.spec.ts` sweeps it for those.\n *\n * The STAFF half is read by staff only and names the evidence plainly.\n *\n * ## Owners can never release\n *\n * No owner action releases a hold or lifts a lock. An owner's \"waive\" is a\n * review request, which appends a note to the same abuse-queue row. The\n * spec pins that no owner action id is a staff decision.\n *\n * ## Text is written against merge tokens\n *\n * `{{item.label}}`, `{{workspace.name}}`, `{{brand.productName}}` and the rest\n * are filled at send time. The same strings seed the System emails catalog\n * entry each kind gets (`risk-notice-emails.ts`), so staff can edit the email\n * a kind sends on the System emails page.\n *\n * Pure and dependency-free: the console, the docs, the specs and the server\n * all import it.\n *=========================================*/\n\n/** Every kind of risk event the platform tells people about. */\nexport const RISK_EVENT_KINDS = [\n // Outbound email held by the safety screen: a campaign, an automation\n // step, any site email at the send seam, an outreach message.\n 'email-held',\n 'email-released',\n 'email-rejected',\n // A published page held before a visitor saw it.\n 'page-held',\n 'page-released',\n 'page-rejected',\n // A page ALREADY LIVE that the safety review flagged: it keeps serving,\n // and staff look — the account may have been compromised.\n 'page-flagged',\n // A marketplace submission (a listing, a publisher profile) held before\n // it was listed.\n 'listing-held',\n 'listing-released',\n 'listing-rejected',\n // A custom site domain or sending domain flagged for a look.\n 'domain-flagged',\n 'domain-cleared',\n 'domain-rejected',\n // A fraud signal on the workspace's own subscription payment.\n 'billing-payment-flagged',\n // A link a merchant configured (a download, a feed, a supplier hook) that\n // wears another brand's name, refused wherever it is followed.\n 'link-blocked',\n // A burst of card payments on one site: possibly card testing.\n 'card-testing',\n // Gift cards an order bought, frozen while its payment is in question.\n 'gift-card-hold',\n // A fraud signal on a sale the workspace took from its own customer.\n 'sale-fraud-warning',\n 'sale-payment-review',\n 'sale-dispute',\n // Several of a seller's sales drew fraud reports: staff are reviewing.\n 'seller-review',\n // A marketplace sale a publisher received is under review, a card signal\n // arrived on one, and a new publisher's payouts wait (or stop waiting).\n 'marketplace-sale-review',\n 'marketplace-sale-warning',\n 'publisher-payouts-held',\n 'publisher-payouts-standard',\n // A review with no held item of its own (a payment, a seller review)\n // closed: cleared, or upheld.\n 'review-cleared',\n 'review-upheld',\n // Security locks, by scope, and their lifts.\n 'workspace-locked',\n 'workspace-unlocked',\n 'site-locked',\n 'site-unlocked',\n 'domain-locked',\n 'domain-unlocked',\n 'account-locked',\n 'account-unlocked',\n // One capability switched off for one workspace (AI, uploads, checkout…).\n 'feature-locked',\n 'feature-unlocked',\n // Staff canceled the workspace's subscription from its staff page. (A\n // lock's own cancellation, and the renewals and payouts a lock pauses and\n // its lift resumes, are told in the lock and lift notices themselves, as\n // what the lock affects — one email per staff action, not four.)\n 'subscription-canceled',\n] as const\n\nexport type RiskEventKind = (typeof RISK_EVENT_KINDS)[number]\n\n/** How loud a notice is. `urgent` kinds are emailed and alert staff at once. */\nexport type RiskNoticeSeverity = 'info' | 'warning' | 'urgent'\n\n/** The actions an OWNER or ADMIN is offered. None of them releases anything. */\nexport const RISK_OWNER_ACTION_IDS = [\n 'view-details',\n 'edit-and-resubmit',\n 'request-review',\n 'refund-order',\n 'keep-order',\n 'answer-dispute',\n 'update-payment-method',\n 'view-billing',\n 'view-holds',\n 'view-marketplace-sales',\n 'release-gift-cards',\n 'contact-support',\n] as const\nexport type RiskOwnerActionId = (typeof RISK_OWNER_ACTION_IDS)[number]\n\n/** The actions STAFF are offered: the real controls, deep-linked. */\nexport const RISK_STAFF_ACTION_IDS = [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-lock-site',\n 'staff-unlock',\n 'staff-cancel-subscription',\n 'staff-open-stripe',\n 'staff-view-workspace',\n] as const\nexport type RiskStaffActionId = (typeof RISK_STAFF_ACTION_IDS)[number]\n\n/**\n * Where each action goes, as a console path TEMPLATE. `{name}` placeholders\n * are filled by {@link resolveRiskActionHref} from the event; an action whose\n * placeholder has no value is dropped rather than rendered dead.\n *\n * Owner paths are in the stored-notification shape the console's\n * `normalizeNotificationLink` rewrites when followed: `/org/…` becomes the\n * reader's `/{orgSlug}/…` and `/{hostId}/…` becomes `/{orgSlug}/hosts/{sub}/…`.\n * `{itemPath}` is the held item's own page, supplied by the signal source.\n *\n * `risk-notice-routes.spec.ts` (console) resolves every template to a page\n * that exists under `apps/console/app`.\n */\nexport interface RiskActionDefinition {\n label: string\n /** What happens when it is followed, for the help page and a tooltip. */\n hint: string\n href: string\n}\n\nexport const RISK_OWNER_ACTIONS: Record<RiskOwnerActionId, RiskActionDefinition> = {\n 'view-details': {\n label: 'View details',\n hint: 'Opens the item this notice is about.',\n href: '{itemPath}',\n },\n 'edit-and-resubmit': {\n label: 'Edit and resubmit',\n hint: 'Opens the item so you can change it. A changed version is checked again on its own.',\n href: '{itemPath}',\n },\n 'request-review': {\n label: 'Request a review',\n hint: 'Sends a note to our review team on the same case. It does not release anything by itself.',\n href: '/org/settings/holds?notice={noticeId}',\n },\n 'refund-order': {\n label: 'Refund this order',\n hint: 'Opens the order, where Refund returns the payment to the card.',\n href: '{itemPath}',\n },\n 'keep-order': {\n label: 'Keep the order',\n hint: 'Opens the order. Nothing needs doing to keep it; fulfill it only once you are sure.',\n href: '{itemPath}',\n },\n 'answer-dispute': {\n label: 'Answer the dispute',\n hint: 'Opens the order with its dispute and the date your evidence is due.',\n href: '{itemPath}',\n },\n 'update-payment-method': {\n label: 'Update payment method',\n hint: 'Opens billing settings, where the card your subscription is paid from lives.',\n href: '/org/billing/settings',\n },\n 'view-billing': {\n label: 'View billing',\n hint: 'Opens your plan and subscription.',\n href: '/org/billing',\n },\n 'release-gift-cards': {\n label: 'Review gift cards',\n hint: 'Opens Gift cards under Promotions, where a held card can be released once you trust the payment.',\n href: '/{hostId}/products/promotions',\n },\n 'view-marketplace-sales': {\n label: 'View marketplace payouts',\n hint: 'Opens your marketplace payouts, where each sale and when it pays out are listed.',\n href: '/org/marketplace/payouts',\n },\n 'view-holds': {\n label: 'View holds and reviews',\n hint: 'Lists everything on this workspace that is held or under review, with its status.',\n href: '/org/settings/holds',\n },\n 'contact-support': {\n label: 'Contact support',\n hint: 'Opens a support ticket. If you cannot sign in, reply to this email instead.',\n href: '/org/support/tickets',\n },\n}\n\nexport const RISK_STAFF_ACTIONS: Record<RiskStaffActionId, RiskActionDefinition> = {\n 'staff-open-row': {\n label: 'Open in abuse queue',\n hint: 'The abuse-queue row with the evidence and any review requests.',\n href: '/admin/abuse-reports?report={reviewId}',\n },\n 'staff-release': {\n label: 'Waive / release',\n hint: 'Dismiss the row. For a held email or page this releases exactly the held content.',\n href: '/admin/abuse-reports?report={reviewId}&decide=dismissed',\n },\n 'staff-reject': {\n label: 'Reject',\n hint: 'Mark the row actioned. A held email or page stays unsent or unserved.',\n href: '/admin/abuse-reports?report={reviewId}&decide=actioned',\n },\n 'staff-lock-workspace': {\n label: 'Lock workspace',\n hint: 'Opens Lockdown with this workspace filled in.',\n href: '/admin/lockdown?scope=org&targetId={orgId}',\n },\n 'staff-lock-site': {\n label: 'Lock site',\n hint: 'Opens Lockdown with this site filled in.',\n href: '/admin/lockdown?scope=host&targetId={hostId}',\n },\n 'staff-unlock': {\n label: 'Review the lock',\n hint: 'Opens Lockdown on the locked target, where it can be lifted.',\n href: '/admin/lockdown?scope={lockScope}&targetId={lockTargetId}',\n },\n 'staff-cancel-subscription': {\n label: 'Cancel subscription',\n hint: \"The workspace's Subscription card on its staff page.\",\n href: '/admin/orgs/{orgId}#subscription',\n },\n 'staff-open-stripe': {\n label: 'Open in Stripe',\n hint: 'The charge, review, dispute or connected account in the Stripe Dashboard.',\n href: '{stripeUrl}',\n },\n 'staff-view-workspace': {\n label: 'View workspace',\n hint: \"The workspace's staff page.\",\n href: '/admin/orgs/{orgId}',\n },\n}\n\n/** One audience's half of a kind. */\nexport interface RiskNoticeCopy {\n /** Short and specific. Also the email subject. */\n title: string\n /** What we saw, on what, and when. */\n summary: string\n /** What it means for them. */\n meaning: string\n /** What to do next, in order. */\n steps: readonly string[]\n}\n\nexport interface RiskNoticeDefinition {\n kind: RiskEventKind\n severity: RiskNoticeSeverity\n /**\n * Whether the owners and admins are emailed as well as notified in the\n * console. The email is transactional account mail from the platform's own\n * sender: it ignores notification preferences and marketing consent, and\n * it reaches a locked workspace.\n */\n emailOwners: boolean\n /** Whether staff are alerted. False for events staff themselves caused. */\n alertStaff: boolean\n /**\n * Whether the notice always goes out, even while the workspace is over its\n * burst allowance. Locks, lifts and cancellations are never folded into a\n * digest: each one changes what the owner can do.\n */\n neverDigest: boolean\n /**\n * An owner can ask for a review. Only kinds with an abuse-queue row to\n * append to are reviewable.\n */\n reviewable: boolean\n /** The kinds staff decisions on this kind's row close it with. */\n closesWith?: { released: RiskEventKind; rejected: RiskEventKind }\n /** Also tell the managers of the site the event is on, not just the workspace's. */\n includeSiteManagers: boolean\n /** The help page section that explains it. */\n helpAnchor: string\n owner: RiskNoticeCopy & { actions: readonly RiskOwnerActionId[] }\n staff: Pick<RiskNoticeCopy, 'title' | 'summary'> & {\n actions: readonly RiskStaffActionId[]\n }\n}\n\n/**\n * The customer help page every notice links to. A path on the docs site;\n * the server prefixes the docs origin.\n */\nexport const RISK_NOTICE_HELP_PATH = '/help/holds-and-reviews'\n\n/**\n * Merge tokens a notice may use. The server fills each from the event; a\n * token the event does not carry renders as the fallback noted here, never\n * as a hole in a sentence.\n */\nexport const RISK_NOTICE_TOKENS = {\n 'workspace.name': 'The workspace name, or \"your workspace\".',\n 'item.label': 'What the notice is about, in the owner\\'s words: the campaign \"Spring sale\", the page /pricing, order 1042.',\n 'item.url': 'The absolute console link to the item.',\n occurredAt: 'When it happened, in UTC.',\n reference: 'The case reference staff know it by (HS-…, PF-…).',\n 'holds.url': \"The workspace's Holds & reviews page.\",\n 'help.url': 'The help page for holds and reviews.',\n 'support.email': \"The operator's support address.\",\n 'lock.message': 'The message staff wrote when they applied the lock.',\n 'lock.affected': 'What the lock or pause covers: sites, sessions, billing.',\n amount: 'The payment amount, when there is one.',\n 'evidence.dueBy': 'The date dispute evidence is due, when Stripe gave one.',\n 'staff.evidence': 'Staff only: what the screen or Stripe reported.',\n} as const\n\nexport type RiskNoticeToken = keyof typeof RISK_NOTICE_TOKENS\n\nconst ASK_FOR_REVIEW =\n 'If you think this is a mistake, choose Request a review and tell us about it. A person reads every request.'\n\nconst REVIEW_TIME =\n 'Reviews are usually answered within one business day. You will get a notice either way.'\n\nconst CANNOT_SIGN_IN =\n 'If you cannot sign in, reply to this email or write to {{support.email}} with the reference {{reference}}.'\n\n/**\n * How a locked ACCOUNT appeals (AGL-3420). It cannot sign in, so the way in\n * is mail: a reply to the notice reaches support (the notice's Reply-To),\n * and support answers from its own mailbox — which a ban does not refuse,\n * because a ban refuses what the platform sends, not what a person does.\n */\nconst APPEAL_BY_REPLY =\n 'If you believe this is a mistake, you can appeal: reply to this email, or write to {{support.email}} with the reference {{reference}}. Tell us anything that explains what happened. A person reviews every appeal and answers from that address.'\n\n/*\n * The catalog. Exhaustive by type: a kind added to RISK_EVENT_KINDS is a\n * compile error here until somebody writes what each audience is told.\n */\nexport const RISK_NOTICE_CATALOG: Readonly<Record<RiskEventKind, RiskNoticeDefinition>> = {\n 'email-held': {\n kind: 'email-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'email-released', rejected: 'email-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'An email is on hold for review',\n summary:\n 'Our automated safety review held {{item.label}} from {{workspace.name}} on {{occurredAt}} before it was sent.',\n meaning:\n 'This email was not sent. Nobody on your list received it, and nothing else on your account has changed.',\n steps: [\n 'Open the email and check its links, its sender name and its wording.',\n 'If you change it, it is checked again when it next sends.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Outbound email held for review — possible phishing',\n summary:\n '{{item.label}} from {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'email-released': {\n kind: 'email-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'Your held email was released',\n summary: 'Our review team released {{item.label}} on {{occurredAt}}.',\n meaning:\n 'A held campaign goes back on the schedule and sends shortly. An automated email sends the next time it runs.',\n steps: [\n 'Nothing to do. If you edit the email before it sends, the edited version is checked on its own.',\n ],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held email released',\n summary: '{{item.label}} from {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'email-rejected': {\n kind: 'email-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'A held email will not be sent',\n summary: 'After review, {{item.label}} was not approved on {{occurredAt}}.',\n meaning:\n 'This email will not be sent in its current form. A held campaign is canceled; an automated email step stays stopped.',\n steps: [\n 'Read our acceptable use rules before you send similar mail again.',\n 'If you think the decision is wrong, choose Request a review and explain what the email is for.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Held email rejected',\n summary: '{{item.label}} from {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'page-held': {\n kind: 'page-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'page-released', rejected: 'page-rejected' },\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'A published page is on hold for review',\n summary:\n 'Our automated safety review held the latest version of {{item.label}} on {{occurredAt}}.',\n meaning:\n 'Visitors still see the previous version of this page. If it has never been published before, visitors see a not-found page until the review is done.',\n steps: [\n 'Open the page and check its links, embeds and any fields that ask visitors for information.',\n 'If you change and publish it again, the new version is checked on its own.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Published page held for review — possible phishing',\n summary:\n '{{item.label}} of {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'page-released': {\n kind: 'page-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'Your held page is live',\n summary: 'Our review team released {{item.label}} on {{occurredAt}}.',\n meaning: 'Visitors now see the version that was held.',\n steps: ['Nothing to do. Open the page to confirm it looks right.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held page released',\n summary: '{{item.label}} of {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'page-flagged': {\n kind: 'page-flagged',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'page-flagged',\n owner: {\n title: 'A live page is being reviewed',\n summary:\n 'Our automated safety review flagged {{item.label}} on {{occurredAt}}. The page is still live.',\n meaning:\n 'Visitors still see the page while a person looks. If you did not publish what is on it, someone else may have access to your account.',\n steps: [\n 'Open the page and check its links, embeds and any fields that ask visitors for information.',\n 'If you did not make these changes, change your password, remove members you do not recognize, and contact support.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Live page flagged — possible phishing or a compromised account',\n summary:\n '{{item.label}} of {{workspace.name}} is live and was flagged on {{occurredAt}}. {{staff.evidence}} It is still serving; lock the site if it is impersonation. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'page-rejected': {\n kind: 'page-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'A held page will not be published',\n summary: 'After review, the held version of {{item.label}} was not approved on {{occurredAt}}.',\n meaning:\n 'Visitors keep seeing the previous version, or a not-found page if there is none. Publishing the same content again is held again.',\n steps: [\n 'Change the page and publish a new version, or restore an earlier version from its history.',\n 'If you think the decision is wrong, choose Request a review and explain what the page is for.',\n ],\n actions: ['edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Held page rejected',\n summary: '{{item.label}} of {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-site', 'staff-view-workspace'],\n },\n },\n 'listing-held': {\n kind: 'listing-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'listing-released', rejected: 'listing-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'A marketplace submission is on hold for review',\n summary:\n 'Our automated safety review held {{item.label}} from {{workspace.name}} on {{occurredAt}} before it was listed.',\n meaning: 'Nothing was published. Buyers cannot see or install it while it waits.',\n steps: [\n 'Check its name, description, links and any fields it asks people to fill in.',\n 'If you change it, the new submission is checked on its own.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Marketplace submission held for review — possible phishing',\n summary:\n '{{item.label}} from publisher workspace {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'listing-released': {\n kind: 'listing-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'Your marketplace submission was released',\n summary: 'Our review team released {{item.label}} on {{occurredAt}}.',\n meaning: 'It was not published automatically.',\n steps: ['Submit it again; it will go through this time.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held marketplace submission released',\n summary: '{{item.label}} from {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'listing-rejected': {\n kind: 'listing-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'A marketplace submission will not be listed',\n summary: 'After review, {{item.label}} was not approved on {{occurredAt}}.',\n meaning: 'It will not be published in its current form. Submitting the same content again is held again.',\n steps: [\n 'Read the marketplace listing rules before you submit something similar.',\n 'If you think the decision is wrong, choose Request a review and explain what it is for.',\n ],\n actions: ['request-review', 'contact-support'],\n },\n staff: {\n title: 'Held marketplace submission rejected',\n summary: '{{item.label}} from {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'domain-flagged': {\n kind: 'domain-flagged',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'domain-cleared', rejected: 'domain-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'A domain you added is being reviewed',\n summary: '{{item.label}} was added to {{workspace.name}} on {{occurredAt}} and is waiting on a routine review.',\n meaning:\n 'The domain stays connected while we look. Email sent from it may wait for the review to finish.',\n steps: [\n 'Nothing is needed if the domain and the name on it are yours.',\n 'To speed it up, choose Request a review and tell us who owns the domain and what it is for.',\n REVIEW_TIME,\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Domain flagged — possible brand impersonation',\n summary:\n '{{item.label}} was added by {{workspace.name}} on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'domain-cleared': {\n kind: 'domain-cleared',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'Your domain review is complete',\n summary: '{{item.label}} was reviewed and cleared on {{occurredAt}}.',\n meaning: 'The domain works as normal. Email that was waiting on it sends on its next attempt.',\n steps: ['Nothing to do.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Flagged domain cleared',\n summary: '{{item.label}} on {{workspace.name}} was cleared. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'domain-rejected': {\n kind: 'domain-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'A domain on your workspace was not approved',\n summary: 'After review, {{item.label}} was not approved on {{occurredAt}}.',\n meaning:\n 'Email from this domain will not be sent, and pages served on it may be restricted.',\n steps: [\n 'Remove the domain from your workspace, or show us that it is yours.',\n 'If you think the decision is wrong, choose Request a review with proof of ownership.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Flagged domain rejected',\n summary: '{{item.label}} on {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'billing-payment-flagged': {\n kind: 'billing-payment-flagged',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'billing-payment-flagged',\n owner: {\n title: 'A payment on your subscription needs attention',\n summary:\n 'On {{occurredAt}}, a subscription payment of {{amount}} for {{workspace.name}} was flagged for a fraud check.',\n meaning:\n 'The payment may be reversed by the cardholder\\'s bank. If it is, your subscription may need a new payment method, and your plan can change.',\n steps: [\n 'If you made this payment, choose Request a review and confirm it, so we can answer the bank.',\n 'Check that the card on your account is yours and current.',\n 'If you did not make this payment, contact support now.',\n ],\n actions: ['request-review', 'update-payment-method', 'view-billing', 'contact-support'],\n },\n staff: {\n title: 'Platform billing fraud signal',\n summary:\n '{{staff.evidence}} Workspace {{workspace.name}}, {{amount}}, on {{occurredAt}}. Nothing has been refunded or canceled. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-cancel-subscription',\n 'staff-lock-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'link-blocked': {\n kind: 'link-blocked',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'link-blocked',\n owner: {\n title: 'A link on your store was blocked',\n summary:\n 'On {{occurredAt}}, we stopped sending anyone to {{item.label}}, because the address looks like another company\\'s website.',\n meaning: 'Nobody who follows that link is sent there. Everything else on your store works as normal.',\n steps: [\n 'Replace it with a file from your media library or a link on your own domain.',\n 'If the address really is yours, choose Request a review and tell us about it.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Commerce link flagged — possible brand impersonation',\n summary:\n '{{item.label}} on {{workspace.name}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-site',\n 'staff-view-workspace',\n ],\n },\n },\n 'card-testing': {\n kind: 'card-testing',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'card-testing',\n owner: {\n title: 'Unusual checkout activity on your site',\n summary:\n 'On {{occurredAt}}, the checkout on {{item.label}} saw an unusual burst of payment attempts, which can be someone testing stolen cards.',\n meaning:\n 'Checkout is still open. Repeated attempts from one source are being slowed. Payments from stolen cards may be reversed by the cardholder\\'s bank later.',\n steps: [\n 'Review your recent orders before you fulfill them.',\n 'Refund any order you do not recognize.',\n 'If this was a launch or a sale, nothing is needed; you can tell us with Request a review.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Card-testing velocity on a site',\n summary:\n '{{item.label}} of {{workspace.name}}. {{staff.evidence}} Nothing has been refused site-wide or refunded. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'gift-card-hold': {\n kind: 'gift-card-hold',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'gift-card-hold',\n owner: {\n title: 'Gift cards from an order are on hold',\n summary:\n 'On {{occurredAt}}, the gift cards bought with {{item.label}} were put on hold because the payment for it is in question.',\n meaning:\n 'They cannot be redeemed for now. Their balance is kept. If the payment is refunded or the dispute is lost, the balance is voided for you.',\n steps: [\n 'Check the order and the buyer.',\n 'If you are satisfied the payment is genuine, release the cards from Gift cards under Promotions.',\n 'If you are not, refund the order.',\n ],\n actions: ['release-gift-cards', 'refund-order', 'contact-support'],\n },\n staff: {\n title: 'Gift cards frozen on a questioned payment',\n summary: '{{item.label}} on {{workspace.name}}. {{staff.evidence}}',\n actions: ['staff-view-workspace', 'staff-lock-site'],\n },\n },\n 'sale-fraud-warning': {\n kind: 'sale-fraud-warning',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-fraud-warning',\n owner: {\n title: 'A payment you received may be fraudulent',\n summary:\n 'On {{occurredAt}}, the card issuer reported the payment for {{item.label}} ({{amount}}) as possibly not made by the cardholder.',\n meaning:\n 'This payment may be reversed by the cardholder\\'s bank. It is not a chargeback yet. Nothing has been refunded or canceled.',\n steps: [\n 'Hold anything not yet shipped or delivered until you are sure the buyer is genuine.',\n 'Refunding now usually prevents a chargeback and its fee.',\n 'If you know the buyer and the sale is genuine, you can keep the order.',\n ],\n actions: ['refund-order', 'keep-order', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Early fraud warning on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace', 'staff-lock-site'],\n },\n },\n 'sale-payment-review': {\n kind: 'sale-payment-review',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-payment-review',\n owner: {\n title: 'A payment you received is on hold for review',\n summary: 'On {{occurredAt}}, the payment for {{item.label}} ({{amount}}) was held for a fraud review.',\n meaning:\n 'The payment has not reached your balance yet and may be refunded if it is not approved. Nothing has been refunded or canceled.',\n steps: [\n 'Hold anything not yet shipped or delivered until the payment clears.',\n 'If you know the buyer is not genuine, refund the order.',\n 'If you know the buyer, keep the order; the review usually clears on its own.',\n ],\n actions: ['refund-order', 'keep-order', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Payment review on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'sale-dispute': {\n kind: 'sale-dispute',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-dispute',\n owner: {\n title: 'A customer disputed a payment',\n summary:\n 'On {{occurredAt}}, the cardholder disputed the payment for {{item.label}} ({{amount}}) with their bank.',\n meaning:\n 'The payment may be reversed by the cardholder\\'s bank. An unanswered dispute is decided for the cardholder. Your evidence is due by {{evidence.dueBy}}.',\n steps: [\n 'Open the order and gather what shows the sale was genuine: receipts, delivery tracking, messages with the buyer.',\n 'Send your evidence before {{evidence.dueBy}}. Contact support if you need help submitting it.',\n 'If the buyer is right, accept the dispute instead of answering it.',\n ],\n actions: ['answer-dispute', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Dispute on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. Evidence due {{evidence.dueBy}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'seller-review': {\n kind: 'seller-review',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'seller-review',\n owner: {\n title: 'We are reviewing recent payments on your store',\n summary:\n 'On {{occurredAt}}, our team opened a routine review of recent card payments taken by {{workspace.name}}.',\n meaning:\n 'Your store keeps selling while we look. We may contact you for information about your recent orders.',\n steps: [\n 'Check your recent orders and refund any you believe were not placed by the cardholder.',\n 'Choose Request a review to tell us about your business and your customers; it helps the review finish sooner.',\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-holds', 'contact-support'],\n },\n staff: {\n title: 'Seller fraud pattern on one connected account',\n summary:\n '{{staff.evidence}} Workspace {{workspace.name}}. Nothing has been refunded, canceled or paused. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'marketplace-sale-review': {\n kind: 'marketplace-sale-review',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'marketplace-sale-review',\n owner: {\n title: 'A marketplace sale is under review',\n summary: 'On {{occurredAt}}, our team opened a routine review of {{item.label}} ({{amount}}).',\n meaning:\n 'The sale is recorded as usual, and its payout may take longer than normal. Nothing has been refunded.',\n steps: [\n 'Nothing is needed from you.',\n 'To tell us about the buyer or the sale, choose Request a review.',\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Marketplace sale flagged — possible self-dealing or card fraud',\n summary:\n '{{item.label}} ({{amount}}) paid publisher workspace {{workspace.name}}. {{staff.evidence}} Nothing has been refunded or paused. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'marketplace-sale-warning': {\n kind: 'marketplace-sale-warning',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-sale-review',\n owner: {\n title: 'A marketplace sale may be reversed',\n summary:\n 'On {{occurredAt}}, the payment for {{item.label}} was reported as possibly not made by the cardholder, or held for a fraud check.',\n meaning:\n 'This payment may be reversed by the cardholder\\'s bank. If it is, your share of it is taken back from your payouts. Nothing has been refunded yet.',\n steps: [\n 'Nothing is needed from you: the marketplace handles the payment with the buyer\\'s bank.',\n 'If you know the buyer, contact support; it can help us answer the bank.',\n ],\n actions: ['view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Card signal on a marketplace sale',\n summary: '{{item.label}} paid publisher workspace {{workspace.name}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'publisher-payouts-held': {\n kind: 'publisher-payouts-held',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-payouts',\n owner: {\n title: 'Your marketplace payouts are on an extended schedule',\n summary: 'On {{occurredAt}}, payouts for {{workspace.name}}\\'s marketplace sales moved to an extended schedule.',\n meaning:\n 'Payouts to new publishers wait for a period before they reach your bank. Your sales are recorded as usual and pay out automatically when the period ends.',\n steps: ['Nothing to do. You will get a notice when payouts return to the standard schedule.'],\n actions: ['view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Publisher payouts on the extended schedule',\n summary: 'Publisher workspace {{workspace.name}} payouts moved to the extended schedule.',\n actions: ['staff-view-workspace'],\n },\n },\n 'publisher-payouts-standard': {\n kind: 'publisher-payouts-standard',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-payouts',\n owner: {\n title: 'Your marketplace payouts are back on the standard schedule',\n summary: 'On {{occurredAt}}, payouts for {{workspace.name}}\\'s marketplace sales returned to the standard schedule.',\n meaning: 'Your sales now pay out on your payout account\\'s standard schedule.',\n steps: ['Nothing to do.'],\n actions: ['view-marketplace-sales'],\n },\n staff: {\n title: 'Publisher payouts back on the standard schedule',\n summary: 'Publisher workspace {{workspace.name}} payouts returned to the standard schedule.',\n actions: ['staff-view-workspace'],\n },\n },\n 'review-cleared': {\n kind: 'review-cleared',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'requesting-a-review',\n owner: {\n title: 'Our review is complete',\n summary: 'On {{occurredAt}}, our team finished reviewing {{item.label}} and closed it with no action.',\n meaning: 'Nothing on your account changes because of it.',\n steps: ['Nothing to do.'],\n actions: ['view-holds'],\n },\n staff: {\n title: 'Review closed with no action',\n summary: '{{item.label}} on {{workspace.name}} was dismissed. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'review-upheld': {\n kind: 'review-upheld',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'requesting-a-review',\n owner: {\n title: 'Our review found a problem',\n summary: 'On {{occurredAt}}, our team finished reviewing {{item.label}} and took action on it.',\n meaning:\n 'You may receive a separate notice about what changed on your account, such as a lock or a canceled subscription.',\n steps: [\n 'Read any other notices you received today; they say what changed.',\n 'If you think the decision is wrong, choose Request a review or contact support with the reference {{reference}}.',\n ],\n actions: ['request-review', 'view-holds', 'contact-support'],\n },\n staff: {\n title: 'Review closed with action',\n summary: '{{item.label}} on {{workspace.name}} was actioned. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'workspace-locked': {\n kind: 'workspace-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{workspace.name}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Read the message above; it says what we need from you.',\n CANNOT_SIGN_IN,\n 'Tell us who you are, what the workspace is for, and anything that explains what happened. A person reads every appeal.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace locked',\n summary: '{{workspace.name}} was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'workspace-unlocked': {\n kind: 'workspace-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{workspace.name}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: [\n 'Sign in again; sessions that were signed out stay signed out.',\n 'Check your sites, scheduled sends and billing. Anything that was canceled stays canceled until you restart it.',\n ],\n actions: ['view-holds', 'view-billing', 'contact-support'],\n },\n staff: {\n title: 'Workspace lock lifted',\n summary: '{{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'site-locked': {\n kind: 'site-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A site on {{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{item.label}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Read the message above; it says what we need from you.',\n 'Contact support to appeal, with the reference {{reference}}. A person reads every appeal.',\n CANNOT_SIGN_IN,\n ],\n actions: ['contact-support', 'view-holds'],\n },\n staff: {\n title: 'Site locked',\n summary: '{{item.label}} of {{workspace.name}} was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'site-unlocked': {\n kind: 'site-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A site on {{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{item.label}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Open the site and check that its pages, forms and checkout work as you expect.'],\n actions: ['view-details', 'contact-support'],\n },\n staff: {\n title: 'Site lock lifted',\n summary: '{{item.label}} of {{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'domain-locked': {\n kind: 'domain-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A domain on {{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{item.label}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Read the message above; it says what we need from you.',\n 'Contact support to appeal, with the reference {{reference}}.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Domain locked',\n summary: '{{item.label}} of {{workspace.name}} was locked on {{occurredAt}}.',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'domain-unlocked': {\n kind: 'domain-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A domain on {{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{item.label}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Visit the domain to confirm it serves your site again.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Domain lock lifted',\n summary: '{{item.label}} of {{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'account-locked': {\n kind: 'account-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Your account has been locked',\n summary: 'On {{occurredAt}}, our team locked your {{brand.productName}} account. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Read the message above; it says what we need from you.',\n APPEAL_BY_REPLY,\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Account locked',\n summary: 'An account was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock'],\n },\n },\n 'account-unlocked': {\n kind: 'account-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Your account has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on your {{brand.productName}} account.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Sign in again. If anything still does not work, contact support.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Account lock lifted',\n summary: 'An account was unlocked on {{occurredAt}}.',\n actions: ['staff-unlock'],\n },\n },\n 'feature-locked': {\n kind: 'feature-locked',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{item.label}} is paused on {{workspace.name}}',\n summary: 'On {{occurredAt}}, our team paused {{item.label}} for {{workspace.name}}. The message from our team: {{lock.message}}',\n meaning: 'Everything else on your workspace keeps working. {{lock.affected}}',\n steps: [\n 'Read the message above; it says what we need from you.',\n 'Contact support with the reference {{reference}} if you have questions.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace feature paused',\n summary: '{{item.label}} was paused for {{workspace.name}} on {{occurredAt}}.',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'feature-unlocked': {\n kind: 'feature-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{item.label}} is back on {{workspace.name}}',\n summary: 'On {{occurredAt}}, our team turned {{item.label}} back on for {{workspace.name}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Nothing to do.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace feature restored',\n summary: '{{item.label}} was restored for {{workspace.name}} on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'subscription-canceled': {\n kind: 'subscription-canceled',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'subscription-canceled',\n owner: {\n title: 'The subscription for {{workspace.name}} was canceled',\n summary: 'On {{occurredAt}}, our team canceled the subscription for {{workspace.name}}.',\n meaning: 'What changes: {{lock.affected}}',\n steps: [\n 'Export anything you need from your workspace.',\n 'Contact support if you believe this was a mistake, with the reference {{reference}}.',\n ],\n actions: ['view-billing', 'contact-support'],\n },\n staff: {\n title: 'Subscription canceled by staff',\n summary: 'The subscription for {{workspace.name}} was canceled on {{occurredAt}}.',\n actions: ['staff-cancel-subscription', 'staff-view-workspace'],\n },\n },\n}\n\n/**\n * The kinds whose email wears the WORKSPACE's brand: routine notices about\n * the workspace's own customers' payments, which read as the workspace's own\n * operations. Every other kind — a hold, a lock, a lift, a cancellation, a\n * review — is the platform acting, and is sent in the platform's brand.\n */\nexport const RISK_NOTICE_WORKSPACE_BRANDED: ReadonlySet<RiskEventKind> = new Set<RiskEventKind>([\n 'sale-fraud-warning',\n 'sale-payment-review',\n 'sale-dispute',\n 'gift-card-hold',\n 'marketplace-sale-warning',\n])\n\n/**\n * The kinds that CLOSE another: a release, a rejection, a review's end. A\n * closing notice never re-stamps its row, so the row keeps naming the kind\n * it was opened as — and a second decision closes it again correctly.\n */\nexport const RISK_NOTICE_CLOSING_KINDS: ReadonlySet<RiskEventKind> = new Set<RiskEventKind>(\n Object.values(RISK_NOTICE_CATALOG).flatMap((definition) =>\n definition.closesWith ? [definition.closesWith.released, definition.closesWith.rejected] : [],\n ),\n)\n\n/** The catalog entry for a kind. */\nexport function riskNoticeDefinition(kind: RiskEventKind): RiskNoticeDefinition {\n return RISK_NOTICE_CATALOG[kind]\n}\n\nexport function isRiskEventKind(value: unknown): value is RiskEventKind {\n return typeof value === 'string' && (RISK_EVENT_KINDS as readonly string[]).includes(value)\n}\n\n/** The values a notice is rendered with. Every value is optional. */\nexport type RiskNoticeValues = Partial<Record<RiskNoticeToken | 'brand.productName', string | null | undefined>>\n\n/**\n * What a token renders as when the event did not carry it: always words, so\n * a sentence never has a hole in it.\n */\nconst TOKEN_FALLBACKS: Partial<Record<RiskNoticeToken | 'brand.productName', string>> = {\n 'workspace.name': 'your workspace',\n 'item.label': 'an item on your workspace',\n occurredAt: 'a recent date',\n reference: 'shown on this notice',\n 'support.email': 'our support team',\n 'lock.message': 'None was given.',\n 'lock.affected': 'see your account for details.',\n amount: 'an amount shown on the payment',\n 'evidence.dueBy': 'the date shown on the order',\n 'staff.evidence': '',\n 'brand.productName': 'the platform',\n}\n\n/** Fill `{{token}}`s from `values`, falling back to words, never to a hole. */\nexport function renderRiskNoticeText(template: string, values: RiskNoticeValues): string {\n return template\n .replace(/\\{\\{\\s*([\\w.]+)\\s*\\}\\}/g, (_match, token: string) => {\n const value = values[token as RiskNoticeToken]\n if (typeof value === 'string' && value.trim()) return value.trim()\n return TOKEN_FALLBACKS[token as RiskNoticeToken] ?? ''\n })\n .replace(/[ \\t]{2,}/g, ' ')\n .trim()\n}\n\n/** The values an action href may use. */\nexport interface RiskActionParams {\n itemPath?: string | null\n noticeId?: string | null\n reviewId?: string | null\n orgId?: string | null\n hostId?: string | null\n stripeUrl?: string | null\n lockScope?: string | null\n lockTargetId?: string | null\n}\n\n/**\n * An action's href with its placeholders filled, or null when one of them\n * has no value — an action that would lead nowhere is not offered.\n */\nexport function resolveRiskActionHref(\n action: RiskActionDefinition,\n params: RiskActionParams,\n): string | null {\n let missing = false\n const href = action.href.replace(/\\{(\\w+)\\}/g, (_match, name: string) => {\n const value = params[name as keyof RiskActionParams]\n if (typeof value !== 'string' || !value) {\n missing = true\n return ''\n }\n // A whole-path placeholder is taken as written; a path segment or query\n // value is encoded.\n return name === 'itemPath' || name === 'stripeUrl' ? value : encodeURIComponent(value)\n })\n if (missing) return null\n if (href.startsWith('https://')) return href\n return href.startsWith('/') ? href : null\n}\n\n/** One action, ready to render. */\nexport interface ResolvedRiskAction {\n id: RiskOwnerActionId | RiskStaffActionId\n label: string\n hint: string\n href: string\n}\n\n/** A kind's owner actions that lead somewhere, in catalog order. */\nexport function resolveOwnerRiskActions(\n kind: RiskEventKind,\n params: RiskActionParams,\n): ResolvedRiskAction[] {\n return RISK_NOTICE_CATALOG[kind].owner.actions.flatMap((id) => {\n const definition = RISK_OWNER_ACTIONS[id]\n const href = resolveRiskActionHref(definition, params)\n return href ? [{ id, label: definition.label, hint: definition.hint, href }] : []\n })\n}\n\n/** A kind's staff actions that lead somewhere, in catalog order. */\nexport function resolveStaffRiskActions(\n kind: RiskEventKind,\n params: RiskActionParams,\n): ResolvedRiskAction[] {\n return RISK_NOTICE_CATALOG[kind].staff.actions.flatMap((id) => {\n const definition = RISK_STAFF_ACTIONS[id]\n const href = resolveRiskActionHref(definition, params)\n return href ? [{ id, label: definition.label, hint: definition.hint, href }] : []\n })\n}\n\n/** An owner notice as plain text: title, summary, meaning, numbered steps. */\nexport function renderOwnerRiskNotice(\n kind: RiskEventKind,\n values: RiskNoticeValues,\n): { title: string; summary: string; meaning: string; steps: string[] } {\n const copy = RISK_NOTICE_CATALOG[kind].owner\n return {\n title: renderRiskNoticeText(copy.title, values),\n summary: renderRiskNoticeText(copy.summary, values),\n meaning: renderRiskNoticeText(copy.meaning, values),\n steps: copy.steps.map((step) => renderRiskNoticeText(step, values)),\n }\n}\n\n/** A staff alert as plain text. */\nexport function renderStaffRiskNotice(\n kind: RiskEventKind,\n values: RiskNoticeValues,\n): { title: string; summary: string } {\n const copy = RISK_NOTICE_CATALOG[kind].staff\n return {\n title: renderRiskNoticeText(copy.title, values),\n summary: renderRiskNoticeText(copy.summary, values),\n }\n}\n\n/** The System emails catalog key a kind's owner email is designed under. */\nexport function riskNoticeEmailKey(kind: RiskEventKind): string {\n return `risk-${kind}`\n}\n\n/** The key the burst digest is designed under. */\nexport const RISK_NOTICE_DIGEST_EMAIL_KEY = 'risk-digest'\n\n/**\n * The kind an abuse-queue row is about, so the staff queue renders the\n * catalog's text for EVERY row a risk source filed — including rows filed\n * before the row carried its notice. The stamp `notifyRiskEvent` writes\n * (`riskNotice.kind`) wins; otherwise the row's own shape says it. Null for\n * a row from the public report form, which is not a risk event.\n */\nexport function riskKindForAbuseRow(row: {\n source?: unknown\n heldSend?: { kind?: unknown } | null\n riskNotice?: { kind?: unknown } | null\n}): RiskEventKind | null {\n const stamped = row.riskNotice?.kind\n if (isRiskEventKind(stamped)) return stamped\n switch (row.source) {\n case 'outbound-screen':\n if (row.heldSend?.kind === 'page') return 'page-held'\n if (row.heldSend?.kind === 'listing') return 'listing-held'\n return row.heldSend ? 'email-held' : 'domain-flagged'\n case 'stripe-fraud-signal':\n return 'billing-payment-flagged'\n case 'stripe-seller-fraud-pattern':\n return 'seller-review'\n case 'marketplace-sale-risk':\n return 'marketplace-sale-review'\n case 'payment-velocity':\n return 'card-testing'\n default:\n return null\n }\n}\n"],"names":["RISK_EVENT_KINDS","RISK_OWNER_ACTION_IDS","RISK_STAFF_ACTION_IDS","RISK_OWNER_ACTIONS","label","hint","href","RISK_STAFF_ACTIONS","RISK_NOTICE_HELP_PATH","RISK_NOTICE_TOKENS","occurredAt","reference","amount","ASK_FOR_REVIEW","REVIEW_TIME","CANNOT_SIGN_IN","APPEAL_BY_REPLY","RISK_NOTICE_CATALOG","kind","severity","emailOwners","alertStaff","neverDigest","reviewable","closesWith","released","rejected","includeSiteManagers","helpAnchor","owner","title","summary","meaning","steps","actions","staff","RISK_NOTICE_WORKSPACE_BRANDED","Set","RISK_NOTICE_CLOSING_KINDS","Object","values","flatMap","definition","riskNoticeDefinition","isRiskEventKind","value","includes","TOKEN_FALLBACKS","renderRiskNoticeText","template","replace","_match","token","trim","resolveRiskActionHref","action","params","missing","name","encodeURIComponent","startsWith","resolveOwnerRiskActions","id","resolveStaffRiskActions","renderOwnerRiskNotice","copy","map","step","renderStaffRiskNotice","riskNoticeEmailKey","RISK_NOTICE_DIGEST_EMAIL_KEY","riskKindForAbuseRow","row","stamped","riskNotice","source","heldSend"],"mappings":"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;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAiB;QACrEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACApB;gBACAC;aACD;YACDoB,SAAS;gBAAC;gBAAgB;gBAAqB;gBAAkB;aAAkB;QACrF;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,kBAAkB;QAChBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SACE;YACFC,OAAO;gBACL;aACD;YACDC,SAAS;gBAAC;aAAe;QAC3B;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;aAAuB;QACrD;IACF;IACA,kBAAkB;QAChBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SACE;YACFC,OAAO;gBACL;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAkB;aAAkB;QAChE;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;gBAAwB;aAAuB;QAC7E;IACF;IACA,aAAa;QACXhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAiBC,UAAU;QAAgB;QACnEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACApB;gBACAC;aACD;YACDoB,SAAS;gBAAC;gBAAgB;gBAAqB;gBAAkB;aAAkB;QACrF;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,iBAAiB;QACfhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SAAS;YACTC,OAAO;gBAAC;aAA0D;YAClEC,SAAS;gBAAC;aAAe;QAC3B;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;aAAuB;QACrD;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACApB;gBACAC;aACD;YACDoB,SAAS;gBAAC;gBAAgB;gBAAqB;gBAAkB;aAAkB;QACrF;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,iBAAiB;QACfhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SACE;YACFC,OAAO;gBACL;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAqB;gBAAkB;aAAkB;QACrE;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;gBAAmB;aAAuB;QACxE;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAoBC,UAAU;QAAmB;QACzEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SAAS;YACTC,OAAO;gBACL;gBAC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;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAkB;aAAkB;QAChE;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,kBAAkB;QAChBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAsB;gBAAgB;aAAkB;QACpE;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAwB;aAAkB;QACtD;IACF;IACA,sBAAsB;QACpBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAc;gBAAgB;aAAkB;QAC5E;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAqB;gBAAwB;aAAkB;QAC3E;IACF;IACA,uBAAuB;QACrBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAc;gBAAgB;aAAkB;QAC5E;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAqB;aAAuB;QACxD;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAkB;gBAAgB;aAAkB;QAChE;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAqB;aAAuB;QACxD;IACF;IACA,iBAAiB;QACfhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACAnB;aACD;YACDoB,SAAS;gBAAC;gBAAkB;gBAAc;aAAkB;QAC9D;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,2BAA2B;QACzBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SACE;YACFC,OAAO;gBACL;gBACA;gBACAnB;aACD;YACDoB,SAAS;gBAAC;gBAAkB;gBAA0B;aAAkB;QAC1E;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,4BAA4B;QAC1BhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;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"}
1
+ {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/risk-notice-catalog.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * THE RISK NOTICE CATALOG (AGL-3368).\n *\n * Every event where the platform holds, flags, locks or pauses something on\n * a workspace, and what each audience is told about it. One entry per kind,\n * read by three consumers that must never disagree:\n *\n * - `notifyRiskEvent` (`@aglyn/tenant-data-admin/server/risk-notice`), which\n * renders the entry into the in-app notification, the owner email and the\n * staff alert;\n * - the console: the workspace's Holds & reviews page renders an owner's\n * notices from it, and the staff abuse queue renders a row's staff half;\n * - the customer help page and the System emails catalog, which list every\n * kind.\n *\n * ## Two audiences, two vocabularies\n *\n * The OWNER half is read by the workspace's owners and admins — and a\n * fraud actor is a workspace owner too. So it describes the OUTCOME and the\n * way to a human (what was held, what that means, how to ask for a review),\n * never the detection: no rule, no threshold, no brand the screen matched,\n * no count of anything. `risk-notice-catalog.spec.ts` sweeps it for those.\n *\n * The STAFF half is read by staff only and names the evidence plainly.\n *\n * ## Owners can never release\n *\n * No owner action releases a hold or lifts a lock. An owner's \"waive\" is a\n * review request, which appends a note to the same abuse-queue row. The\n * spec pins that no owner action id is a staff decision.\n *\n * ## Text is written against merge tokens\n *\n * `{{item.label}}`, `{{workspace.name}}`, `{{brand.productName}}` and the rest\n * are filled at send time. The same strings seed the System emails catalog\n * entry each kind gets (`risk-notice-emails.ts`), so staff can edit the email\n * a kind sends on the System emails page.\n *\n * Pure and dependency-free: the console, the docs, the specs and the server\n * all import it.\n *=========================================*/\n\n/** Every kind of risk event the platform tells people about. */\nexport const RISK_EVENT_KINDS = [\n // Outbound email held by the safety screen: a campaign, an automation\n // step, any site email at the send seam, an outreach message.\n 'email-held',\n 'email-released',\n 'email-rejected',\n // A published page held before a visitor saw it.\n 'page-held',\n 'page-released',\n 'page-rejected',\n // A page ALREADY LIVE that the safety review flagged: it keeps serving,\n // and staff look — the account may have been compromised.\n 'page-flagged',\n // A marketplace submission (a listing, a publisher profile) held before\n // it was listed.\n 'listing-held',\n 'listing-released',\n 'listing-rejected',\n // A custom site domain or sending domain flagged for a look.\n 'domain-flagged',\n 'domain-cleared',\n 'domain-rejected',\n // A fraud signal on the workspace's own subscription payment.\n 'billing-payment-flagged',\n // A link a merchant configured (a download, a feed, a supplier hook) that\n // wears another brand's name, refused wherever it is followed.\n 'link-blocked',\n // A burst of card payments on one site: possibly card testing.\n 'card-testing',\n // Gift cards an order bought, frozen while its payment is in question.\n 'gift-card-hold',\n // A fraud signal on a sale the workspace took from its own customer.\n 'sale-fraud-warning',\n 'sale-payment-review',\n 'sale-dispute',\n // Several of a seller's sales drew fraud reports: staff are reviewing.\n 'seller-review',\n // A marketplace sale a publisher received is under review, a card signal\n // arrived on one, and a new publisher's payouts wait (or stop waiting).\n 'marketplace-sale-review',\n 'marketplace-sale-warning',\n 'publisher-payouts-held',\n 'publisher-payouts-standard',\n // A review with no held item of its own (a payment, a seller review)\n // closed: cleared, or upheld.\n 'review-cleared',\n 'review-upheld',\n // Security locks, by scope, and their lifts.\n 'workspace-locked',\n 'workspace-unlocked',\n 'site-locked',\n 'site-unlocked',\n 'domain-locked',\n 'domain-unlocked',\n 'account-locked',\n 'account-unlocked',\n // One capability switched off for one workspace (AI, uploads, checkout…).\n 'feature-locked',\n 'feature-unlocked',\n // Staff canceled the workspace's subscription from its staff page. (A\n // lock's own cancellation, and the renewals and payouts a lock pauses and\n // its lift resumes, are told in the lock and lift notices themselves, as\n // what the lock affects — one email per staff action, not four.)\n 'subscription-canceled',\n] as const\n\nexport type RiskEventKind = (typeof RISK_EVENT_KINDS)[number]\n\n/** How loud a notice is. `urgent` kinds are emailed and alert staff at once. */\nexport type RiskNoticeSeverity = 'info' | 'warning' | 'urgent'\n\n/** The actions an OWNER or ADMIN is offered. None of them releases anything. */\nexport const RISK_OWNER_ACTION_IDS = [\n 'view-details',\n 'edit-and-resubmit',\n 'request-review',\n 'refund-order',\n 'keep-order',\n 'answer-dispute',\n 'update-payment-method',\n 'view-billing',\n 'view-holds',\n 'view-marketplace-sales',\n 'release-gift-cards',\n 'contact-support',\n] as const\nexport type RiskOwnerActionId = (typeof RISK_OWNER_ACTION_IDS)[number]\n\n/** The actions STAFF are offered: the real controls, deep-linked. */\nexport const RISK_STAFF_ACTION_IDS = [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-lock-site',\n 'staff-unlock',\n 'staff-cancel-subscription',\n 'staff-open-stripe',\n 'staff-view-workspace',\n] as const\nexport type RiskStaffActionId = (typeof RISK_STAFF_ACTION_IDS)[number]\n\n/**\n * Where each action goes, as a console path TEMPLATE. `{name}` placeholders\n * are filled by {@link resolveRiskActionHref} from the event; an action whose\n * placeholder has no value is dropped rather than rendered dead.\n *\n * Owner paths are in the stored-notification shape the console's\n * `normalizeNotificationLink` rewrites when followed: `/org/…` becomes the\n * reader's `/{orgSlug}/…` and `/{hostId}/…` becomes `/{orgSlug}/hosts/{sub}/…`.\n * `{itemPath}` is the held item's own page, supplied by the signal source.\n *\n * `risk-notice-routes.spec.ts` (console) resolves every template to a page\n * that exists under `apps/console/app`.\n */\nexport interface RiskActionDefinition {\n label: string\n /** What happens when it is followed, for the help page and a tooltip. */\n hint: string\n href: string\n}\n\nexport const RISK_OWNER_ACTIONS: Record<RiskOwnerActionId, RiskActionDefinition> = {\n 'view-details': {\n label: 'View details',\n hint: 'Opens the item this notice is about.',\n href: '{itemPath}',\n },\n 'edit-and-resubmit': {\n label: 'Edit and resubmit',\n hint: 'Opens the item so you can change it. A changed version is checked again on its own.',\n href: '{itemPath}',\n },\n 'request-review': {\n label: 'Request a review',\n hint: 'Sends a note to our review team on the same case. It does not release anything by itself.',\n href: '/org/settings/holds?notice={noticeId}',\n },\n 'refund-order': {\n label: 'Refund this order',\n hint: 'Opens the order, where Refund returns the payment to the card.',\n href: '{itemPath}',\n },\n 'keep-order': {\n label: 'Keep the order',\n hint: 'Opens the order. Nothing needs doing to keep it; fulfill it only once you are sure.',\n href: '{itemPath}',\n },\n 'answer-dispute': {\n label: 'Answer the dispute',\n hint: 'Opens the order with its dispute and the date your evidence is due.',\n href: '{itemPath}',\n },\n 'update-payment-method': {\n label: 'Update payment method',\n hint: 'Opens billing settings, where the card your subscription is paid from lives.',\n href: '/org/billing/settings',\n },\n 'view-billing': {\n label: 'View billing',\n hint: 'Opens your plan and subscription.',\n href: '/org/billing',\n },\n 'release-gift-cards': {\n label: 'Review gift cards',\n hint: 'Opens Gift cards under Promotions, where a held card can be released once you trust the payment.',\n href: '/{hostId}/products/promotions',\n },\n 'view-marketplace-sales': {\n label: 'View marketplace payouts',\n hint: 'Opens your marketplace payouts, where each sale and when it pays out are listed.',\n href: '/org/marketplace/payouts',\n },\n 'view-holds': {\n label: 'View holds and reviews',\n hint: 'Lists everything on this workspace that is held or under review, with its status.',\n href: '/org/settings/holds',\n },\n 'contact-support': {\n label: 'Contact support',\n hint: 'Opens a support ticket. If you cannot sign in, reply to this email instead.',\n href: '/org/support/tickets',\n },\n}\n\nexport const RISK_STAFF_ACTIONS: Record<RiskStaffActionId, RiskActionDefinition> = {\n 'staff-open-row': {\n label: 'Open in abuse queue',\n hint: 'The abuse-queue row with the evidence and any review requests.',\n href: '/admin/abuse-reports?report={reviewId}',\n },\n 'staff-release': {\n label: 'Waive / release',\n hint: 'Dismiss the row. For a held email or page this releases exactly the held content.',\n href: '/admin/abuse-reports?report={reviewId}&decide=dismissed',\n },\n 'staff-reject': {\n label: 'Reject',\n hint: 'Mark the row actioned. A held email or page stays unsent or unserved.',\n href: '/admin/abuse-reports?report={reviewId}&decide=actioned',\n },\n 'staff-lock-workspace': {\n label: 'Lock workspace',\n hint: 'Opens Lockdown with this workspace filled in.',\n href: '/admin/lockdown?scope=org&targetId={orgId}',\n },\n 'staff-lock-site': {\n label: 'Lock site',\n hint: 'Opens Lockdown with this site filled in.',\n href: '/admin/lockdown?scope=host&targetId={hostId}',\n },\n 'staff-unlock': {\n label: 'Review the lock',\n hint: 'Opens Lockdown on the locked target, where it can be lifted.',\n href: '/admin/lockdown?scope={lockScope}&targetId={lockTargetId}',\n },\n 'staff-cancel-subscription': {\n label: 'Cancel subscription',\n hint: \"The workspace's Subscription card on its staff page.\",\n href: '/admin/orgs/{orgId}#subscription',\n },\n 'staff-open-stripe': {\n label: 'Open in Stripe',\n hint: 'The charge, review, dispute or connected account in the Stripe Dashboard.',\n href: '{stripeUrl}',\n },\n 'staff-view-workspace': {\n label: 'View workspace',\n hint: \"The workspace's staff page.\",\n href: '/admin/orgs/{orgId}',\n },\n}\n\n/** One audience's half of a kind. */\nexport interface RiskNoticeCopy {\n /** Short and specific. Also the email subject. */\n title: string\n /** What we saw, on what, and when. */\n summary: string\n /** What it means for them. */\n meaning: string\n /** What to do next, in order. */\n steps: readonly string[]\n}\n\nexport interface RiskNoticeDefinition {\n kind: RiskEventKind\n severity: RiskNoticeSeverity\n /**\n * Whether the owners and admins are emailed as well as notified in the\n * console. The email is transactional account mail from the platform's own\n * sender: it ignores notification preferences and marketing consent, and\n * it reaches a locked workspace.\n */\n emailOwners: boolean\n /** Whether staff are alerted. False for events staff themselves caused. */\n alertStaff: boolean\n /**\n * Whether the notice always goes out, even while the workspace is over its\n * burst allowance. Locks, lifts and cancellations are never folded into a\n * digest: each one changes what the owner can do. Nor is a dispute, whose\n * evidence deadline a digest's one-line tally would drop, or a card-testing\n * warning, whose site and orders to check it would drop.\n */\n neverDigest: boolean\n /**\n * An owner can ask for a review. Only kinds with an abuse-queue row to\n * append to are reviewable.\n */\n reviewable: boolean\n /** The kinds staff decisions on this kind's row close it with. */\n closesWith?: { released: RiskEventKind; rejected: RiskEventKind }\n /**\n * Also tell the managers of the site the event is on, not just the\n * workspace's. A closing notice sent for a decided row goes to whoever\n * its opening went to, so for it the opening kind's answer is the one read.\n */\n includeSiteManagers: boolean\n /** The help page section that explains it. */\n helpAnchor: string\n owner: RiskNoticeCopy & { actions: readonly RiskOwnerActionId[] }\n staff: Pick<RiskNoticeCopy, 'title' | 'summary'> & {\n actions: readonly RiskStaffActionId[]\n }\n}\n\n/**\n * The customer help page every notice links to. A path on the docs site;\n * the server prefixes the docs origin.\n */\nexport const RISK_NOTICE_HELP_PATH = '/help/holds-and-reviews'\n\n/**\n * Merge tokens a notice may use. The server fills each from the event; a\n * token the event does not carry renders as the fallback noted here, never\n * as a hole in a sentence.\n */\nexport const RISK_NOTICE_TOKENS = {\n 'workspace.name': 'The workspace name, or \"your workspace\".',\n 'site.label': 'The site the notice is about, as `the site \"Harbor View\"`, or \"your site\".',\n 'item.label': 'What the notice is about, in the owner\\'s words: the campaign \"Spring sale\", the page /pricing, order 1042.',\n 'item.url': 'The absolute console link to the item.',\n occurredAt: 'When it happened, in UTC.',\n reference: 'The case reference staff know it by (HS-…, PF-…).',\n 'holds.url': \"The workspace's Holds & reviews page.\",\n 'help.url': 'The help page for holds and reviews.',\n 'support.email': \"The operator's support address.\",\n 'lock.message': 'The message staff wrote when they applied the lock.',\n 'lock.affected': 'What the lock or pause covers: sites, sessions, billing.',\n amount: 'The payment amount, when there is one.',\n 'payment.event':\n 'What happened to a payment, finishing \"the payment was …\": flagged for a fraud check, disputed by the cardholder with their bank.',\n 'page.visitors': 'What visitors see while a held page waits, as one sentence.',\n 'evidence.dueBy': 'The date dispute evidence is due, when Stripe gave one.',\n 'payout.delay':\n 'A new publisher\\'s payout schedule, finishing \"moved to an extended schedule:\": each payout reaches your bank 14 days after the sale, until your workspace is 30 days old.',\n 'staff.evidence': 'Staff only: what the screen or Stripe reported.',\n} as const\n\nexport type RiskNoticeToken = keyof typeof RISK_NOTICE_TOKENS\n\n/**\n * `{{payment.event}}` for each card signal a payment can draw, in the owner's\n * words. The early warning and the review are told apart, because only one\n * of them has held the money; a dispute is the bank's, and says so.\n */\nexport const RISK_PAYMENT_EVENTS = {\n 'early-fraud-warning': 'reported by the card issuer as possibly not made by the cardholder',\n 'radar-review': 'held for a fraud review',\n dispute: 'disputed by the cardholder with their bank',\n} as const satisfies Record<string, string>\n\n/** `14 days`, `1 day`. */\nfunction dayCount(days: number): string {\n return `${days} ${days === 1 ? 'day' : 'days'}`\n}\n\n/**\n * `{{payout.delay}}`: how long a new publisher's payouts wait, and until\n * when. The numbers are the marketplace's own payout terms, passed in by the\n * caller, and the notice states them: the schedule is money the publisher is\n * owed and when it lands, not how anything was detected.\n */\nexport function riskPayoutDelayText(payout: { delayDays: number; untilWorkspaceAgeDays: number }): string {\n return (\n `each payout reaches your bank ${dayCount(payout.delayDays)} after the sale, ` +\n `until your workspace is ${dayCount(payout.untilWorkspaceAgeDays)} old`\n )\n}\n\nconst ASK_FOR_REVIEW =\n 'If you think this is a mistake, choose Request a review and tell us about it. A person reads every request.'\n\nconst REVIEW_TIME =\n 'Reviews are usually answered within one business day. You will get a notice either way.'\n\nconst CANNOT_SIGN_IN =\n 'If you cannot sign in, reply to this email or write to {{support.email}} with the reference {{reference}}.'\n\n/**\n * How a locked ACCOUNT appeals (AGL-3420). It cannot sign in, so the way in\n * is mail: a reply to the notice reaches support (the notice's Reply-To),\n * and support answers from its own mailbox — which a ban does not refuse,\n * because a ban refuses what the platform sends, not what a person does.\n */\nconst APPEAL_BY_REPLY =\n 'If you believe this is a mistake, you can appeal: reply to this email, or write to {{support.email}} with the reference {{reference}}. Tell us anything that explains what happened. A person reviews every appeal and answers from that address.'\n\n/*\n * The catalog. Exhaustive by type: a kind added to RISK_EVENT_KINDS is a\n * compile error here until somebody writes what each audience is told.\n */\nexport const RISK_NOTICE_CATALOG: Readonly<Record<RiskEventKind, RiskNoticeDefinition>> = {\n 'email-held': {\n kind: 'email-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'email-released', rejected: 'email-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'An email is on hold for review',\n summary:\n 'Our automated safety review held {{item.label}} from {{workspace.name}} on {{occurredAt}} before it was sent.',\n meaning:\n 'This email was not delivered to anyone. Other emails with the same links or wording are stopped too while it is under review. Nothing else on your account has changed.',\n steps: [\n 'Open the email and check its links, its sender name and its wording.',\n 'If you change it, it is checked again when it next sends.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Outbound email held for review — possible phishing',\n summary:\n '{{item.label}} from {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'email-released': {\n kind: 'email-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'Your held email was released',\n summary: 'Our review team released {{item.label}} on {{occurredAt}}.',\n meaning:\n 'A held campaign that is still waiting goes back on the schedule and sends shortly; one you edited or canceled meanwhile stays as you left it. An automated email sends the next time it runs. A single email that was stopped, such as a receipt or a form reply, is not sent again, and the next one like it sends normally.',\n steps: [\n 'Nothing to do. If you edit the email before it sends, the edited version is checked on its own.',\n ],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held email released',\n summary: '{{item.label}} from {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'email-rejected': {\n kind: 'email-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'email-held',\n owner: {\n title: 'A held email will not be sent',\n summary: 'After review, {{item.label}} from {{workspace.name}} was not approved on {{occurredAt}}.',\n meaning:\n 'This email will not be sent in its current form, and other emails with the same links or wording are stopped too until they are changed. A held campaign that was still waiting is canceled; an automated email step stays stopped.',\n steps: [\n 'Read our acceptable use rules before you send similar mail again.',\n 'If you think the decision is wrong, choose Request a review and explain what the email is for.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Held email rejected',\n summary: '{{item.label}} from {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'page-held': {\n kind: 'page-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'page-released', rejected: 'page-rejected' },\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'A published page is on hold for review',\n summary:\n 'On {{occurredAt}}, our automated safety review held the latest version of {{item.label}} on {{site.label}}.',\n meaning: '{{page.visitors}} Nothing else on the site has changed.',\n steps: [\n 'Open the page and check its links, embeds and any fields that ask visitors for information.',\n 'If you change and publish it again, the new version is checked on its own.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Published page held for review — possible phishing',\n summary:\n '{{item.label}} of {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'page-released': {\n kind: 'page-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'Your held page is live',\n summary: 'On {{occurredAt}}, our review team released {{item.label}} on {{site.label}}.',\n meaning: 'Visitors now see the version that was held.',\n steps: ['Nothing to do. Open the page to confirm it looks right.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held page released',\n summary: '{{item.label}} of {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'page-flagged': {\n kind: 'page-flagged',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'page-flagged',\n owner: {\n title: 'A live page is being reviewed',\n summary:\n 'On {{occurredAt}}, our automated safety review flagged {{item.label}} on {{site.label}}. The page is still live.',\n meaning:\n 'Visitors still see the page while a person looks. If you did not publish what is on it, someone else may have access to your account.',\n steps: [\n 'Open the page and check its links, embeds and any fields that ask visitors for information.',\n 'If you did not make these changes, change your password, remove members you do not recognize, and contact support.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['view-details', 'edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Live page flagged — possible phishing or a compromised account',\n summary:\n '{{item.label}} of {{workspace.name}} is live and was flagged on {{occurredAt}}. {{staff.evidence}} It is still serving; lock the site if it is impersonation. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'page-rejected': {\n kind: 'page-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: true,\n helpAnchor: 'page-held',\n owner: {\n title: 'A held page will not be published',\n summary:\n 'On {{occurredAt}}, after review, our team did not approve the held version of {{item.label}} on {{site.label}}.',\n meaning:\n 'Visitors keep seeing the previous version, or a not-found page if there is none. Publishing the same content again is held again.',\n steps: [\n 'Change the page and publish a new version, or restore an earlier version from its history.',\n 'If you think the decision is wrong, choose Request a review and explain what the page is for.',\n ],\n actions: ['edit-and-resubmit', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Held page rejected',\n summary: '{{item.label}} of {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-site', 'staff-view-workspace'],\n },\n },\n 'listing-held': {\n kind: 'listing-held',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'listing-released', rejected: 'listing-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'A marketplace submission is on hold for review',\n summary:\n 'Our automated safety review held {{item.label}} from {{workspace.name}} on {{occurredAt}} before it was listed.',\n meaning: 'Nothing was published. Buyers cannot see or install it while it waits.',\n steps: [\n 'Check its name, description, links and any fields it asks people to fill in.',\n 'If you change it, the new submission is checked on its own.',\n ASK_FOR_REVIEW,\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Marketplace submission held for review — possible phishing',\n summary:\n '{{item.label}} from publisher workspace {{workspace.name}} was held on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'listing-released': {\n kind: 'listing-released',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'Your marketplace submission was cleared',\n summary:\n 'On {{occurredAt}}, our review team cleared {{item.label}} from {{workspace.name}}. It is not listed yet: submit it again and it will go through.',\n meaning: 'It was not published automatically, so buyers cannot see it until you submit it again.',\n steps: ['Submit it again; it will go through this time.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Held marketplace submission released',\n summary: '{{item.label}} from {{workspace.name}} was released. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'listing-rejected': {\n kind: 'listing-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'listing-held',\n owner: {\n title: 'A marketplace submission will not be listed',\n summary: 'After review, {{item.label}} was not approved on {{occurredAt}}.',\n meaning: 'It will not be published in its current form. Submitting the same content again is held again.',\n steps: [\n 'Read the marketplace listing rules before you submit something similar.',\n 'If you think the decision is wrong, choose Request a review and explain what it is for.',\n ],\n actions: ['request-review', 'contact-support'],\n },\n staff: {\n title: 'Held marketplace submission rejected',\n summary: '{{item.label}} from {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'domain-flagged': {\n kind: 'domain-flagged',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'domain-cleared', rejected: 'domain-rejected' },\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'A domain you added is being reviewed',\n summary:\n 'On {{occurredAt}}, {{item.label}} was added to {{workspace.name}}, and it is waiting on a routine review by our team.',\n meaning:\n 'The domain stays connected while we look, and nothing is charged. If you send email from it, that email is stopped and held for its own review, whatever this review decides.',\n steps: [\n 'Nothing is needed if the domain and the name on it are yours.',\n 'To speed it up, choose Request a review and tell us who owns the domain and what it is for.',\n REVIEW_TIME,\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Domain flagged — possible brand impersonation',\n summary:\n '{{item.label}} was added by {{workspace.name}} on {{occurredAt}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n ],\n },\n },\n 'domain-cleared': {\n kind: 'domain-cleared',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'Your domain review is complete',\n summary: 'On {{occurredAt}}, our team reviewed {{item.label}} on {{workspace.name}} and cleared it.',\n meaning:\n 'The domain stays connected. If you send email from it, clearing the domain does not release that email: an email that was stopped is not sent again, and new email from it still goes through its own review.',\n steps: ['Nothing to do.'],\n actions: ['view-details'],\n },\n staff: {\n title: 'Flagged domain cleared',\n summary: '{{item.label}} on {{workspace.name}} was cleared. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'domain-rejected': {\n kind: 'domain-rejected',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'domain-flagged',\n owner: {\n title: 'A domain on your workspace was not approved',\n summary: 'On {{occurredAt}}, after review, our team did not approve {{item.label}} on {{workspace.name}}.',\n meaning:\n 'This decision by itself does not disconnect the domain or change your sites. If you send email from it, that email keeps being stopped.',\n steps: [\n 'Remove the domain from your workspace, or show us that it is yours.',\n 'If you think the decision is wrong, choose Request a review with proof of ownership.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Flagged domain rejected',\n summary: '{{item.label}} on {{workspace.name}} was rejected. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-lock-workspace', 'staff-view-workspace'],\n },\n },\n 'billing-payment-flagged': {\n kind: 'billing-payment-flagged',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'billing-payment-flagged',\n owner: {\n title: 'A payment on your subscription needs attention',\n summary:\n 'On {{occurredAt}}, a subscription payment of {{amount}} for {{workspace.name}} was {{payment.event}}.',\n meaning:\n 'The payment may be reversed by the cardholder\\'s bank. If it is, your subscription may need a new payment method, and your plan can change.',\n steps: [\n 'If you made this payment, choose Request a review and confirm it, so we can answer the bank.',\n 'Check that the card on your account is yours and current.',\n 'If you did not make this payment, contact support now.',\n ],\n actions: ['request-review', 'update-payment-method', 'view-billing', 'contact-support'],\n },\n staff: {\n title: 'Platform billing fraud signal',\n summary:\n '{{staff.evidence}} Workspace {{workspace.name}}, {{amount}}, on {{occurredAt}}. Nothing has been refunded or canceled. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-cancel-subscription',\n 'staff-lock-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'link-blocked': {\n kind: 'link-blocked',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'link-blocked',\n owner: {\n title: 'A link on {{site.label}} was blocked',\n summary:\n 'On {{occurredAt}}, we blocked {{item.label}} on {{site.label}}, because the address looks like another company\\'s website.',\n meaning:\n 'Nobody who follows that link is sent there. Everything else on the site works as normal, and nothing is charged.',\n steps: [\n 'Replace it with a file from your media library or a link on your own domain. The link stays blocked whatever a review decides, so replacing it is the way to make it work again.',\n 'If the address really is yours, you can still tell us with Request a review.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Commerce link flagged — possible brand impersonation',\n summary:\n '{{item.label}} on {{workspace.name}}. {{staff.evidence}} Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-release',\n 'staff-reject',\n 'staff-lock-site',\n 'staff-view-workspace',\n ],\n },\n },\n 'card-testing': {\n kind: 'card-testing',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n // Which site, and that its orders need checking before they ship, is the\n // point of the notice; a digest would drop both.\n neverDigest: true,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: true,\n helpAnchor: 'card-testing',\n owner: {\n title: 'Unusual checkout activity on {{site.label}}',\n summary:\n 'On {{occurredAt}}, checkout on {{site.label}} saw an unusual burst of payment attempts, which can be someone testing stolen cards.',\n meaning:\n 'Checkout is still open. Repeated attempts from one source are being slowed. Payments from stolen cards may be reversed by the cardholder\\'s bank later.',\n steps: [\n 'Review your recent orders before you fulfill them.',\n 'Refund any order you do not recognize.',\n 'If this was a launch or a sale, nothing is needed; you can tell us with Request a review.',\n ],\n actions: ['view-details', 'request-review', 'contact-support'],\n },\n staff: {\n title: 'Card-testing velocity on a site',\n summary:\n 'Unusual burst of card payments: {{item.label}}, workspace {{workspace.name}}. {{staff.evidence}} Nothing has been refused site-wide or refunded. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-lock-site',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'gift-card-hold': {\n kind: 'gift-card-hold',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'gift-card-hold',\n owner: {\n title: 'Gift cards from an order are on hold',\n summary:\n 'On {{occurredAt}}, we put on hold the gift cards bought with {{item.label}} on {{site.label}}, because the payment for that order is in question.',\n meaning:\n 'They cannot be redeemed for now. Their balance is kept. If the payment is refunded or the dispute is lost, the balance is voided for you.',\n steps: [\n 'Check the order and the buyer.',\n 'If you are satisfied the payment is genuine, release the cards from Gift cards under Promotions.',\n 'If you are not, refund the order.',\n ],\n actions: ['release-gift-cards', 'refund-order', 'contact-support'],\n },\n staff: {\n title: 'Gift cards frozen on a questioned payment',\n summary: 'Gift cards bought with {{item.label}} on {{workspace.name}} were frozen. {{staff.evidence}}',\n actions: ['staff-view-workspace', 'staff-lock-site'],\n },\n },\n 'sale-fraud-warning': {\n kind: 'sale-fraud-warning',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-fraud-warning',\n owner: {\n title: 'A payment you received may be fraudulent',\n summary:\n 'On {{occurredAt}}, the card issuer reported the payment for {{item.label}} on {{site.label}} ({{amount}}) as possibly not made by the cardholder.',\n meaning:\n 'This payment may be reversed by the cardholder\\'s bank. It is not a chargeback yet. Nothing has been refunded or canceled.',\n steps: [\n 'Hold anything not yet shipped or delivered until you are sure the buyer is genuine.',\n 'Refunding now usually prevents a chargeback. If a chargeback is decided for the cardholder, the payment is taken back from you.',\n 'If you know the buyer and the sale is genuine, you can keep the order.',\n ],\n actions: ['refund-order', 'keep-order', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Early fraud warning on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace', 'staff-lock-site'],\n },\n },\n 'sale-payment-review': {\n kind: 'sale-payment-review',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-payment-review',\n owner: {\n title: 'A payment you received is on hold for review',\n summary:\n 'On {{occurredAt}}, the payment for {{item.label}} on {{site.label}} ({{amount}}) was held for a fraud review.',\n meaning:\n 'The payment has not reached your balance yet and may be refunded if it is not approved. Nothing has been refunded or canceled.',\n steps: [\n 'Hold anything not yet shipped or delivered until the payment clears.',\n 'If you know the buyer is not genuine, refund the order.',\n 'If you know the buyer, keep the order; the review usually clears on its own.',\n ],\n actions: ['refund-order', 'keep-order', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Payment review on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'sale-dispute': {\n kind: 'sale-dispute',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n // Its evidence deadline is the point of the notice; a digest would drop it.\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'sale-dispute',\n owner: {\n title: 'A customer disputed a payment',\n summary:\n 'On {{occurredAt}}, the cardholder disputed the payment for {{item.label}} on {{site.label}} ({{amount}}) with their bank.',\n meaning:\n 'The payment may be reversed by the cardholder\\'s bank. An unanswered dispute is decided for the cardholder. Your evidence is due by {{evidence.dueBy}}.',\n steps: [\n 'Open the order and gather what shows the sale was genuine: receipts, delivery tracking, messages with the buyer.',\n 'Send your evidence before {{evidence.dueBy}}. Contact support if you need help submitting it.',\n 'If the buyer is right, accept the dispute instead of answering it.',\n ],\n actions: ['answer-dispute', 'view-details', 'contact-support'],\n },\n staff: {\n title: 'Dispute on a site sale',\n summary: '{{item.label}} on {{workspace.name}}, {{amount}}. Evidence due {{evidence.dueBy}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'seller-review': {\n kind: 'seller-review',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'seller-review',\n owner: {\n title: 'We are reviewing recent payments on your store',\n summary:\n 'On {{occurredAt}}, our team opened a routine review of recent card payments taken by {{workspace.name}}.',\n meaning:\n 'Your store keeps selling while we look. We may contact you for information about your recent orders.',\n steps: [\n 'Check your recent orders and refund any you believe were not placed by the cardholder.',\n 'Choose Request a review to tell us about your business and your customers; it helps the review finish sooner.',\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-holds', 'contact-support'],\n },\n staff: {\n title: 'Seller fraud pattern on one connected account',\n summary:\n '{{staff.evidence}} Workspace {{workspace.name}}. Nothing has been refunded, canceled or paused. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'marketplace-sale-review': {\n kind: 'marketplace-sale-review',\n severity: 'warning',\n emailOwners: true,\n alertStaff: true,\n neverDigest: false,\n reviewable: true,\n closesWith: { released: 'review-cleared', rejected: 'review-upheld' },\n includeSiteManagers: false,\n helpAnchor: 'marketplace-sale-review',\n owner: {\n title: 'A marketplace sale is under review',\n summary:\n 'On {{occurredAt}}, our team opened a routine review of {{item.label}} ({{amount}}) for {{workspace.name}}.',\n meaning:\n 'The sale is recorded as usual, and its payout may take longer than normal. Nothing has been refunded.',\n steps: [\n 'Nothing is needed from you.',\n 'To tell us about the buyer or the sale, choose Request a review.',\n REVIEW_TIME,\n ],\n actions: ['request-review', 'view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Marketplace sale flagged — possible self-dealing or card fraud',\n summary:\n '{{item.label}} ({{amount}}) paid publisher workspace {{workspace.name}}. {{staff.evidence}} Nothing has been refunded or paused. Reference {{reference}}.',\n actions: [\n 'staff-open-row',\n 'staff-open-stripe',\n 'staff-lock-workspace',\n 'staff-view-workspace',\n 'staff-release',\n 'staff-reject',\n ],\n },\n },\n 'marketplace-sale-warning': {\n kind: 'marketplace-sale-warning',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-sale-review',\n owner: {\n title: 'A marketplace sale may be reversed',\n summary:\n 'On {{occurredAt}}, the payment for {{item.label}} ({{amount}}) to {{workspace.name}} was {{payment.event}}.',\n meaning:\n 'This payment may be reversed by the cardholder\\'s bank. If it is, your share of it is taken back from your payouts. Nothing has been refunded yet.',\n steps: [\n 'Nothing is needed from you: the marketplace handles the payment with the buyer\\'s bank.',\n 'If you know the buyer, contact support; it can help us answer the bank.',\n ],\n actions: ['view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Card signal on a marketplace sale',\n summary: '{{item.label}} paid publisher workspace {{workspace.name}}. {{staff.evidence}}',\n actions: ['staff-open-stripe', 'staff-view-workspace'],\n },\n },\n 'publisher-payouts-held': {\n kind: 'publisher-payouts-held',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-payouts',\n owner: {\n title: 'Your marketplace payouts are on an extended schedule',\n summary:\n 'On {{occurredAt}}, payouts for {{workspace.name}}\\'s marketplace sales moved to an extended schedule: {{payout.delay}}.',\n meaning:\n 'Nothing is withheld or charged. Your sales are recorded as usual, and each one pays out automatically when its wait ends.',\n steps: ['Nothing to do. You will get a notice when payouts return to the standard schedule.'],\n actions: ['view-marketplace-sales', 'contact-support'],\n },\n staff: {\n title: 'Publisher payouts on the extended schedule',\n summary: 'Publisher workspace {{workspace.name}} payouts moved to the extended schedule.',\n actions: ['staff-view-workspace'],\n },\n },\n 'publisher-payouts-standard': {\n kind: 'publisher-payouts-standard',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'marketplace-payouts',\n owner: {\n title: 'Your marketplace payouts are back on the standard schedule',\n summary: 'On {{occurredAt}}, payouts for {{workspace.name}}\\'s marketplace sales returned to the standard schedule.',\n meaning: 'Your sales now pay out on your payout account\\'s standard schedule.',\n steps: ['Nothing to do.'],\n actions: ['view-marketplace-sales'],\n },\n staff: {\n title: 'Publisher payouts back on the standard schedule',\n summary: 'Publisher workspace {{workspace.name}} payouts returned to the standard schedule.',\n actions: ['staff-view-workspace'],\n },\n },\n 'review-cleared': {\n kind: 'review-cleared',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'requesting-a-review',\n owner: {\n title: 'Our review is complete',\n summary:\n 'On {{occurredAt}}, our team finished reviewing {{item.label}} on {{workspace.name}} and closed it with no action.',\n meaning: 'Nothing on your account changes because of it.',\n steps: ['Nothing to do.'],\n actions: ['view-holds'],\n },\n staff: {\n title: 'Review closed with no action',\n summary: '{{item.label}} on {{workspace.name}} was dismissed. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'review-upheld': {\n kind: 'review-upheld',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: false,\n reviewable: true,\n includeSiteManagers: false,\n helpAnchor: 'requesting-a-review',\n owner: {\n title: 'Our review found a problem',\n summary:\n 'On {{occurredAt}}, our team finished reviewing {{item.label}} on {{workspace.name}} and did not clear it.',\n meaning:\n 'This decision by itself does not lock anything, take anything down or change your billing. If we take any further step, you will get a separate notice saying exactly what changed.',\n steps: [\n 'If another notice arrives, it says what changed. If none does, nothing else has changed.',\n 'If you think the decision is wrong, choose Request a review or contact support with the reference {{reference}}.',\n ],\n actions: ['request-review', 'view-holds', 'contact-support'],\n },\n staff: {\n title: 'Review closed with action',\n summary: '{{item.label}} on {{workspace.name}} was actioned. Reference {{reference}}.',\n actions: ['staff-open-row', 'staff-view-workspace'],\n },\n },\n 'workspace-locked': {\n kind: 'workspace-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{workspace.name}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Nothing is needed from you unless the message above asks for something, or you believe this is a mistake.',\n CANNOT_SIGN_IN,\n 'Tell us who you are, what the workspace is for, and anything that explains what happened. A person reads every appeal.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace locked',\n summary: '{{workspace.name}} was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'workspace-unlocked': {\n kind: 'workspace-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: '{{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{workspace.name}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: [\n 'Sign in again; sessions that were signed out stay signed out.',\n 'Check your sites, scheduled sends and billing. Anything that was canceled stays canceled until you restart it.',\n ],\n actions: ['view-holds', 'view-billing', 'contact-support'],\n },\n staff: {\n title: 'Workspace lock lifted',\n summary: '{{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'site-locked': {\n kind: 'site-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A site on {{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{item.label}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Nothing is needed from you unless the message above asks for something, or you believe this is a mistake.',\n 'Contact support to appeal, with the reference {{reference}}. A person reads every appeal.',\n CANNOT_SIGN_IN,\n ],\n actions: ['contact-support', 'view-holds'],\n },\n staff: {\n title: 'Site locked',\n summary: '{{item.label}} of {{workspace.name}} was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'site-unlocked': {\n kind: 'site-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A site on {{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{item.label}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Open the site and check that its pages, forms and checkout work as you expect.'],\n actions: ['view-details', 'contact-support'],\n },\n staff: {\n title: 'Site lock lifted',\n summary: '{{item.label}} of {{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'domain-locked': {\n kind: 'domain-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A domain on {{workspace.name}} has been locked',\n summary: 'On {{occurredAt}}, our team locked {{item.label}}. The message from our team: {{lock.message}}',\n meaning: 'While it is locked: {{lock.affected}}',\n steps: [\n 'Nothing is needed from you unless the message above asks for something, or you believe this is a mistake.',\n 'Contact support to appeal, with the reference {{reference}}.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Domain locked',\n summary: '{{item.label}} of {{workspace.name}} was locked on {{occurredAt}}.',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'domain-unlocked': {\n kind: 'domain-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: true,\n helpAnchor: 'locked',\n owner: {\n title: 'A domain on {{workspace.name}} has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on {{item.label}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Visit the domain to confirm it serves your site again.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Domain lock lifted',\n summary: '{{item.label}} of {{workspace.name}} was unlocked on {{occurredAt}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'account-locked': {\n kind: 'account-locked',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Your account has been locked',\n summary: 'On {{occurredAt}}, our team locked your {{brand.productName}} account. The message from our team: {{lock.message}}',\n meaning: 'What this means: {{lock.affected}}',\n steps: [\n 'Nothing is needed from you unless the message above asks for something, or you believe this is a mistake.',\n APPEAL_BY_REPLY,\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Account locked',\n summary: 'An account was locked on {{occurredAt}}. Affected: {{lock.affected}}',\n actions: ['staff-unlock'],\n },\n },\n 'account-unlocked': {\n kind: 'account-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Your account has been restored',\n summary: 'On {{occurredAt}}, our team lifted the lock on your {{brand.productName}} account.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Sign in again. If anything still does not work, contact support.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Account lock lifted',\n summary: 'An account was unlocked on {{occurredAt}}.',\n actions: ['staff-unlock'],\n },\n },\n 'feature-locked': {\n kind: 'feature-locked',\n severity: 'warning',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Paused on {{workspace.name}}: {{item.label}}',\n summary:\n 'On {{occurredAt}}, our team paused {{item.label}} on {{workspace.name}}. The message from our team: {{lock.message}}',\n meaning: 'Everything else on your workspace keeps working. {{lock.affected}}',\n steps: [\n 'Nothing is needed from you unless the message above asks for something, or you believe this is a mistake.',\n 'Contact support with the reference {{reference}} if you have questions.',\n ],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace feature paused',\n summary: 'Paused for {{workspace.name}} on {{occurredAt}}: {{item.label}}.',\n actions: ['staff-unlock', 'staff-view-workspace'],\n },\n },\n 'feature-unlocked': {\n kind: 'feature-unlocked',\n severity: 'info',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'locked',\n owner: {\n title: 'Back on for {{workspace.name}}: {{item.label}}',\n summary: 'On {{occurredAt}}, our team turned {{item.label}} back on for {{workspace.name}}.',\n meaning: 'What happens now: {{lock.affected}}',\n steps: ['Nothing to do.'],\n actions: ['contact-support'],\n },\n staff: {\n title: 'Workspace feature restored',\n summary: 'Restored for {{workspace.name}} on {{occurredAt}}: {{item.label}}.',\n actions: ['staff-view-workspace'],\n },\n },\n 'subscription-canceled': {\n kind: 'subscription-canceled',\n severity: 'urgent',\n emailOwners: true,\n alertStaff: false,\n neverDigest: true,\n reviewable: false,\n includeSiteManagers: false,\n helpAnchor: 'subscription-canceled',\n owner: {\n title: 'The subscription for {{workspace.name}} was canceled',\n summary: 'On {{occurredAt}}, our team canceled the subscription for {{workspace.name}}.',\n meaning: 'What changes: {{lock.affected}}',\n steps: [\n 'Nothing is deleted. Your sites and data stay when the workspace moves to the Free plan.',\n 'Contact support if you believe this was a mistake, with the reference {{reference}}.',\n ],\n actions: ['view-billing', 'contact-support'],\n },\n staff: {\n title: 'Subscription canceled by staff',\n summary: 'The subscription for {{workspace.name}} was canceled on {{occurredAt}}.',\n actions: ['staff-cancel-subscription', 'staff-view-workspace'],\n },\n },\n}\n\n/**\n * The kinds whose email wears the WORKSPACE's brand: routine notices about\n * the workspace's own customers' payments, which read as the workspace's own\n * operations. Every other kind — a hold, a lock, a lift, a cancellation, a\n * review — is the platform acting, and is sent in the platform's brand.\n */\nexport const RISK_NOTICE_WORKSPACE_BRANDED: ReadonlySet<RiskEventKind> = new Set<RiskEventKind>([\n 'sale-fraud-warning',\n 'sale-payment-review',\n 'sale-dispute',\n 'gift-card-hold',\n 'marketplace-sale-warning',\n])\n\n/**\n * The kinds that CLOSE another: a release, a rejection, a review's end. A\n * closing notice never re-stamps its row, so the row keeps naming the kind\n * it was opened as — and a second decision closes it again correctly.\n */\nexport const RISK_NOTICE_CLOSING_KINDS: ReadonlySet<RiskEventKind> = new Set<RiskEventKind>(\n Object.values(RISK_NOTICE_CATALOG).flatMap((definition) =>\n definition.closesWith ? [definition.closesWith.released, definition.closesWith.rejected] : [],\n ),\n)\n\n/** The catalog entry for a kind. */\nexport function riskNoticeDefinition(kind: RiskEventKind): RiskNoticeDefinition {\n return RISK_NOTICE_CATALOG[kind]\n}\n\nexport function isRiskEventKind(value: unknown): value is RiskEventKind {\n return typeof value === 'string' && (RISK_EVENT_KINDS as readonly string[]).includes(value)\n}\n\n/** The values a notice is rendered with. Every value is optional. */\nexport type RiskNoticeValues = Partial<Record<RiskNoticeToken | 'brand.productName', string | null | undefined>>\n\n/**\n * What a token renders as when the event did not carry it: always words, so\n * a sentence never has a hole in it.\n */\nconst TOKEN_FALLBACKS: Partial<Record<RiskNoticeToken | 'brand.productName', string>> = {\n 'workspace.name': 'your workspace',\n 'site.label': 'your site',\n 'item.label': 'an item on your workspace',\n occurredAt: 'a recent date',\n reference: 'shown on this notice',\n 'support.email': 'our support team',\n 'lock.message': 'None was given.',\n 'lock.affected': 'see your account for details.',\n amount: 'an amount shown on the payment',\n 'payment.event': 'flagged for a fraud check',\n 'page.visitors':\n 'Visitors see the previous version of this page, or a not-found page if it was never published, until the review is done.',\n 'evidence.dueBy': 'the date shown on the order',\n 'payout.delay': 'each payout waits a set number of days after the sale before it reaches your bank',\n 'staff.evidence': '',\n 'brand.productName': 'the platform',\n}\n\n/** Fill `{{token}}`s from `values`, falling back to words, never to a hole. */\nexport function renderRiskNoticeText(template: string, values: RiskNoticeValues): string {\n return template\n .replace(/\\{\\{\\s*([\\w.]+)\\s*\\}\\}/g, (_match, token: string) => {\n const value = values[token as RiskNoticeToken]\n if (typeof value === 'string' && value.trim()) return value.trim()\n return TOKEN_FALLBACKS[token as RiskNoticeToken] ?? ''\n })\n .replace(/[ \\t]{2,}/g, ' ')\n .trim()\n}\n\n/** The values an action href may use. */\nexport interface RiskActionParams {\n itemPath?: string | null\n noticeId?: string | null\n reviewId?: string | null\n orgId?: string | null\n hostId?: string | null\n stripeUrl?: string | null\n lockScope?: string | null\n lockTargetId?: string | null\n}\n\n/**\n * An action's href with its placeholders filled, or null when one of them\n * has no value — an action that would lead nowhere is not offered.\n */\nexport function resolveRiskActionHref(\n action: RiskActionDefinition,\n params: RiskActionParams,\n): string | null {\n let missing = false\n const href = action.href.replace(/\\{(\\w+)\\}/g, (_match, name: string) => {\n const value = params[name as keyof RiskActionParams]\n if (typeof value !== 'string' || !value) {\n missing = true\n return ''\n }\n // A whole-path placeholder is taken as written; a path segment or query\n // value is encoded.\n return name === 'itemPath' || name === 'stripeUrl' ? value : encodeURIComponent(value)\n })\n if (missing) return null\n if (href.startsWith('https://')) return href\n return href.startsWith('/') ? href : null\n}\n\n/** One action, ready to render. */\nexport interface ResolvedRiskAction {\n id: RiskOwnerActionId | RiskStaffActionId\n label: string\n hint: string\n href: string\n}\n\n/** A kind's owner actions that lead somewhere, in catalog order. */\nexport function resolveOwnerRiskActions(\n kind: RiskEventKind,\n params: RiskActionParams,\n): ResolvedRiskAction[] {\n return RISK_NOTICE_CATALOG[kind].owner.actions.flatMap((id) => {\n const definition = RISK_OWNER_ACTIONS[id]\n const href = resolveRiskActionHref(definition, params)\n return href ? [{ id, label: definition.label, hint: definition.hint, href }] : []\n })\n}\n\n/** A kind's staff actions that lead somewhere, in catalog order. */\nexport function resolveStaffRiskActions(\n kind: RiskEventKind,\n params: RiskActionParams,\n): ResolvedRiskAction[] {\n return RISK_NOTICE_CATALOG[kind].staff.actions.flatMap((id) => {\n const definition = RISK_STAFF_ACTIONS[id]\n const href = resolveRiskActionHref(definition, params)\n return href ? [{ id, label: definition.label, hint: definition.hint, href }] : []\n })\n}\n\n/** An owner notice as plain text: title, summary, meaning, numbered steps. */\nexport function renderOwnerRiskNotice(\n kind: RiskEventKind,\n values: RiskNoticeValues,\n): { title: string; summary: string; meaning: string; steps: string[] } {\n const copy = RISK_NOTICE_CATALOG[kind].owner\n return {\n title: renderRiskNoticeText(copy.title, values),\n summary: renderRiskNoticeText(copy.summary, values),\n meaning: renderRiskNoticeText(copy.meaning, values),\n steps: copy.steps.map((step) => renderRiskNoticeText(step, values)),\n }\n}\n\n/** A staff alert as plain text. */\nexport function renderStaffRiskNotice(\n kind: RiskEventKind,\n values: RiskNoticeValues,\n): { title: string; summary: string } {\n const copy = RISK_NOTICE_CATALOG[kind].staff\n return {\n title: renderRiskNoticeText(copy.title, values),\n summary: renderRiskNoticeText(copy.summary, values),\n }\n}\n\n/** The System emails catalog key a kind's owner email is designed under. */\nexport function riskNoticeEmailKey(kind: RiskEventKind): string {\n return `risk-${kind}`\n}\n\n/** The key the burst digest is designed under. */\nexport const RISK_NOTICE_DIGEST_EMAIL_KEY = 'risk-digest'\n\n/**\n * The kind an abuse-queue row is about, so the staff queue renders the\n * catalog's text for EVERY row a risk source filed — including rows filed\n * before the row carried its notice. The stamp `notifyRiskEvent` writes\n * (`riskNotice.kind`) wins; otherwise the row's own shape says it. Null for\n * a row from the public report form, which is not a risk event.\n */\nexport function riskKindForAbuseRow(row: {\n source?: unknown\n heldSend?: { kind?: unknown } | null\n riskNotice?: { kind?: unknown } | null\n}): RiskEventKind | null {\n const stamped = row.riskNotice?.kind\n if (isRiskEventKind(stamped)) return stamped\n switch (row.source) {\n case 'outbound-screen':\n if (row.heldSend?.kind === 'page') return 'page-held'\n if (row.heldSend?.kind === 'listing') return 'listing-held'\n return row.heldSend ? 'email-held' : 'domain-flagged'\n case 'stripe-fraud-signal':\n return 'billing-payment-flagged'\n case 'stripe-seller-fraud-pattern':\n return 'seller-review'\n case 'marketplace-sale-risk':\n return 'marketplace-sale-review'\n case 'payment-velocity':\n return 'card-testing'\n default:\n return null\n }\n}\n"],"names":["RISK_EVENT_KINDS","RISK_OWNER_ACTION_IDS","RISK_STAFF_ACTION_IDS","RISK_OWNER_ACTIONS","label","hint","href","RISK_STAFF_ACTIONS","RISK_NOTICE_HELP_PATH","RISK_NOTICE_TOKENS","occurredAt","reference","amount","RISK_PAYMENT_EVENTS","dispute","dayCount","days","riskPayoutDelayText","payout","delayDays","untilWorkspaceAgeDays","ASK_FOR_REVIEW","REVIEW_TIME","CANNOT_SIGN_IN","APPEAL_BY_REPLY","RISK_NOTICE_CATALOG","kind","severity","emailOwners","alertStaff","neverDigest","reviewable","closesWith","released","rejected","includeSiteManagers","helpAnchor","owner","title","summary","meaning","steps","actions","staff","RISK_NOTICE_WORKSPACE_BRANDED","Set","RISK_NOTICE_CLOSING_KINDS","Object","values","flatMap","definition","riskNoticeDefinition","isRiskEventKind","value","includes","TOKEN_FALLBACKS","renderRiskNoticeText","template","replace","_match","token","trim","resolveRiskActionHref","action","params","missing","name","encodeURIComponent","startsWith","resolveOwnerRiskActions","id","resolveStaffRiskActions","renderOwnerRiskNotice","copy","map","step","renderStaffRiskNotice","riskNoticeEmailKey","RISK_NOTICE_DIGEST_EMAIL_KEY","riskKindForAbuseRow","row","stamped","riskNotice","source","heldSend"],"mappings":"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OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;gBAAwB;aAAuB;QAC7E;IACF;IACA,aAAa;QACXhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAiBC,UAAU;QAAgB;QACnEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SAAS;YACTC,OAAO;gBACL;gBACA;gBACApB;gBACAC;aACD;YACDoB,SAAS;gBAAC;gBAAgB;gBAAqB;gBAAkB;aAAkB;QACrF;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,iBAAiB;QACfhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SAAS;YACTC,SAAS;YACTC,OAAO;gBAAC;aAA0D;YAClEC,SAAS;gBAAC;aAAe;QAC3B;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAkB;aAAuB;QACrD;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACApB;gBACAC;aACD;YACDoB,SAAS;gBAAC;gBAAgB;gBAAqB;gBAAkB;aAAkB;QACrF;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,iBAAiB;QACfhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO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CA;gBACA;aACD;QACH;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAkB;aAAkB;QAChE;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,gBAAgB;QACdhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZ,yEAAyE;QACzE,iDAAiD;QACjDC,aAAa;QACbC,YAAY;QACZC,YAAY;YAAEC,UAAU;YAAkBC,UAAU;QAAgB;QACpEC,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAgB;gBAAkB;aAAkB;QAChE;QACAC,OAAO;YACLL,OAAO;YACPC,SACE;YACFG,SAAS;gBACP;gBACA;gBACA;gBACA;gBACA;gBACA;aACD;QACH;IACF;IACA,kBAAkB;QAChBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YACFC,SACE;YACFC,OAAO;gBACL;gBACA;gBACA;aACD;YACDC,SAAS;gBAAC;gBAAsB;gBAAgB;aAAkB;QACpE;QACAC,OAAO;YACLL,OAAO;YACPC,SAAS;YACTG,SAAS;gBAAC;gBAAwB;aAAkB;QACtD;IACF;IACA,sBAAsB;QACpBhB,MAAM;QACNC,UAAU;QACVC,aAAa;QACbC,YAAY;QACZC,aAAa;QACbC,YAAY;QACZI,qBAAqB;QACrBC,YAAY;QACZC,OAAO;YACLC,OAAO;YACPC,SACE;YA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"}
@@ -255,63 +255,6 @@ export declare function deliverableMonthlyCeiling(platformPerHour: number, share
255
255
  * than this would promise a new tenant more than an established one may send.
256
256
  */
257
257
  export declare function orgDailyCampaignCeiling(platformPerHour: number, share?: number): number;
258
- /** Why a partly-delivered email will not run another batch. */
259
- export type CampaignBatchStop =
260
- /** Nothing is left to address. */
261
- 'complete'
262
- /** {@link EMAIL_MAX_SEND_BATCHES} reached. */
263
- | 'batch-limit'
264
- /** The batch settled nobody, so another one would settle nobody either. */
265
- | 'no-progress';
266
- /** What happens to an email after one batch of it has been delivered. */
267
- export interface CampaignBatchPlan {
268
- /** People this email has resolved and not yet addressed. */
269
- remaining: number;
270
- /** Batches this email has now run, including the one just finished. */
271
- batch: number;
272
- /** True when another batch will run. */
273
- resuming: boolean;
274
- /**
275
- * Why no further batch will run. Null while {@link resuming} is true —
276
- * a reason for a state that has not happened is a reason a surface would
277
- * show.
278
- */
279
- stop: CampaignBatchStop | null;
280
- }
281
- export interface CampaignBatchPlanInput {
282
- /** People this batch could have addressed, before the per-send cap. */
283
- mailable: number;
284
- /** People it did address — `min(mailable, perSend)`. */
285
- addressed: number;
286
- /**
287
- * Of those it addressed, how many are left for a later batch to try again:
288
- * the tail an hourly deferral cut off, and nothing else. A recipient the
289
- * send SETTLED — delivered, suppressed or off-topic — is not retryable and
290
- * is not counted here.
291
- */
292
- retryable: number;
293
- /**
294
- * People this batch settled: delivered plus permanently excluded. Zero is
295
- * what {@link CampaignBatchStop} `no-progress` is, and it is the reason
296
- * this is an input rather than a derivation — a batch that addressed 500
297
- * people and settled none of them will address the same 500 next time.
298
- */
299
- settled: number;
300
- /** Batches run before this one. */
301
- batchesSoFar: number;
302
- /** Injectable for tests; defaults to the shipped guard. */
303
- maxBatches?: number;
304
- }
305
- /**
306
- * Whether a partly-delivered email runs again, and how much is left.
307
- *
308
- * Pure, so the termination rule can be read and tested without a send. The
309
- * one property it exists to hold is that a campaign always terminates:
310
- * `resuming` is false whenever there is nothing left, whenever the batch
311
- * guard is reached, and whenever a batch settled nobody — the last of which
312
- * is the only way a self-rescheduling job can loop.
313
- */
314
- export declare function campaignBatchPlan(input: CampaignBatchPlanInput): CampaignBatchPlan;
315
258
  export interface DescribeEmailCeilingsInput {
316
259
  /** The live platform hourly ceiling, from `rateLimits/sendRateConfig`. */
317
260
  platformPerHour: number;
@@ -200,53 +200,6 @@
200
200
  */ export function orgDailyCampaignCeiling(platformPerHour, share = EMAIL_ORG_HOURLY_SHARE) {
201
201
  return orgHourlyCampaignCeiling(platformPerHour, share) * EMAIL_CEILING_HOURS_PER_DAY;
202
202
  }
203
- /**
204
- * Whether a partly-delivered email runs again, and how much is left.
205
- *
206
- * Pure, so the termination rule can be read and tested without a send. The
207
- * one property it exists to hold is that a campaign always terminates:
208
- * `resuming` is false whenever there is nothing left, whenever the batch
209
- * guard is reached, and whenever a batch settled nobody — the last of which
210
- * is the only way a self-rescheduling job can loop.
211
- */ export function campaignBatchPlan(input) {
212
- const mailable = positiveInt(input.mailable, 0);
213
- const addressed = Math.min(mailable, positiveInt(input.addressed, 0));
214
- const retryable = Math.min(addressed, positiveInt(input.retryable, 0));
215
- const settled = positiveInt(input.settled, 0);
216
- const batch = positiveInt(input.batchesSoFar, 0) + 1;
217
- const maxBatches = positiveInt(input.maxBatches, EMAIL_MAX_SEND_BATCHES);
218
- const remaining = Math.max(0, mailable - addressed) + retryable;
219
- if (remaining <= 0) {
220
- return {
221
- remaining: 0,
222
- batch,
223
- resuming: false,
224
- stop: 'complete'
225
- };
226
- }
227
- if (batch >= maxBatches) {
228
- return {
229
- remaining,
230
- batch,
231
- resuming: false,
232
- stop: 'batch-limit'
233
- };
234
- }
235
- if (settled <= 0) {
236
- return {
237
- remaining,
238
- batch,
239
- resuming: false,
240
- stop: 'no-progress'
241
- };
242
- }
243
- return {
244
- remaining,
245
- batch,
246
- resuming: true,
247
- stop: null
248
- };
249
- }
250
203
  /**
251
204
  * Builds the reconciled model and names every relation that fails.
252
205
  *