@aglyn/shared-util-email 1.0.0-beta.269 → 1.0.0-beta.271
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/index.d.ts +3 -0
- package/src/index.js +3 -0
- package/src/index.js.map +1 -1
- package/src/lib/domain-emails.d.ts +29 -0
- package/src/lib/domain-emails.js +587 -0
- package/src/lib/domain-emails.js.map +1 -0
- package/src/lib/site-care-emails.d.ts +26 -0
- package/src/lib/site-care-emails.js +461 -0
- package/src/lib/site-care-emails.js.map +1 -0
- package/src/lib/site-care-project-emails.d.ts +22 -0
- package/src/lib/site-care-project-emails.js +287 -0
- package/src/lib/site-care-project-emails.js.map +1 -0
- package/src/lib/system-email-catalog.js +162 -3
- package/src/lib/system-email-catalog.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/system-email-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 * Origins used as merge-token SAMPLE values in the staff email designer\n * (AGL-2202).\n *\n * These are never sent — they render in the template preview so an author can\n * see what `{{console.url}}` will become. That still made them wrong on a\n * self-host install: the preview showed Aglyn's console as the example for a\n * link that will resolve to the operator's, which is exactly the sort of\n * quiet mis-teaching that ends up copied into a hand-written template.\n *\n * Read from the environment rather than through `@aglyn/aglyn`'s\n * `platform-brand` / `constants`: `shared-util-email` is tagged `scope:shared`\n * and `@nx/enforce-module-boundaries` refuses the edge. Same defaults, so a\n * deployment that configures nothing sees exactly what it saw before.\n */\nconst SAMPLE_CONSOLE_ORIGIN: string =\n (process.env.NEXT_PUBLIC_CONSOLE_URL || '').trim().replace(/\\/+$/, '') ||\n 'https://app.aglyn.com'\n\n/**\n * The docs origin the getting-started emails' docs-link samples build on\n * (AGL-3692), read the way the console's `DOCS_BASE_URL` reads it. Only a\n * preview and test-send sample: the real send fills those links from the\n * console's own docs origin.\n */\nconst SAMPLE_DOCS_ORIGIN: string =\n (\n process.env.NEXT_PUBLIC_DOCS_ORIGIN ||\n process.env.NEXT_PUBLIC_AGLYN_DOCS_URL ||\n ''\n )\n .trim()\n .replace(/\\/+$/, '') || 'https://docs.aglyn.com'\n\n/**\n * Mirrors `PLATFORM_SUPPORT_URL`'s precedence, including the step that makes\n * the operator identity sufficient on its own: a configured support URL, else\n * the operator's support mailbox as a `mailto:`, else the console's own\n * support page.\n *\n * The last step is built from `SAMPLE_CONSOLE_ORIGIN` rather than written out\n * (AGL-3262). The support entry point is a CONSOLE route — `/support`\n * resolves the workspace from the session (AGL-3265) — so the origin it hangs\n * off is the one directly above, and an operator who set\n * `NEXT_PUBLIC_CONSOLE_URL` gets their own console in the sample instead of\n * ours. The literal it replaces was `aglyn.com/support`, which answers 404 and\n * never existed.\n */\nconst SAMPLE_SUPPORT_URL: string =\n (process.env.NEXT_PUBLIC_PLATFORM_SUPPORT_URL || '').trim() ||\n ((process.env.NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL || '').trim()\n ? `mailto:${(process.env.NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL || '').trim()}`\n : `${SAMPLE_CONSOLE_ORIGIN}/support`)\n\n// Deep import, NOT the barrel (AGL-1151): `@aglyn/shared-data-enums` re-exports\n// `firebase-auth`, whose `AuthErrorCodes` is a VALUE import of `firebase/auth`.\n// This module is reachable from the email plugin's site half, which a PUBLISHED\n// tenant page loads, so the barrel put the Firebase auth client into that\n// page's chunks for one brand constant.\nimport { BRAND } from '@aglyn/shared-data-enums/aglyn'\nimport { EMAIL_NODE_ROOT_ID } from './email-render'\nimport { RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES } from './risk-notice-emails'\nimport { retentionSystemEmailTemplates } from './retention-emails'\nimport { welcomeEmailMergeValues } from './welcome-email'\n\n/** The welcome email's next steps, as a new workspace's owner gets them. */\nconst WELCOME_SAMPLES = welcomeEmailMergeValues({\n orgName: 'Test Org',\n slug: 'test-org',\n consoleOrigin: SAMPLE_CONSOLE_ORIGIN,\n docsOrigin: SAMPLE_DOCS_ORIGIN,\n})\n\n/**\n * Who actually puts the message on the wire.\n *\n * `resend` — Aglyn composes and sends it, so a besigner template can change\n * what the recipient sees.\n *\n * `firebase` — Firebase Auth sends it from its own templates, configured in\n * the Firebase console. **A besigner template cannot affect these at all**\n * because the sender owns the copy (AGL-767).\n *\n * `stripe` — Stripe sends it on Aglyn's behalf from the Dashboard's\n * Customer-emails settings (billing receipts, dunning, refunds, expiring-card\n * notices). Aglyn never composes these, so like `firebase` they cannot be\n * designed here (AGL-767).\n *\n * The non-`resend` entries are listed so staff can see the full set of mail\n * the product sends and where each one is controlled; the UI must present\n * them as non-editable rather than offering an editor that silently does\n * nothing.\n */\n/**\n * Who actually puts the message on the wire.\n *\n * `'firebase'` was removed by AGL-1112, once nothing was left that Firebase\n * Auth composed. Deliberately not kept \"just in case\": with the variant gone,\n * reintroducing a Firebase-sent email is a compile error rather than a row in\n * a table that quietly stops being editable. The staff editor is wired to\n * `'resend'`, so any other value silently produces a template that renders\n * nothing — which is exactly how the `[aglyn.io]` subject survived so long.\n */\nexport type SystemEmailDeliveredBy = 'resend' | 'stripe'\n\nexport interface SystemEmailMergeToken {\n /** Token as written in the template, without braces. */\n name: string\n description: string\n /** Stand-in used by the staff preview. */\n sample: string\n}\n\n/**\n * One block of a template's starting content (AGL-764). Declarative on\n * purpose: the catalog stays a dependency-free data module, and the console\n * turns these into email-plugin nodes (`emailSection` → `emailText`/\n * `emailButton`) when it seeds the first version. Mirror the copy the send\n * site uses today, with the same `{{tokens}}`, so a staffer who opens the\n * editor starts from what recipients actually get rather than a blank canvas.\n */\nexport type SystemEmailDefaultBlock =\n | {\n block: 'text'\n text: string\n /**\n * `eyebrow` is a small muted line above a heading; `details` draws each\n * \"Label: value\" line as a row of a panel (AGL-3897).\n */\n variant?: 'heading' | 'subheading' | 'body' | 'caption' | 'eyebrow' | 'details' | 'links'\n }\n | { block: 'button'; label: string; href: string }\n /**\n * Markup composed per send, carried in whole by one token (AGL-3867): a\n * layout that text blocks cannot draw, such as the weekly summary's tiles.\n * Rendered as an `emailHtml` block, so it passes the same sanitizer as any\n * author's HTML, and its colors are the email theme's, resolved by the\n * sender.\n */\n | { block: 'html'; html: string }\n\nexport interface SystemEmailTemplateDefinition {\n /** Stable storage key — the Firestore document id. Never rename. */\n key: string\n name: string\n description: string\n deliveredBy: SystemEmailDeliveredBy\n /** Subject used when no template has been published. */\n defaultSubject: string\n mergeTokens: SystemEmailMergeToken[]\n /**\n * Starting content for the first version staff design (AGL-764). Every\n * `resend` template should carry one; a `firebase` template has no editor\n * so it needs none. Absent → the editor seeds a minimal placeholder.\n */\n defaultBody?: readonly SystemEmailDefaultBlock[]\n /**\n * The footer's \"why am I getting this\" line (AGL-3322), drawn under the\n * built-in copy, and under any design sent without the platform's own\n * email blocks.\n *\n * Written against the merge tokens, never a product name: on a white-label\n * send `{{brand.productName}}` is the agency's, and on a renamed deployment\n * it is the operator's, so one sentence is right for every sender. Like the\n * body, it may only use tokens the email declares — a token the send does\n * not supply is blanked, and leaves a hole in the sentence. Every `resend`\n * template carries one; the others are never rendered here.\n */\n footerReason?: string\n /**\n * Where the fallback copy lives, for staff wondering what recipients get\n * today. Informational — nothing reads it at runtime.\n */\n source: string\n}\n\n/**\n * Every system email Aglyn sends.\n *\n * Deliberately **code-defined and fixed**: staff edit the system emails that\n * exist, they do not create or delete them. Adding one is a code change,\n * which is what keeps this list from drifting into advertising an email the\n * product never actually sends — the failure mode a Firestore-backed list\n * would have.\n *\n * The staff page renders from this registry, not from Firestore, so an email\n * with no template designed yet still appears (as \"Using default\").\n */\n/**\n * Brand tokens EVERY system email resolves (AGL-2139).\n *\n * White-label used to invert precisely when staff published a template: the\n * designed template wins over each sender's branded fallback, and the copy\n * here hard-coded \"Aglyn\". Nor was there anything to design against — the\n * merge maps carried `org.name`, `invite.role`, `signInUrl` and friends and\n * nothing about the brand, while `blankUnresolvedTokens` DELETES any token\n * the caller did not supply, so a designer who typed `{{brand.productName}}`\n * would have shipped an email with a hole in the sentence.\n *\n * Declared once and appended to every template's own list rather than copied\n * into each: 13 hand-maintained copies is how the token list falls behind the\n * copy, and the editor renders this list as the palette a designer picks\n * from — a token missing here is a token nobody knows exists.\n *\n * The samples are the DEPLOYMENT's own values (`BRAND.ORG_NAME`, AGL-2319),\n * because that is what an unbranded org genuinely renders — on a self-host\n * install a hardcoded \"Aglyn\" would preview a brand that appears nowhere in\n * the mail the designer is editing.\n */\nexport const BRAND_MERGE_TOKENS: readonly SystemEmailMergeToken[] = [\n {\n name: 'brand.productName',\n description: \"The sender's product name — the org's own on white-label\",\n sample: BRAND.ORG_NAME,\n },\n {\n name: 'brand.fromName',\n description: 'Sender display name the mail is delivered under',\n sample: BRAND.ORG_NAME,\n },\n {\n name: 'brand.supportUrl',\n description: 'Where the recipient should go for help',\n sample: SAMPLE_SUPPORT_URL,\n },\n]\n\n// NOT declared: a `brand.logoUrl` token. The logo is STRUCTURAL — the\n// renderer emits it as a header row above the designed body, or emits\n// nothing — so a designer never places it, and a palette entry for it would\n// need a sample URL that a staff test-send would render as a broken image.\n// The three tokens above are the ones that belong in copy.\n\nconst BASE_SYSTEM_EMAIL_TEMPLATES: readonly SystemEmailTemplateDefinition[] =\n [\n {\n key: 'org-invite',\n name: 'Organization invite',\n description:\n 'Sent when an admin invites someone to an organization from the ' +\n 'Team page.',\n deliveredBy: 'resend',\n defaultSubject: \"You've been invited to {{org.name}} on {{brand.productName}}\",\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the inviting organization',\n sample: 'Test Org',\n },\n {\n name: 'invite.role',\n description: 'Role the person is invited as',\n sample: 'Editor',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to sign in and accept',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in invites/route.ts.\n defaultBody: [\n { block: 'text', text: 'Invitation · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Join {{org.name}} on {{brand.productName}}', variant: 'heading' },\n { block: 'text', text: 'You\\'ve been invited to join {{org.name}} as {{invite.role}}. Sign in with this email address and the invitation is waiting on your dashboard.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: {{invite.role}}', variant: 'details' },\n { block: 'button', label: 'Accept the invitation', href: '{{signInUrl}}' },\n { block: 'text', text: 'Not expecting this? You can ignore it. Nothing happens unless you accept.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone invited you to join ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/invites/route.ts',\n },\n {\n key: 'org-owner-handoff',\n name: 'Workspace handoff',\n description:\n 'Sent when the owner of a workspace, or the platform team, invites ' +\n 'someone to take the workspace over as its new owner.',\n deliveredBy: 'resend',\n defaultSubject: '{{org.name}} is being handed to you on {{brand.productName}}',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the workspace being handed over',\n sample: 'Test Org',\n },\n {\n name: 'handoff.previousOwner',\n description:\n 'What happens to the current owner once the handoff is accepted',\n sample: 'The current owner stays on as an admin.',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to sign in and accept',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallback text in invites/route.ts.\n defaultBody: [\n { block: 'text', text: 'Ownership transfer · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{org.name}} is being handed to you', variant: 'heading' },\n { block: 'text', text: 'You\\'ve been invited to take over {{org.name}} as its owner. The owner holds the workspace, every site in it, and its billing. {{handoff.previousOwner}}', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: Owner', variant: 'details' },\n { block: 'button', label: 'Review and accept', href: '{{signInUrl}}' },\n { block: 'text', text: 'Nothing changes until you accept. Sign in with this email address to see the invitation.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone invited you to take over ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/invites/route.ts',\n },\n {\n key: 'org-upgrade-proposal',\n name: 'Upgrade proposal',\n description:\n \"Sent to a workspace's owner when the platform team proposes a paid \" +\n 'plan for it, after the workspace has been evaluated.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} team proposed the {{plan.name}} plan for {{org.name}}',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the workspace the plan is proposed for',\n sample: 'Test Org',\n },\n {\n name: 'plan.name',\n description: 'The proposed plan',\n sample: 'Starter',\n },\n {\n name: 'proposal.note',\n description: 'A line from the team, or nothing when none was written',\n sample: 'As we discussed on Tuesday.',\n },\n {\n name: 'billingUrl',\n description: 'Billing page with the proposed plan preselected',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter`,\n },\n ],\n // Mirrors the fallback text in /api/admin/org-upgrade-proposal.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'The {{plan.name}} plan, proposed for {{org.name}}', variant: 'heading' },\n { block: 'text', text: 'Your {{brand.productName}} team proposed moving {{org.name}} to the {{plan.name}} plan.', variant: 'body' },\n { block: 'text', text: '{{proposal.note}}', variant: 'body' },\n { block: 'text', text: 'When you are ready, start the subscription from Billing. The plan is already selected there, beside the others so you can compare them first.', variant: 'body' },\n { block: 'button', label: 'Review the {{plan.name}} plan', href: '{{billingUrl}}' },\n { block: 'text', text: 'Nothing changes until you start the subscription.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you own {{org.name}} on ' +\n '{{brand.productName}} and its team proposed a plan for it.',\n source: 'apps/console/app/api/admin/org-upgrade-proposal/route.ts',\n },\n {\n key: 'usage-summary',\n name: 'Monthly usage summary',\n description:\n 'Monthly per-organization usage and metered-cost summary, sent by ' +\n 'the scheduled job.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} usage summary for {{month.label}}',\n mergeTokens: [\n {\n name: 'month',\n description: 'Billing month as YYYY-MM',\n sample: '2026-06',\n },\n {\n name: 'month.label',\n description: 'Billing month as a reader writes it',\n sample: 'June 2026',\n },\n {\n name: 'org.name',\n description: 'Organization the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'usage.summary',\n description: 'Pre-formatted usage lines',\n sample:\n 'Plan: Starter\\nPage views: 12,400\\n' +\n 'Metered usage beyond your plan: none, so nothing extra is billed for it.',\n },\n { name: 'billingUrl', description: 'The workspace Billing page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing` },\n ],\n // Mirrors the summary lines assembled in usage-email/route.ts.\n defaultBody: [\n { block: 'text', text: '{{month.label}} · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your usage for {{month.label}}', variant: 'heading' },\n { block: 'text', text: 'Here is how {{org.name}} used {{brand.productName}} in {{month.label}}: your plan, storage, page views and anything metered beyond the plan.', variant: 'body' },\n { block: 'text', text: '{{usage.summary}}', variant: 'details' },\n { block: 'text', text: 'Billing shows the full meters beside each plan limit, and the invoices for every month.', variant: 'body' },\n { block: 'button', label: 'Open billing', href: '{{billingUrl}}' },\n { block: 'text', text: 'Usage that goes over your plan is billed with the next invoice. A larger plan includes more, and you can compare them from Billing.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this monthly summary because you manage ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/billing/usage-email/route.ts',\n },\n {\n key: 'erasure-hold-alert',\n name: 'Erasure hold staff alert',\n description:\n 'Internal alert to STAFF_ALERT_EMAIL when GDPR erasure requests ' +\n 'pass their 7-day hold.',\n deliveredBy: 'resend',\n defaultSubject: '{{count}} erasure request(s) past the 7-day hold',\n mergeTokens: [\n {\n name: 'count',\n description: 'How many organizations are past the hold',\n sample: '3',\n },\n {\n name: 'orgs.list',\n description: 'The organizations, one per line',\n sample: 'Test Org (org_123) — requested 2026-07-01\\nNorth Bakery (org_456) — requested 2026-07-02',\n },\n { name: 'healthUrl', description: 'Staff → Health, where pending erasures can be run', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/health` },\n ],\n // Mirrors the staff-alert text in audit-archive/route.ts. It reports\n // and asks for nothing: `run-erasures` erases these orgs at 04:00 UTC,\n // an hour after this sends, and a failure raises its own alert.\n defaultBody: [\n { block: 'text', text: 'Staff · data erasure', variant: 'eyebrow' },\n { block: 'text', text: '{{count}} erasure request(s) past the hold', variant: 'heading' },\n { block: 'text', text: 'These workspaces are past their 7-day erasure hold. The nightly erasure job erases them at 04:00 UTC, five a run and oldest first, and keeps no copy, so nothing is needed from you.', variant: 'body' },\n { block: 'text', text: '{{orgs.list}}', variant: 'details' },\n { block: 'text', text: 'A workspace still listed tomorrow either failed to erase, which raises its own \"could not be erased\" alert, or is waiting behind a longer queue. Pending erasures on Staff → Health can run the due ones sooner.', variant: 'body' },\n { block: 'button', label: 'Open Staff → Health', href: '{{healthUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s staff alerts.',\n source: 'apps/console/app/api/admin/audit-archive/route.ts',\n },\n {\n key: 'welcome',\n name: 'Welcome',\n description:\n 'Sent to a new owner the first time they create an organization ' +\n '(not on every organization they later create).',\n deliveredBy: 'resend',\n defaultSubject: 'Welcome to {{brand.productName}}',\n mergeTokens: [\n {\n name: 'name',\n description: \"The new owner's display name\",\n sample: 'Alex',\n },\n {\n name: 'org.name',\n description: 'The organization they just created',\n sample: 'Test Org',\n },\n {\n name: 'consoleUrl',\n description: 'Console dashboard URL',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n { name: 'welcome.intro', description: 'What is ready, and what to do first, for how the workspace started', sample: WELCOME_SAMPLES['welcome.intro'] },\n { name: 'welcome.steps', description: 'The next steps, one per line, each \"Step — link\"', sample: WELCOME_SAMPLES['welcome.steps'] },\n ],\n // Mirrors the fallbackText in orgs/create/route.ts.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Welcome to {{brand.productName}}, {{name}}', variant: 'heading' },\n { block: 'text', text: '{{welcome.intro}}', variant: 'body' },\n { block: 'text', text: '{{welcome.steps}}', variant: 'links' },\n { block: 'button', label: 'Open {{org.name}}', href: '{{consoleUrl}}' },\n { block: 'text', text: 'Questions as you build? The guides answer most of them, and support is a click away: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you created an organization on ' +\n '{{brand.productName}}.',\n source: 'apps/console/app/api/orgs/create/route.ts',\n },\n {\n key: 'member-added',\n name: 'Added to an organization',\n description:\n `Sent when an existing ${BRAND.ORG_NAME} account is added directly ` +\n 'to an organization. People who do not have an account yet get the ' +\n 'organization invite email instead.',\n deliveredBy: 'resend',\n defaultSubject: \"You've been added to {{org.name}}\",\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization they were added to',\n sample: 'Test Org',\n },\n {\n name: 'member.role',\n description: 'Role they were given',\n sample: 'Editor',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to open the organization',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in orgs/members/route.ts.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'You’re in {{org.name}}', variant: 'heading' },\n { block: 'text', text: 'You were added to {{org.name}} as {{member.role}}. Sign in and pick it from the workspace menu to see its sites.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: {{member.role}}', variant: 'details' },\n { block: 'button', label: 'Open {{org.name}}', href: '{{signInUrl}}' },\n { block: 'text', text: 'Not expecting this? Ask whoever runs {{org.name}}, or contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you were added to {{org.name}} ' +\n 'on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/members/route.ts',\n },\n {\n key: 'erasure-confirmation',\n name: 'Erasure completed',\n description:\n 'Sent to an organization owner once its data has been permanently ' +\n 'erased under a GDPR request.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} data has been erased',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization that was erased',\n sample: 'Test Org',\n },\n ],\n // Mirrors the fallbackText in admin/run-erasures/route.ts.\n defaultBody: [\n { block: 'text', text: 'Data erasure · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your data has been erased', variant: 'heading' },\n { block: 'text', text: '{{org.name}} and all of its data have been permanently erased from {{brand.productName}}, as you asked. This is complete and cannot be undone.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nStatus: Erased', variant: 'details' },\n { block: 'text', text: 'Nothing more is needed from you. Your sign-in stays, so you can start a new workspace any time.', variant: 'body' },\n { block: 'text', text: 'Questions about the erasure? Contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you asked {{brand.productName}} ' +\n 'to erase {{org.name}}’s data.',\n source: 'apps/console/app/api/admin/run-erasures/route.ts',\n },\n {\n key: 'erasure-requested',\n name: 'Erasure requested',\n description:\n 'Confirms to an organization owner that a GDPR erasure request was ' +\n 'recorded, and that deletion follows after a 7-day hold.',\n deliveredBy: 'resend',\n defaultSubject: 'We received your erasure request',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization to be erased',\n sample: 'Test Org',\n },\n { name: 'erasure.date', description: 'The day the 7-day hold ends and erasure runs', sample: 'July 8, 2026' },\n ],\n // Mirrors the fallbackText in admin/erasure-request/route.ts.\n defaultBody: [\n { block: 'text', text: 'Data erasure · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your erasure request is recorded', variant: 'heading' },\n { block: 'text', text: 'We have recorded a request to erase {{org.name}} and all of its data from {{brand.productName}}: every site, form submission, order, file and member.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nErased on: {{erasure.date}}', variant: 'details' },\n { block: 'text', text: 'Erasure is permanent. It waits out a 7-day hold first, so if this was not intended, contact support before {{erasure.date}} and we will cancel it.', variant: 'body' },\n { block: 'button', label: 'Contact support', href: '{{brand.supportUrl}}' },\n { block: 'text', text: 'Want a copy of anything first? Export it from the workspace before the hold ends.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you own {{org.name}} on ' +\n '{{brand.productName}}.',\n source: 'apps/console/app/api/admin/erasure-request/route.ts',\n },\n // Admin-initiated password mail (AGL-910). Unlike the self-serve\n // `password-reset` below, Aglyn composes and sends these itself — the\n // reset LINK still comes from Firebase (generatePasswordResetLink), but\n // the message around it is ours, so both are designable.\n {\n key: 'admin-password-reset',\n name: 'Password reset (sent by an admin)',\n description:\n 'Password reset link sent on someone else\\'s behalf from the ' +\n 'console — by staff from a user\\'s detail page, or by an ' +\n 'organization admin from a team member\\'s page.',\n deliveredBy: 'resend',\n defaultSubject: 'Reset your {{brand.productName}} password',\n mergeTokens: [\n {\n name: 'resetUrl',\n description: 'One-time link that opens the reset form',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/reset-password?oobCode=…`,\n },\n {\n name: 'actor.name',\n description: 'Who asked for the reset',\n sample: '{{brand.productName}} support',\n },\n ],\n // Mirrors the fallbackText in _lib/password-admin.ts.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Reset your password', variant: 'heading' },\n { block: 'text', text: '{{actor.name}} started a password reset for your {{brand.productName}} account. Choose a new password with the button below.', variant: 'body' },\n { block: 'button', label: 'Set a new password', href: '{{resetUrl}}' },\n { block: 'text', text: 'The link works once and expires shortly. If you were not expecting this, ignore this email and your password stays as it is.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because an administrator started a ' +\n 'password reset for your {{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/password-admin.ts',\n },\n {\n key: 'password-changed-by-admin',\n name: 'Password changed by an admin',\n description:\n 'Notice sent to the account holder after an admin sets their ' +\n 'password directly. Always sent — it is how someone finds out an ' +\n 'administrator changed their credentials.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} password was changed',\n mergeTokens: [\n {\n name: 'actor.name',\n description: 'Who changed the password',\n sample: '{{brand.productName}} support',\n },\n {\n name: 'signInUrl',\n description: 'Where to sign in with the new password',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in _lib/password-admin.ts.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Your password was changed', variant: 'heading' },\n { block: 'text', text: '{{actor.name}} set a new password on your {{brand.productName}} account and signed you out everywhere. Sign back in with the new password.', variant: 'body' },\n { block: 'text', text: 'Changed by: {{actor.name}}', variant: 'details' },\n { block: 'button', label: 'Sign in', href: '{{signInUrl}}' },\n { block: 'text', text: 'If you did not expect this, contact whoever administers your account straight away, or support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because an administrator changed the ' +\n 'password on your {{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/password-admin.ts',\n },\n // Security alerts (AGL-665). Factual and actionable: what happened, from\n // where, and one button to the account-security surface. These must be\n // believed, so the send path only fires them on genuinely new devices —\n // never on every sign-in.\n {\n key: 'security-new-device',\n name: 'New device sign-in',\n description:\n 'Security alert sent when an account signs in from a device it has ' +\n 'not used before. Not sent on routine sign-ins from known devices.',\n deliveredBy: 'resend',\n defaultSubject: 'New sign-in to your {{brand.productName}} account',\n mergeTokens: [\n {\n name: 'device.name',\n description: 'Browser and operating system that signed in',\n sample: 'Chrome on macOS',\n },\n {\n name: 'device.location',\n description: 'Approximate location, from the request IP',\n sample: 'Denver, CO, US',\n },\n {\n name: 'device.ip',\n description: 'IP address the sign-in came from',\n sample: '203.0.113.7',\n },\n {\n name: 'device.time',\n description: 'When the sign-in happened (UTC)',\n sample: '2026-08-08 14:03 UTC',\n },\n {\n name: 'accountSecurityUrl',\n description:\n 'Manage-account Security section — Recent sign-ins, where the ' +\n 'device can be signed out, plus password and passkeys',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user/security`,\n },\n ],\n // Mirrors the fallbackText in _lib/security-alerts.ts.\n defaultBody: [\n { block: 'text', text: 'Security alert', variant: 'eyebrow' },\n { block: 'text', text: 'New device sign-in', variant: 'heading' },\n { block: 'text', text: 'Your {{brand.productName}} account was just signed in to from a device it has not used before.', variant: 'body' },\n { block: 'text', text: 'Device: {{device.name}}\\nLocation: {{device.location}}\\nIP address: {{device.ip}}\\nWhen: {{device.time}}', variant: 'details' },\n { block: 'text', text: 'If this was you, there is nothing to do. If it was not, sign this device out from Recent sign-ins and change your password right away.', variant: 'body' },\n { block: 'button', label: 'Review your devices', href: '{{accountSecurityUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because your {{brand.productName}} ' +\n 'account signed in from a new device.',\n source: 'apps/console/app/api/_lib/security-alerts.ts',\n },\n {\n key: 'security-passkey-added',\n name: 'New passkey added',\n description:\n 'Security alert sent when a passkey is registered on an account. ' +\n 'The trigger ships with passkey support (AGL-662); until then no ' +\n 'call site sends this.',\n deliveredBy: 'resend',\n defaultSubject: 'A passkey was added to your {{brand.productName}} account',\n mergeTokens: [\n {\n name: 'passkey.label',\n description: 'Name the passkey was saved under',\n sample: 'MacBook Touch ID',\n },\n {\n name: 'device.time',\n description: 'When the passkey was added (UTC)',\n sample: '2026-08-08 14:03 UTC',\n },\n {\n name: 'accountSecurityUrl',\n description: 'Manage-account page where credentials are reviewed',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user`,\n },\n ],\n // Mirrors the fallbackText in _lib/security-alerts.ts.\n defaultBody: [\n { block: 'text', text: 'Security alert', variant: 'eyebrow' },\n { block: 'text', text: 'New passkey added', variant: 'heading' },\n { block: 'text', text: 'A passkey was just added to your {{brand.productName}} account. It can sign you in without your password.', variant: 'body' },\n { block: 'text', text: 'Passkey: {{passkey.label}}\\nWhen: {{device.time}}', variant: 'details' },\n { block: 'text', text: 'If you added it, there is nothing to do. If you did not, remove it and change your password right away.', variant: 'body' },\n { block: 'button', label: 'Review account security', href: '{{accountSecurityUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because a passkey was added to your ' +\n '{{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/security-alerts.ts',\n },\n // Aglyn composes and sends both of these now (AGL-1112). They were\n // Firebase's, from a template nobody could edit — the subject still\n // carried `[aglyn.io]`, a domain the company no longer uses, and the link\n // landed on `aglyn-main.firebaseapp.com`. Neither could be fixed: every\n // write under `notification.sendEmail` is refused with\n // `EMAIL_TEMPLATE_UPDATE_NOT_ALLOWED`.\n //\n // Firebase still MINTS the one-time code, which is the part that has to\n // be its. Only the message around it, and the host the link points at,\n // became ours. So editing these here now does what it says.\n {\n key: 'password-reset',\n name: 'Forgot password',\n description:\n 'Password reset link, sent when someone asks for one from Account ' +\n 'recovery.',\n deliveredBy: 'resend',\n defaultSubject: 'Reset your {{brand.productName}} password',\n mergeTokens: [\n {\n name: 'resetUrl',\n description: 'One-time link that opens the choose-a-new-password page',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/reset-password?oobCode=\\u2026`,\n },\n ],\n // Mirrors the fallbackText in the route, so the designed and undesigned\n // versions say the same thing.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Reset your password', variant: 'heading' },\n { block: 'text', text: 'Someone asked to reset the password for your {{brand.productName}} account. If it was you, choose a new one with the button below.', variant: 'body' },\n { block: 'button', label: 'Choose a new password', href: '{{resetUrl}}' },\n { block: 'text', text: 'The link works once and expires shortly. If this was not you, ignore this email and your password stays as it is.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone asked to reset the ' +\n 'password on your {{brand.productName}} account.',\n source: 'apps/console/app/api/auth/send-password-reset/route.ts',\n },\n {\n key: 'email-verification',\n name: 'Confirm email',\n description:\n 'Address verification link, sent after sign-up and whenever someone ' +\n 'asks for another from the verify page.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email address',\n mergeTokens: [\n {\n name: 'verifyUrl',\n description: 'One-time link that confirms the address',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/verify-email?oobCode=\\u2026`,\n },\n ],\n defaultBody: [\n { block: 'text', text: 'One last step', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm your email', variant: 'heading' },\n { block: 'text', text: 'Confirm this address to finish setting up your {{brand.productName}} account. It keeps your account secure, and it is where we tell you about your sites: new form submissions, orders and bookings.', variant: 'body' },\n { block: 'button', label: 'Confirm my email', href: '{{verifyUrl}}' },\n { block: 'text', text: 'If you did not sign up for {{brand.productName}}, you can ignore this email.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address was used to sign ' +\n 'up for {{brand.productName}}.',\n source: 'apps/console/app/api/auth/send-verification/route.ts',\n },\n // Its own entry rather than a second use of the one above, because every\n // line of that one is about signing up: \"finish setting up your account\",\n // \"if you did not create an account\", a footer saying the address was\n // used to sign up. This mail goes to an address someone is ADDING to an\n // account that already exists, and the one thing its reader needs to hear\n // is that ignoring it changes nothing.\n {\n key: 'email-address-confirmation',\n name: 'Confirm added email',\n description:\n 'Confirmation link, sent when someone adds another email address to ' +\n 'their account under Manage Account → Email addresses.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email address',\n mergeTokens: [\n {\n name: 'confirmUrl',\n description: 'One-time link that adds the address to the account',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user?confirmEmail=…`,\n },\n ],\n // Mirrors the fallbackText in the route.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm this email address', variant: 'heading' },\n { block: 'text', text: 'Confirm this address to add it to your {{brand.productName}} account. Once it is confirmed you can sign in with it and choose it for your email.', variant: 'body' },\n { block: 'button', label: 'Confirm email address', href: '{{confirmUrl}}' },\n { block: 'text', text: 'If you did not ask to add this address, ignore this email. Nothing has changed, and the address has not been added to any account.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone asked to add this address ' +\n 'to a {{brand.productName}} account.',\n source: 'apps/console/app/api/account/emails/route.ts',\n },\n // AGL-3691. A message a staffer writes to one account from its staff\n // page, sent in the platform's design. The subject heads the body, so the\n // email states its topic even to a reader who skipped the subject line\n // (AGL-3432). It leaves from the platform sender with Reply-To set to the\n // staffer, so an answer reaches a person rather than `noreply@`.\n {\n key: 'staff-follow-up',\n name: 'Follow-up from the team',\n description:\n 'A message a staff member writes to one account from its page in ' +\n 'the staff console, sent in the platform design. Replies go to the ' +\n 'staff member who sent it.',\n deliveredBy: 'resend',\n defaultSubject: '{{message.subject}}',\n mergeTokens: [\n {\n name: 'name',\n description: \"The account holder's first name, or nothing\",\n sample: 'Alex',\n },\n {\n name: 'message.subject',\n description: 'What the message is about, in one line',\n sample: 'Your site is ready to publish',\n },\n {\n name: 'message.body',\n description: 'The message itself, as the staff member wrote it',\n sample:\n 'I saw you started a site yesterday. Reply here if anything ' +\n 'got in the way and I will sort it out.',\n },\n {\n name: 'sender.name',\n description: 'The staff member who wrote it',\n sample: 'Zach',\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{message.subject}}', variant: 'heading' },\n { block: 'text', text: 'Hi {{name}},', variant: 'body' },\n { block: 'text', text: '{{message.body}}', variant: 'body' },\n { block: 'text', text: '{{sender.name}}\\n{{brand.productName}}', variant: 'body' },\n { block: 'text', text: 'Reply to this email to reach {{sender.name}} directly.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you have a {{brand.productName}} ' +\n 'account and our team wrote to you about it.',\n source: 'apps/console/app/api/admin/users/system-email/route.ts',\n },\n // AGL-3367. The platform's other senders, each of which composed its\n // own plain text and so went out with no header or footer. A sender whose\n // message is assembled per send (a digest's list, an alert's figures)\n // hands its composed text in as one body token: the built-in copy is that\n // text in the brand's chrome, and a design can wrap it in anything else.\n {\n key: 'notification',\n name: 'Notification',\n description:\n 'The email copy of a console notification, sent to people who ' +\n 'turned email on for that kind of notification: staff alerts, ' +\n 'workspace-admin and site-manager notices.',\n deliveredBy: 'resend',\n defaultSubject: '{{notification.title}}',\n mergeTokens: [\n {\n name: 'notification.title',\n description: 'The notification, in one line',\n sample: 'Subscription canceled',\n },\n {\n name: 'notification.body',\n description: 'The detail under it, when it has any',\n sample: 'Test Org canceled, leaving the Advanced plan.',\n },\n {\n name: 'notification.details',\n description:\n 'What the email alone carries, one line each, when there is any: ' +\n 'a form submission’s answers',\n sample: 'Name: Jane Doe\\nEmail: jane@example.com\\nMessage: Do you deliver on Saturdays?',\n },\n {\n name: 'notification.context',\n description: 'The site and workspace it is about, when it is about one',\n sample: 'Copper Kettle Catering · Test Org',\n },\n {\n name: 'notification.action',\n description: 'What the button opens: \"View submission\", \"View order\", or \"Open in\" the product',\n sample: 'View submission',\n },\n {\n name: 'notification.replyNote',\n description: 'Who a reply reaches, when it reaches the person who wrote in',\n sample: 'Reply to this email to answer maria.delgado@example.com.',\n },\n {\n name: 'notification.url',\n description: 'Where the notification opens in the console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications`,\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where email can be turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{notification.context}}', variant: 'eyebrow' },\n { block: 'text', text: '{{notification.title}}', variant: 'heading' },\n { block: 'text', text: '{{notification.body}}', variant: 'body' },\n { block: 'text', text: '{{notification.details}}', variant: 'details' },\n { block: 'button', label: '{{notification.action}}', href: '{{notification.url}}' },\n { block: 'text', text: '{{notification.replyNote}}', variant: 'caption' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this because email is on for these ' +\n 'notifications in your {{brand.productName}} settings.',\n source: 'libs/tenant/data/admin/src/lib/server/notifications.ts',\n },\n {\n key: 'staff-alert',\n name: 'Staff alert',\n description:\n 'Operational alerts to STAFF_ALERT_EMAIL: free-tier AI spend, usage ' +\n 'margins, SSO re-verification and the like.',\n deliveredBy: 'resend',\n defaultSubject: '{{alert.subject}}',\n mergeTokens: [\n {\n name: 'alert.subject',\n description: 'The alert, in one line',\n sample: 'Free AI spend at 80% of today’s ceiling',\n },\n {\n name: 'alert.body',\n description: 'The alert as its sender wrote it',\n sample: 'Free-tier AI spend for 2026-09-28 (UTC) is at $40.00 of the $50.00 ceiling.',\n },\n { name: 'alert.url', description: 'Where the alert is handled; the staff console when the sender names nowhere', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/lockdown` },\n { name: 'alert.urlLabel', description: 'The button’s words for that page', sample: 'Open Staff → Lockdown' },\n ],\n // The subject heads the body (AGL-3432): a reader who skips the\n // subject line still sees what the alert is about.\n defaultBody: [\n { block: 'text', text: 'Staff alert', variant: 'eyebrow' },\n { block: 'text', text: '{{alert.subject}}', variant: 'heading' },\n { block: 'text', text: '{{alert.body}}', variant: 'body' },\n { block: 'button', label: '{{alert.urlLabel}}', href: '{{alert.url}}' },\n { block: 'text', text: 'Sent to the staff alert inbox. Every alert is also on Staff → Overview.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s staff alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/staff-alert-email.ts',\n },\n {\n key: 'operator-alert',\n name: 'Operator alert',\n description:\n 'Emailed to the operator for every operator alert delivered right ' +\n 'away: fraud and risk, a lost dispute, a failed erasure, a degraded ' +\n 'health check, a webhook failing its signature, and every other type ' +\n 'listed on Staff → Operator alerts. Goes to STAFF_ALERT_EMAIL, else ' +\n 'the operator support address, else every staff account.',\n deliveredBy: 'resend',\n defaultSubject: '{{alert.title}}',\n mergeTokens: [\n {\n name: 'alert.title',\n description: 'The alert, in one line',\n sample: 'Card testing on northwind.test',\n },\n {\n name: 'alert.body',\n description: 'What happened, as staff are told it',\n sample:\n '38 declined card attempts in 10 minutes on the checkout of ' +\n 'northwind.test. Checkout is rate limited while this is reviewed.',\n },\n {\n name: 'alert.url',\n description: 'The item in the staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/abuse-reports`,\n },\n { name: 'alert.eyebrow', description: 'The alert’s level and area', sample: 'Must know · Payments & payouts' },\n { name: 'alert.details', description: 'Which alert, which workspace or site, and when, as \"Label: value\" lines', sample: 'Alert: Card testing\\nLevel: Must know\\nSite id: host_123\\nRaised: 2026-09-28 14:03 UTC' },\n { name: 'settingsUrl', description: 'Staff → Operator alerts', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/operator-alerts` },\n ],\n defaultBody: [\n { block: 'text', text: '{{alert.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{alert.title}}', variant: 'heading' },\n { block: 'text', text: '{{alert.body}}', variant: 'body' },\n { block: 'text', text: '{{alert.details}}', variant: 'details' },\n { block: 'button', label: 'Review it', href: '{{alert.url}}' },\n { block: 'text', text: 'Choose which alerts email you, and which wait for the daily digest, on Staff → Operator alerts: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s operator alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/operator-alerts.ts',\n },\n {\n key: 'operator-alert-digest',\n name: 'Operator alert digest',\n description:\n 'Once a day, every operator alert set to the digest on Staff → ' +\n 'Operator alerts — new support tickets and replies, listings waiting ' +\n 'for review, and any type staff moved there — in one email. Goes to ' +\n 'the same inbox as the operator alert.',\n deliveredBy: 'resend',\n defaultSubject: '{{digest.title}}',\n mergeTokens: [\n {\n name: 'digest.title',\n description: 'The count and the day, in one line, “alert” or “alerts” as the count needs',\n sample: '3 operator alerts on 2026-09-28',\n },\n {\n name: 'digest.date',\n description: 'The day the digest covers, UTC',\n sample: '2026-09-28',\n },\n {\n name: 'digest.count',\n description: 'How many alerts it holds',\n sample: '3',\n },\n {\n name: 'digest.body',\n description: 'The alerts, one paragraph each',\n sample:\n '• New support ticket: Checkout button missing\\n' +\n 'northwind opened a ticket.\\n\\n' +\n '• Plugin listing waiting for review\\n' +\n 'Acme Forms 2.1.0 was submitted for review.',\n },\n {\n name: 'digest.url',\n description: 'The staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/operator-alerts`,\n },\n ],\n defaultBody: [\n { block: 'text', text: 'Daily digest · {{digest.date}}', variant: 'eyebrow' },\n { block: 'text', text: '{{digest.title}}', variant: 'heading' },\n { block: 'text', text: 'The routine alerts from the last day, batched so they arrive together. None of them needed you right away.', variant: 'body' },\n { block: 'text', text: '{{digest.body}}', variant: 'body' },\n { block: 'button', label: 'Open operator alerts', href: '{{digest.url}}' },\n { block: 'text', text: 'Choose which alerts wait for this digest on Staff → Operator alerts.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s operator alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/operator-alerts.ts',\n },\n {\n key: 'support-ticket-alert',\n name: 'Support ticket to success manager',\n description:\n 'Copies an organization’s named success manager on a support ticket ' +\n 'it opened or replied to.',\n deliveredBy: 'resend',\n defaultSubject: '{{ticket.heading}} — {{org.name}}: {{ticket.subject}}',\n mergeTokens: [\n {\n name: 'ticket.heading',\n description: '“New ticket” or “Ticket reply”',\n sample: 'New ticket',\n },\n {\n name: 'ticket.subject',\n description: 'The ticket’s subject',\n sample: 'Domain will not verify',\n },\n {\n name: 'ticket.body',\n description: 'Who wrote, and what they wrote',\n sample: 'Test Org opened a support ticket.\\nFrom: owner@example.com',\n },\n {\n name: 'ticket.url',\n description: 'The ticket in the staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/support`,\n },\n {\n name: 'manager.name',\n description: 'The success manager’s name',\n sample: 'Sam',\n },\n {\n name: 'org.name',\n description: 'The organization the ticket is from',\n sample: 'Test Org',\n },\n { name: 'ticket.opening', description: 'Who opened or replied, as one sentence', sample: 'Test Org opened a support ticket.' },\n { name: 'ticket.message', description: 'What the customer wrote', sample: 'We added the TXT record yesterday and the domain still says pending.' },\n { name: 'ticket.details', description: 'The workspace, sender, subject and ticket id as \"Label: value\" lines', sample: 'Workspace: Test Org\\nFrom: owner@example.com\\nSubject: Domain will not verify\\nTicket id: tkt_123' },\n ],\n defaultBody: [\n { block: 'text', text: '{{ticket.heading}} · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{ticket.subject}}', variant: 'heading' },\n { block: 'text', text: '{{manager.name}}, {{ticket.opening}} You are its success manager, so it is copied to you.', variant: 'body' },\n { block: 'text', text: '{{ticket.details}}', variant: 'details' },\n { block: 'text', text: '{{ticket.message}}', variant: 'body' },\n { block: 'button', label: 'Open the ticket', href: '{{ticket.url}}' },\n { block: 'text', text: 'Answer from Staff → Support so the reply is threaded on the ticket and the customer sees it in their console.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you are the success manager for ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/_lib/success-manager.ts',\n },\n {\n key: 'workspace-notice',\n name: 'Workspace notice',\n description:\n 'Operational notices to a workspace’s people: usage alerts and SSO ' +\n 'domain lapses to its owners and admins, and a stopped outreach ' +\n 'mailbox to the member who connected it.',\n deliveredBy: 'resend',\n defaultSubject: '{{notice.subject}}',\n mergeTokens: [\n {\n name: 'notice.subject',\n description: 'The notice, in one line',\n sample: 'Sequences paused your mailbox avery@example.com',\n },\n {\n name: 'notice.body',\n description: 'The notice as its sender wrote it',\n sample: 'Sequences paused the mailbox Avery Quinn <avery@example.com>.\\n\\nSequences paused it after 3 bounces in a row.',\n },\n {\n name: 'org.name',\n description: 'The workspace the notice is about',\n sample: 'Test Org',\n },\n { name: 'notice.lead', description: 'What happened and what to do, without the link', sample: 'Sequences paused avery@example.com after 3 bounces in a row. 4 enrollments are active on it and waiting. Re-check the addresses, then open Mailboxes and select Resume.' },\n { name: 'notice.details', description: 'The facts, as \"Label: value\" lines', sample: 'Mailbox: avery@example.com\\nStatus: Paused by Sequences\\nEnrollments waiting: 4' },\n { name: 'notice.url', description: 'Where the reader acts on it', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/outreach/mailboxes` },\n { name: 'notice.action', description: 'The button’s words', sample: 'Open Mailboxes to resume' },\n { name: 'notice.reason', description: 'Why this reader is getting it', sample: 'You are getting this because the mailbox is yours, or you manage the organization it belongs to.' },\n ],\n // The subject heads the body (AGL-3432): a reader who skips the\n // subject line still sees what the notice is about.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{notice.subject}}', variant: 'heading' },\n { block: 'text', text: '{{notice.lead}}', variant: 'body' },\n { block: 'text', text: '{{notice.details}}', variant: 'details' },\n { block: 'button', label: '{{notice.action}}', href: '{{notice.url}}' },\n { block: 'text', text: '{{notice.reason}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you’re a member of {{org.name}} on ' +\n '{{brand.productName}}.',\n source: 'libs/tenant/data/admin/src/lib/server/org-member-notice.ts',\n },\n {\n key: 'member-email-alias-confirmation',\n name: 'Member email address confirmation',\n description:\n 'Sent to an address a workspace member asked to add as one of their ' +\n 'own, so mail from it is filed under the people it was written to.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your address for {{org.name}}',\n mergeTokens: [\n {\n name: 'member.name',\n description: 'The member who asked',\n sample: 'Alex',\n },\n {\n name: 'address',\n description: 'The address being confirmed',\n sample: 'alex@example.com',\n },\n {\n name: 'org.name',\n description: 'The workspace',\n sample: 'Test Org',\n },\n {\n name: 'confirmUrl',\n description: 'The one-time confirmation link',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/account`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm this address', variant: 'heading' },\n { block: 'text', text: '{{member.name}} asked to add {{address}} as one of their own email addresses in {{org.name}}. Open the link while signed in as that member to confirm it.', variant: 'body' },\n { block: 'text', text: 'Address: {{address}}\\nWorkspace: {{org.name}}\\nFor: {{member.name}}', variant: 'details' },\n { block: 'button', label: 'Confirm the address', href: '{{confirmUrl}}' },\n { block: 'text', text: 'Once confirmed, email sent from {{address}} with the workspace’s capture address in BCC is filed under the person it was written to. The link works for 24 hours. If you did not expect this, ignore it.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because a member of {{org.name}} on ' +\n '{{brand.productName}} asked to add this address to their account.',\n source: 'libs/tenant/data/admin/src/lib/server/member-email-aliases.ts',\n },\n {\n key: 'crm-daily-digest',\n name: 'Daily CRM digest',\n description:\n 'Each morning, a member’s overdue and due-today tasks and unworked ' +\n 'leads, for members who turned the digest on.',\n deliveredBy: 'resend',\n defaultSubject: '{{digest.subject}}',\n mergeTokens: [\n {\n name: 'digest.subject',\n description: 'The summary line',\n sample: '2 tasks overdue, 3 new leads',\n },\n {\n name: 'digest.body',\n description: 'The tasks and leads, one per line, with their links',\n sample: 'Overdue (2)\\n- Call back Jordan · Sep 27, 9:00 AM',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the digest is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n { name: 'digest.eyebrow', description: 'The workspace and the day', sample: 'Test Org · Friday, September 28' },\n { name: 'digest.summary', description: 'What is owed today, in one line', sample: '1 task due today, 2 overdue, 3 unworked leads.' },\n { name: 'digest.overdueHeading', description: 'The overdue list’s heading, empty when there is none', sample: 'Overdue (2)' },\n { name: 'digest.overdue', description: 'Overdue tasks, one \"Title — when\" per line', sample: 'Call back Jordan — Main site · Thu, Sep 27, 9:00 AM CDT\\nSend the proposal — Fri, Sep 28, 8:00 AM CDT' },\n { name: 'digest.todayHeading', description: 'The due-today list’s heading', sample: 'Due today (1)' },\n { name: 'digest.today', description: 'Tasks due today, one per line', sample: 'Follow up with Priya — Main site · Fri, Sep 28, 3:00 PM CDT' },\n { name: 'digest.leadsHeading', description: 'The unworked leads list’s heading', sample: 'Unworked leads (3)' },\n { name: 'digest.leads', description: 'Unworked leads, one \"Name — site · first seen\" per line', sample: 'Jane Doe — Main site · first seen Sep 26\\nsam@example.com — Main site · first seen Sep 27' },\n { name: 'digest.nurturing', description: 'The leads in sequences or campaigns, or empty', sample: '2 leads are in sequences or campaigns.' },\n { name: 'digest.url', description: 'Where the reader starts: the Tasks section, else the leads', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks` },\n { name: 'digest.action', description: 'The button’s words', sample: 'Open your tasks' },\n { name: 'digest.links', description: 'Each site’s leads, one \"Leads on Site — URL\" per line', sample: `Leads on Main site — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/leads` },\n ],\n defaultBody: [\n { block: 'text', text: '{{digest.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your day in the CRM', variant: 'heading' },\n { block: 'text', text: '{{digest.summary}}', variant: 'body' },\n { block: 'text', text: '{{digest.overdueHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.overdue}}', variant: 'details' },\n { block: 'text', text: '{{digest.todayHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.today}}', variant: 'details' },\n { block: 'text', text: '{{digest.leadsHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.leads}}', variant: 'details' },\n { block: 'text', text: '{{digest.nurturing}}', variant: 'caption' },\n { block: 'button', label: '{{digest.action}}', href: '{{digest.url}}' },\n { block: 'text', text: '{{digest.links}}', variant: 'links' },\n { block: 'text', text: 'Turn the digest off, or change what you are emailed about: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this each morning because the Daily CRM digest is ' +\n 'on in your {{brand.productName}} notification settings.',\n source: 'libs/plugins/crm/src/lib/server/daily-digest-route.ts',\n },\n {\n key: 'crm-task-reminder',\n name: 'CRM task reminder',\n description: 'A reminder for CRM tasks that have come due.',\n deliveredBy: 'resend',\n defaultSubject: '{{reminder.subject}}',\n mergeTokens: [\n {\n name: 'reminder.subject',\n description: 'The task, or how many are due',\n sample: 'Reminder: Call back Jordan',\n },\n {\n name: 'reminder.body',\n description: 'The tasks, each with its link',\n sample: '- Call back Jordan · due today at 9:00 AM',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where reminders are turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n { name: 'reminder.eyebrow', description: 'The workspace the task is in', sample: 'Test Org' },\n { name: 'reminder.intro', description: 'What this is, in one sentence', sample: 'A reminder about your task. Open it to see the contact or deal it is for.' },\n { name: 'reminder.details', description: 'Each task as \"Title — due …\"', sample: 'Call back Jordan — due today at 9:00 AM CDT' },\n { name: 'reminder.url', description: 'The task, or the first one when there are several', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1` },\n { name: 'reminder.action', description: 'The button’s words', sample: 'Open the task' },\n { name: 'reminder.links', description: 'For several tasks, each one’s link as \"Title — URL\"; empty for one', sample: `Call back Jordan — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1\\nSend the proposal — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-2` },\n ],\n defaultBody: [\n { block: 'text', text: '{{reminder.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{reminder.subject}}', variant: 'heading' },\n { block: 'text', text: '{{reminder.intro}}', variant: 'body' },\n { block: 'text', text: '{{reminder.details}}', variant: 'details' },\n { block: 'button', label: '{{reminder.action}}', href: '{{reminder.url}}' },\n { block: 'text', text: '{{reminder.links}}', variant: 'links' },\n { block: 'text', text: 'Change what you are emailed about: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because task reminders are on in your ' +\n '{{brand.productName}} notification settings.',\n source: 'libs/plugins/crm/src/lib/server/task-reminders-route.ts',\n },\n {\n key: 'ai-insights-digest',\n name: 'Weekly insights digest',\n description:\n 'The week’s AI insights for a site, for members who turned the ' +\n 'digest on for that workspace.',\n deliveredBy: 'resend',\n defaultSubject: 'Your weekly insights for {{site.name}}',\n mergeTokens: [\n {\n name: 'site.name',\n description: 'The site the insights are about',\n sample: 'Test Site',\n },\n {\n name: 'digest.body',\n description: 'The insights, numbered, with their links',\n sample: '1. Visits from search rose 18% on last week.',\n },\n { name: 'digest.eyebrow', description: 'The workspace and the week', sample: 'Test Org · Oct 5 – Oct 11' },\n { name: 'digest.intro', description: 'What the insights are, in one sentence', sample: 'What Test Site\\'s figures showed last week. Each one is traced to the figures it cites, so you can check it on the Analytics page.' },\n { name: 'digest.insights', description: 'The insights, numbered', sample: '1. Visits from search rose 18% on last week.\\n\\n2. The pricing page was the most viewed page, with 312 views.' },\n { name: 'digest.analyticsUrl', description: 'The site’s Analytics page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/hosts/test-site/analytics` },\n { name: 'digest.why', description: 'Why it came, what it cost and how to turn it off', sample: `You asked for weekly insights for Test Org. Writing these used 21 of Test Org’s AI credits. Turn them off in Notifications: ${SAMPLE_CONSOLE_ORIGIN}/manage/notifications` },\n ],\n defaultBody: [\n { block: 'text', text: '{{digest.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: 'Weekly insights for {{site.name}}', variant: 'heading' },\n { block: 'text', text: '{{digest.intro}}', variant: 'body' },\n { block: 'text', text: '{{digest.insights}}', variant: 'body' },\n { block: 'button', label: 'Open {{site.name}} analytics', href: '{{digest.analyticsUrl}}' },\n { block: 'text', text: '{{digest.why}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you turned on weekly insights in ' +\n '{{brand.productName}}.',\n source: 'libs/plugins/ai/src/lib/insights/ai-insight-digest.ts',\n },\n {\n key: 'weekly-summary',\n name: 'Weekly summary · workspace',\n description:\n 'Each Monday, how a workspace did the week before: its totals across ' +\n 'sites, a line for each site, and its deals. For its owners and ' +\n 'admins. Free: nothing is generated.',\n deliveredBy: 'resend',\n defaultSubject: '{{summary.subject}}',\n mergeTokens: [\n {\n name: 'summary.subject',\n description: 'The subject line, leading with the week’s figures',\n sample: 'Your week at Test Org: 1,204 visitors, 9 new leads, 6 bookings',\n },\n {\n name: 'summary.title',\n description: 'The heading',\n sample: 'Test Org last week',\n },\n {\n name: 'summary.period',\n description: 'The week the figures cover',\n sample: 'Oct 5 – Oct 11, compared with the week before',\n },\n {\n name: 'summary.html',\n description: 'The figures, drawn as tiles and ranked lists in the email’s theme',\n sample: '<div style=\"padding:16px 0 8px;\"><div style=\"font-family:Helvetica, Arial, sans-serif;font-size:12px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;\">Traffic</div></div>',\n },\n {\n name: 'summary.buttonLabel',\n description: 'The button’s words',\n sample: 'Open Test Org',\n },\n {\n name: 'summary.url',\n description: 'Where the button goes',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org`,\n },\n {\n name: 'org.name',\n description: 'The workspace the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the summary is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{summary.title}}', variant: 'heading' },\n { block: 'text', text: '{{summary.period}}', variant: 'caption' },\n { block: 'html', html: '{{summary.html}}' },\n { block: 'button', label: '{{summary.buttonLabel}}', href: '{{summary.url}}' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this each Monday because you manage {{org.name}} and ' +\n 'the Weekly summary is on in your {{brand.productName}} notification settings.',\n source: 'libs/tenant/data/admin/src/lib/server/weekly-summary.ts',\n },\n {\n key: 'weekly-summary-site',\n name: 'Weekly summary · site',\n description:\n 'Each Monday, how one site did the week before — visitors, top pages, ' +\n 'sources, forms, new leads, bookings, sales, campaigns and more — for ' +\n 'the workspace’s owners and admins and the site’s own admins. Free: ' +\n 'nothing is generated.',\n deliveredBy: 'resend',\n defaultSubject: '{{summary.subject}}',\n mergeTokens: [\n {\n name: 'summary.subject',\n description: 'The subject line, leading with the week’s figures',\n sample: 'Test Site last week: 1,204 visitors, 9 new leads',\n },\n {\n name: 'summary.title',\n description: 'The heading',\n sample: 'Test Site last week',\n },\n {\n name: 'summary.period',\n description: 'The week the figures cover',\n sample: 'Oct 5 – Oct 11, compared with the week before',\n },\n {\n name: 'summary.html',\n description: 'The figures, drawn as tiles and ranked lists in the email’s theme',\n sample: '<div style=\"padding:16px 0 8px;\"><div style=\"font-family:Helvetica, Arial, sans-serif;font-size:12px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;\">Traffic</div></div>',\n },\n {\n name: 'summary.buttonLabel',\n description: 'The button’s words',\n sample: 'Open Test Site',\n },\n {\n name: 'summary.url',\n description: 'Where the button goes',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/hosts/test-site`,\n },\n {\n name: 'org.name',\n description: 'The workspace the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the summary is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{summary.title}}', variant: 'heading' },\n { block: 'text', text: '{{summary.period}}', variant: 'caption' },\n { block: 'html', html: '{{summary.html}}' },\n { block: 'button', label: '{{summary.buttonLabel}}', href: '{{summary.url}}' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this each Monday because you manage {{org.name}} and ' +\n 'the Weekly summary is on in your {{brand.productName}} notification settings.',\n source: 'libs/tenant/data/admin/src/lib/server/weekly-summary.ts',\n },\n {\n key: 'legal-intake-receipt',\n name: 'Report and notice receipt',\n description:\n 'The receipt for an abuse report, a copyright notice or a ' +\n 'counter-notice, carrying its reference.',\n deliveredBy: 'resend',\n defaultSubject: '{{receipt.subject}}',\n mergeTokens: [\n {\n name: 'receipt.subject',\n description: 'What was received, and its reference',\n sample: 'Report received — AR-3F9K2',\n },\n {\n name: 'receipt.body',\n description: 'The receipt as the intake wrote it',\n sample: 'We have received your report about https://example.com.\\n\\nYour reference is AR-3F9K2.',\n },\n { name: 'receipt.eyebrow', description: 'The reference', sample: 'Receipt · AR-3F9K2' },\n { name: 'receipt.heading', description: 'What was received', sample: 'We received your report' },\n { name: 'receipt.intro', description: 'What it was about', sample: 'We have received your report about https://example.com.' },\n { name: 'receipt.details', description: 'Reference, address and time, as \"Label: value\" lines', sample: 'Reference: AR-3F9K2\\nAbout: https://example.com\\nReceived: 2026-09-28 14:03 UTC' },\n { name: 'receipt.next', description: 'What happens next', sample: 'We do not publish what we decide about individual sites, and we will not share your details with the site\\'s owner unless the law requires it.' },\n { name: 'receipt.keep', description: 'Keep this email, and the sign-off', sample: 'Keep this email. It is your record that we received the message above, and the reference is how we will find it if you write to us about it.' },\n ],\n defaultBody: [\n { block: 'text', text: '{{receipt.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{receipt.heading}}', variant: 'heading' },\n { block: 'text', text: '{{receipt.intro}}', variant: 'body' },\n { block: 'text', text: '{{receipt.details}}', variant: 'details' },\n { block: 'text', text: 'What happens next', variant: 'subheading' },\n { block: 'text', text: '{{receipt.next}}', variant: 'body' },\n { block: 'text', text: '{{receipt.keep}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address was given on a report ' +\n 'or notice sent to {{brand.productName}}.',\n source: 'apps/tenant/app/api/_legal-intake/acknowledge.ts',\n },\n {\n key: 'plugin-review-update',\n name: 'Plugin review update',\n description:\n 'Tells a marketplace publisher’s owners and admins what review ' +\n 'decided about their submission.',\n deliveredBy: 'resend',\n defaultSubject: '{{review.subject}}',\n mergeTokens: [\n {\n name: 'review.subject',\n description: 'The decision, in one line',\n sample: 'Your plugin was approved',\n },\n {\n name: 'review.body',\n description: 'The decision as review wrote it',\n sample: 'Test Plugin 1.2.0 passed review and is live in the marketplace.',\n },\n { name: 'review.details', description: 'Plugin, version and outcome as \"Label: value\" lines', sample: 'Plugin: Test Plugin\\nVersion: 1.2.0\\nOutcome: Approved' },\n { name: 'review.url', description: 'The publisher’s Marketplace page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/marketplace` },\n ],\n defaultBody: [\n { block: 'text', text: 'Marketplace review', variant: 'eyebrow' },\n { block: 'text', text: '{{review.subject}}', variant: 'heading' },\n { block: 'text', text: '{{review.body}}', variant: 'body' },\n { block: 'text', text: '{{review.details}}', variant: 'details' },\n { block: 'button', label: 'Open your marketplace listings', href: '{{review.url}}' },\n { block: 'text', text: 'Questions about a review? Contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you manage a plugin published on ' +\n '{{brand.productName}}.',\n source: 'libs/plugins/marketplace/src/lib/server/publisher-review-email.ts',\n },\n // Stripe-delivered billing email (AGL-767). Aglyn never composes these —\n // Stripe sends them from the Dashboard's Customer-emails and Subscription\n // settings, so they are listed for visibility only and are not designable.\n // Whether each actually sends is a Dashboard toggle the code cannot read;\n // the descriptions say \"if enabled\" rather than asserting it is on.\n {\n key: 'stripe-receipt',\n name: 'Payment receipt',\n description:\n 'Receipt for a successful subscription or invoice payment. Sent by ' +\n 'Stripe if \"Successful payments\" is enabled under Customer emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your receipt from ${BRAND.ORG_NAME}`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n {\n key: 'stripe-payment-failed',\n name: 'Payment failed',\n description:\n 'Dunning notice when a subscription charge fails and Stripe retries ' +\n 'it. Sent by Stripe if failed-payment emails are enabled under ' +\n 'Subscriptions and emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} payment could not be processed`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Subscriptions and emails',\n },\n {\n key: 'stripe-refund',\n name: 'Refund confirmation',\n description:\n 'Confirms a refund back to the customer. Sent by Stripe if ' +\n '\"Refunds\" is enabled under Customer emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} refund`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n {\n key: 'stripe-card-expiring',\n name: 'Card expiring soon',\n description:\n 'Reminder that the card on file is about to expire. Sent by Stripe ' +\n 'if expiring-card reminders are enabled under Subscriptions and ' +\n 'emails.',\n deliveredBy: 'stripe',\n defaultSubject: 'Your card on file is expiring soon',\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Subscriptions and emails',\n },\n {\n key: 'stripe-invoice',\n name: 'Invoice',\n description:\n 'A finalized invoice emailed to the organization. Sent by Stripe ' +\n 'when invoice emails are enabled for the billing configuration.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} invoice`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n ]\n\n/**\n * Every system email Aglyn sends, each with the universal brand tokens\n * appended to its own (AGL-2139).\n *\n * The template's own tokens come FIRST so the editor's palette still leads\n * with what is specific to that email; the brand block reads as the shared\n * footer it is.\n */\nexport const SYSTEM_EMAIL_TEMPLATES: readonly SystemEmailTemplateDefinition[] =\n // The risk notices (AGL-3368) are generated from their own catalog, one key\n // per kind, so they live in `risk-notice-emails.ts` beside it.\n // The getting-started emails (AGL-3692) likewise live beside their own\n // notes on which preference governs them, in `retention-emails.ts`.\n [\n ...BASE_SYSTEM_EMAIL_TEMPLATES,\n ...RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES,\n ...retentionSystemEmailTemplates(SAMPLE_CONSOLE_ORIGIN, SAMPLE_DOCS_ORIGIN),\n ].map((entry) => ({\n ...entry,\n mergeTokens: [...entry.mergeTokens, ...BRAND_MERGE_TOKENS],\n }))\n\n/** Firestore collection holding the designed templates. */\nexport const SYSTEM_EMAIL_COLLECTION = 'systemEmailTemplates'\n\nexport function getSystemEmailTemplate(\n key: string,\n): SystemEmailTemplateDefinition | undefined {\n return SYSTEM_EMAIL_TEMPLATES.find((entry) => entry.key === key)\n}\n\n/** True when a besigner template can actually change what is delivered. */\nexport function isSystemEmailEditable(\n definition: SystemEmailTemplateDefinition,\n): boolean {\n return definition.deliveredBy === 'resend'\n}\n\n/** The stored template document, when staff have designed one. */\nexport interface SystemEmailTemplateDoc {\n subject?: string\n preheader?: string\n versionId?: string\n updatedAt?: unknown\n updatedByEmail?: string\n}\n\n/** A besigner node in the flat, denormalized map a version stores. */\nexport interface SystemEmailNode {\n $id: string\n componentId: string\n pluginId?: string\n parentId?: string\n props?: Record<string, unknown>\n nodes?: string[]\n}\n\nconst PLACEHOLDER_DEFAULT_BODY: readonly SystemEmailDefaultBlock[] = [\n { block: 'text', text: 'Hello,', variant: 'body' },\n]\n\n/**\n * Turns a template's `defaultBody` into the besigner node map the editor\n * seeds and the send-time default renders (AGL-764/766).\n *\n * One place builds this so the two never diverge — the version a staffer\n * opens is byte-for-byte what a test/send renders when nothing is published.\n * Rooted at {@link EMAIL_NODE_ROOT_ID} so `renderEmailHtml` finds it (AGL-765),\n * with deterministic ids: a version doc only needs ids unique within itself,\n * and determinism keeps the map stable and diffable.\n */\nexport function buildDefaultEmailNodeMap(\n // Structural so the tenant catalog (AGL-770) can seed the same way — every\n // definition that carries a `defaultBody` builds an identical node map.\n definition: { defaultBody?: readonly SystemEmailDefaultBlock[] },\n): Record<string, SystemEmailNode> {\n const blocks = definition.defaultBody?.length\n ? definition.defaultBody\n : PLACEHOLDER_DEFAULT_BODY\n const sectionId = 'default-section'\n const childIds: string[] = []\n const map: Record<string, SystemEmailNode> = {}\n\n blocks.forEach((block, index) => {\n const id = `default-${index}`\n childIds.push(id)\n map[id] =\n block.block === 'button'\n ? {\n $id: id,\n componentId: 'emailButton',\n pluginId: 'email',\n parentId: sectionId,\n props: { children: block.label, href: block.href },\n }\n : block.block === 'html'\n ? {\n $id: id,\n componentId: 'emailHtml',\n pluginId: 'email',\n parentId: sectionId,\n props: { html: block.html },\n }\n : {\n $id: id,\n componentId: 'emailText',\n pluginId: 'email',\n parentId: sectionId,\n props: { children: block.text, variant: block.variant ?? 'body' },\n }\n })\n\n map[EMAIL_NODE_ROOT_ID] = {\n $id: EMAIL_NODE_ROOT_ID,\n componentId: 'div',\n nodes: [sectionId],\n }\n map[sectionId] = {\n $id: sectionId,\n componentId: 'emailSection',\n pluginId: 'email',\n parentId: EMAIL_NODE_ROOT_ID,\n nodes: childIds,\n }\n return map\n}\n"],"names":["SAMPLE_CONSOLE_ORIGIN","process","env","NEXT_PUBLIC_CONSOLE_URL","trim","replace","SAMPLE_DOCS_ORIGIN","NEXT_PUBLIC_DOCS_ORIGIN","NEXT_PUBLIC_AGLYN_DOCS_URL","SAMPLE_SUPPORT_URL","NEXT_PUBLIC_PLATFORM_SUPPORT_URL","NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL","BRAND","EMAIL_NODE_ROOT_ID","RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES","retentionSystemEmailTemplates","welcomeEmailMergeValues","WELCOME_SAMPLES","orgName","slug","consoleOrigin","docsOrigin","BRAND_MERGE_TOKENS","name","description","sample","ORG_NAME","BASE_SYSTEM_EMAIL_TEMPLATES","key","deliveredBy","defaultSubject","mergeTokens","defaultBody","block","text","variant","label","href","footerReason","source","html","SYSTEM_EMAIL_TEMPLATES","map","entry","SYSTEM_EMAIL_COLLECTION","getSystemEmailTemplate","find","isSystemEmailEditable","definition","PLACEHOLDER_DEFAULT_BODY","buildDefaultEmailNodeMap","blocks","length","sectionId","childIds","forEach","index","id","push","$id","componentId","pluginId","parentId","props","children","nodes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/system-email-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 * Origins used as merge-token SAMPLE values in the staff email designer\n * (AGL-2202).\n *\n * These are never sent — they render in the template preview so an author can\n * see what `{{console.url}}` will become. That still made them wrong on a\n * self-host install: the preview showed Aglyn's console as the example for a\n * link that will resolve to the operator's, which is exactly the sort of\n * quiet mis-teaching that ends up copied into a hand-written template.\n *\n * Read from the environment rather than through `@aglyn/aglyn`'s\n * `platform-brand` / `constants`: `shared-util-email` is tagged `scope:shared`\n * and `@nx/enforce-module-boundaries` refuses the edge. Same defaults, so a\n * deployment that configures nothing sees exactly what it saw before.\n */\nconst SAMPLE_CONSOLE_ORIGIN: string =\n (process.env.NEXT_PUBLIC_CONSOLE_URL || '').trim().replace(/\\/+$/, '') ||\n 'https://app.aglyn.com'\n\n/**\n * The docs origin the getting-started emails' docs-link samples build on\n * (AGL-3692), read the way the console's `DOCS_BASE_URL` reads it. Only a\n * preview and test-send sample: the real send fills those links from the\n * console's own docs origin.\n */\nconst SAMPLE_DOCS_ORIGIN: string =\n (\n process.env.NEXT_PUBLIC_DOCS_ORIGIN ||\n process.env.NEXT_PUBLIC_AGLYN_DOCS_URL ||\n ''\n )\n .trim()\n .replace(/\\/+$/, '') || 'https://docs.aglyn.com'\n\n/**\n * Mirrors `PLATFORM_SUPPORT_URL`'s precedence, including the step that makes\n * the operator identity sufficient on its own: a configured support URL, else\n * the operator's support mailbox as a `mailto:`, else the console's own\n * support page.\n *\n * The last step is built from `SAMPLE_CONSOLE_ORIGIN` rather than written out\n * (AGL-3262). The support entry point is a CONSOLE route — `/support`\n * resolves the workspace from the session (AGL-3265) — so the origin it hangs\n * off is the one directly above, and an operator who set\n * `NEXT_PUBLIC_CONSOLE_URL` gets their own console in the sample instead of\n * ours. The literal it replaces was `aglyn.com/support`, which answers 404 and\n * never existed.\n */\nconst SAMPLE_SUPPORT_URL: string =\n (process.env.NEXT_PUBLIC_PLATFORM_SUPPORT_URL || '').trim() ||\n ((process.env.NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL || '').trim()\n ? `mailto:${(process.env.NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL || '').trim()}`\n : `${SAMPLE_CONSOLE_ORIGIN}/support`)\n\n// Deep import, NOT the barrel (AGL-1151): `@aglyn/shared-data-enums` re-exports\n// `firebase-auth`, whose `AuthErrorCodes` is a VALUE import of `firebase/auth`.\n// This module is reachable from the email plugin's site half, which a PUBLISHED\n// tenant page loads, so the barrel put the Firebase auth client into that\n// page's chunks for one brand constant.\nimport { BRAND } from '@aglyn/shared-data-enums/aglyn'\nimport { EMAIL_NODE_ROOT_ID } from './email-render'\nimport { domainSystemEmailTemplates } from './domain-emails'\nimport { RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES } from './risk-notice-emails'\nimport { retentionSystemEmailTemplates } from './retention-emails'\nimport { SITE_CARE_SYSTEM_EMAIL_TEMPLATES } from './site-care-emails'\nimport { SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES } from './site-care-project-emails'\nimport { welcomeEmailMergeValues } from './welcome-email'\n\n/** The welcome email's next steps, as a new workspace's owner gets them. */\nconst WELCOME_SAMPLES = welcomeEmailMergeValues({\n orgName: 'Test Org',\n slug: 'test-org',\n consoleOrigin: SAMPLE_CONSOLE_ORIGIN,\n docsOrigin: SAMPLE_DOCS_ORIGIN,\n})\n\n/**\n * Who actually puts the message on the wire.\n *\n * `resend` — Aglyn composes and sends it, so a besigner template can change\n * what the recipient sees.\n *\n * `firebase` — Firebase Auth sends it from its own templates, configured in\n * the Firebase console. **A besigner template cannot affect these at all**\n * because the sender owns the copy (AGL-767).\n *\n * `stripe` — Stripe sends it on Aglyn's behalf from the Dashboard's\n * Customer-emails settings (billing receipts, dunning, refunds, expiring-card\n * notices). Aglyn never composes these, so like `firebase` they cannot be\n * designed here (AGL-767).\n *\n * The non-`resend` entries are listed so staff can see the full set of mail\n * the product sends and where each one is controlled; the UI must present\n * them as non-editable rather than offering an editor that silently does\n * nothing.\n */\n/**\n * Who actually puts the message on the wire.\n *\n * `'firebase'` was removed by AGL-1112, once nothing was left that Firebase\n * Auth composed. Deliberately not kept \"just in case\": with the variant gone,\n * reintroducing a Firebase-sent email is a compile error rather than a row in\n * a table that quietly stops being editable. The staff editor is wired to\n * `'resend'`, so any other value silently produces a template that renders\n * nothing — which is exactly how the `[aglyn.io]` subject survived so long.\n */\nexport type SystemEmailDeliveredBy = 'resend' | 'stripe'\n\nexport interface SystemEmailMergeToken {\n /** Token as written in the template, without braces. */\n name: string\n description: string\n /** Stand-in used by the staff preview. */\n sample: string\n}\n\n/**\n * One block of a template's starting content (AGL-764). Declarative on\n * purpose: the catalog stays a dependency-free data module, and the console\n * turns these into email-plugin nodes (`emailSection` → `emailText`/\n * `emailButton`) when it seeds the first version. Mirror the copy the send\n * site uses today, with the same `{{tokens}}`, so a staffer who opens the\n * editor starts from what recipients actually get rather than a blank canvas.\n */\nexport type SystemEmailDefaultBlock =\n | {\n block: 'text'\n text: string\n /**\n * `eyebrow` is a small muted line above a heading; `details` draws each\n * \"Label: value\" line as a row of a panel (AGL-3897).\n */\n variant?: 'heading' | 'subheading' | 'body' | 'caption' | 'eyebrow' | 'details' | 'links'\n }\n | { block: 'button'; label: string; href: string }\n /**\n * Markup composed per send, carried in whole by one token (AGL-3867): a\n * layout that text blocks cannot draw, such as the weekly summary's tiles.\n * Rendered as an `emailHtml` block, so it passes the same sanitizer as any\n * author's HTML, and its colors are the email theme's, resolved by the\n * sender.\n */\n | { block: 'html'; html: string }\n\nexport interface SystemEmailTemplateDefinition {\n /** Stable storage key — the Firestore document id. Never rename. */\n key: string\n name: string\n description: string\n deliveredBy: SystemEmailDeliveredBy\n /** Subject used when no template has been published. */\n defaultSubject: string\n mergeTokens: SystemEmailMergeToken[]\n /**\n * Starting content for the first version staff design (AGL-764). Every\n * `resend` template should carry one; a `firebase` template has no editor\n * so it needs none. Absent → the editor seeds a minimal placeholder.\n */\n defaultBody?: readonly SystemEmailDefaultBlock[]\n /**\n * The footer's \"why am I getting this\" line (AGL-3322), drawn under the\n * built-in copy, and under any design sent without the platform's own\n * email blocks.\n *\n * Written against the merge tokens, never a product name: on a white-label\n * send `{{brand.productName}}` is the agency's, and on a renamed deployment\n * it is the operator's, so one sentence is right for every sender. Like the\n * body, it may only use tokens the email declares — a token the send does\n * not supply is blanked, and leaves a hole in the sentence. Every `resend`\n * template carries one; the others are never rendered here.\n */\n footerReason?: string\n /**\n * Where the fallback copy lives, for staff wondering what recipients get\n * today. Informational — nothing reads it at runtime.\n */\n source: string\n}\n\n/**\n * Every system email Aglyn sends.\n *\n * Deliberately **code-defined and fixed**: staff edit the system emails that\n * exist, they do not create or delete them. Adding one is a code change,\n * which is what keeps this list from drifting into advertising an email the\n * product never actually sends — the failure mode a Firestore-backed list\n * would have.\n *\n * The staff page renders from this registry, not from Firestore, so an email\n * with no template designed yet still appears (as \"Using default\").\n */\n/**\n * Brand tokens EVERY system email resolves (AGL-2139).\n *\n * White-label used to invert precisely when staff published a template: the\n * designed template wins over each sender's branded fallback, and the copy\n * here hard-coded \"Aglyn\". Nor was there anything to design against — the\n * merge maps carried `org.name`, `invite.role`, `signInUrl` and friends and\n * nothing about the brand, while `blankUnresolvedTokens` DELETES any token\n * the caller did not supply, so a designer who typed `{{brand.productName}}`\n * would have shipped an email with a hole in the sentence.\n *\n * Declared once and appended to every template's own list rather than copied\n * into each: 13 hand-maintained copies is how the token list falls behind the\n * copy, and the editor renders this list as the palette a designer picks\n * from — a token missing here is a token nobody knows exists.\n *\n * The samples are the DEPLOYMENT's own values (`BRAND.ORG_NAME`, AGL-2319),\n * because that is what an unbranded org genuinely renders — on a self-host\n * install a hardcoded \"Aglyn\" would preview a brand that appears nowhere in\n * the mail the designer is editing.\n */\nexport const BRAND_MERGE_TOKENS: readonly SystemEmailMergeToken[] = [\n {\n name: 'brand.productName',\n description: \"The sender's product name — the org's own on white-label\",\n sample: BRAND.ORG_NAME,\n },\n {\n name: 'brand.fromName',\n description: 'Sender display name the mail is delivered under',\n sample: BRAND.ORG_NAME,\n },\n {\n name: 'brand.supportUrl',\n description: 'Where the recipient should go for help',\n sample: SAMPLE_SUPPORT_URL,\n },\n]\n\n// NOT declared: a `brand.logoUrl` token. The logo is STRUCTURAL — the\n// renderer emits it as a header row above the designed body, or emits\n// nothing — so a designer never places it, and a palette entry for it would\n// need a sample URL that a staff test-send would render as a broken image.\n// The three tokens above are the ones that belong in copy.\n\nconst BASE_SYSTEM_EMAIL_TEMPLATES: readonly SystemEmailTemplateDefinition[] =\n [\n {\n key: 'org-invite',\n name: 'Organization invite',\n description:\n 'Sent when an admin invites someone to an organization from the ' +\n 'Team page.',\n deliveredBy: 'resend',\n defaultSubject: \"You've been invited to {{org.name}} on {{brand.productName}}\",\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the inviting organization',\n sample: 'Test Org',\n },\n {\n name: 'invite.role',\n description: 'Role the person is invited as',\n sample: 'Editor',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to sign in and accept',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in invites/route.ts.\n defaultBody: [\n { block: 'text', text: 'Invitation · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Join {{org.name}} on {{brand.productName}}', variant: 'heading' },\n { block: 'text', text: 'You\\'ve been invited to join {{org.name}} as {{invite.role}}. Sign in with this email address and the invitation is waiting on your dashboard.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: {{invite.role}}', variant: 'details' },\n { block: 'button', label: 'Accept the invitation', href: '{{signInUrl}}' },\n { block: 'text', text: 'Not expecting this? You can ignore it. Nothing happens unless you accept.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone invited you to join ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/invites/route.ts',\n },\n {\n key: 'org-owner-handoff',\n name: 'Workspace handoff',\n description:\n 'Sent when the owner of a workspace, or the platform team, invites ' +\n 'someone to take the workspace over as its new owner.',\n deliveredBy: 'resend',\n defaultSubject: '{{org.name}} is being handed to you on {{brand.productName}}',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the workspace being handed over',\n sample: 'Test Org',\n },\n {\n name: 'handoff.previousOwner',\n description:\n 'What happens to the current owner once the handoff is accepted',\n sample: 'The current owner stays on as an admin.',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to sign in and accept',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallback text in invites/route.ts.\n defaultBody: [\n { block: 'text', text: 'Ownership transfer · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{org.name}} is being handed to you', variant: 'heading' },\n { block: 'text', text: 'You\\'ve been invited to take over {{org.name}} as its owner. The owner holds the workspace, every site in it, and its billing. {{handoff.previousOwner}}', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: Owner', variant: 'details' },\n { block: 'button', label: 'Review and accept', href: '{{signInUrl}}' },\n { block: 'text', text: 'Nothing changes until you accept. Sign in with this email address to see the invitation.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone invited you to take over ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/invites/route.ts',\n },\n {\n key: 'org-owner-handoff-proposal',\n name: 'Workspace handoff with a plan',\n description:\n 'Sent when the platform team hands a workspace to a new owner and ' +\n 'proposes its plan in the same step: the invitation, with a link to ' +\n 'Billing where the plan, add-ons, cadence and coupon are already chosen.',\n deliveredBy: 'resend',\n defaultSubject: '{{org.name}} is ready for you on {{brand.productName}}',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the workspace being handed over',\n sample: 'Test Org',\n },\n {\n name: 'handoff.previousOwner',\n description:\n 'What happens to the current owner once the handoff is accepted',\n sample: 'The current owner stays on as an admin.',\n },\n {\n name: 'plan.name',\n description: 'The proposed plan',\n sample: 'Starter',\n },\n {\n name: 'proposal.summary',\n description: 'The plan with the add-ons, cadence and coupon proposed with it',\n sample: 'Starter with Site Care, billed yearly, code BOOTH25',\n },\n {\n name: 'proposal.note',\n description: 'A line from the team, or nothing when none was written',\n sample: 'Great meeting you at the booth.',\n },\n {\n name: 'billingUrl',\n description:\n 'Billing page with the bundle preselected; signing in with this ' +\n 'address shows the invitation to accept first',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter&interval=year&addons=siteCare`,\n },\n ],\n // Mirrors the fallback text in invites/route.ts.\n defaultBody: [\n { block: 'text', text: 'Your new website · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{org.name}} is ready for you', variant: 'heading' },\n { block: 'text', text: 'You\\'ve been invited to take over {{org.name}} as its owner. The owner holds the workspace, every site in it, and its billing. {{handoff.previousOwner}}', variant: 'body' },\n { block: 'text', text: '{{proposal.note}}', variant: 'body' },\n { block: 'text', text: 'Your plan: {{proposal.summary}}', variant: 'details' },\n { block: 'button', label: 'Accept and start the {{plan.name}} plan', href: '{{billingUrl}}' },\n { block: 'text', text: 'Sign in with this email address, accept the invitation, and Billing opens with everything already chosen. Nothing is charged until you confirm.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because the {{brand.productName}} team invited ' +\n 'you to take over {{org.name}}.',\n source: 'apps/console/app/api/orgs/invites/route.ts',\n },\n {\n key: 'org-upgrade-proposal',\n name: 'Upgrade proposal',\n description:\n \"Sent to a workspace's owner when the platform team proposes a paid \" +\n 'plan for it, after the workspace has been evaluated.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} team proposed the {{plan.name}} plan for {{org.name}}',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'Name of the workspace the plan is proposed for',\n sample: 'Test Org',\n },\n {\n name: 'plan.name',\n description: 'The proposed plan',\n sample: 'Starter',\n },\n {\n name: 'proposal.note',\n description: 'A line from the team, or nothing when none was written',\n sample: 'As we discussed on Tuesday.',\n },\n {\n name: 'proposal.summary',\n description:\n 'The plan with the add-ons, cadence and coupon proposed with it, ' +\n 'or nothing when only a plan was proposed',\n sample: 'Starter with Site Care, billed yearly, code BOOTH25',\n },\n {\n name: 'billingUrl',\n description: 'Billing page with the proposed plan, add-ons, cadence and coupon preselected',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter&interval=year&addons=siteCare`,\n },\n ],\n // Mirrors the fallback text in /api/admin/org-upgrade-proposal.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'The {{plan.name}} plan, proposed for {{org.name}}', variant: 'heading' },\n { block: 'text', text: 'Your {{brand.productName}} team proposed moving {{org.name}} to the {{plan.name}} plan.', variant: 'body' },\n { block: 'text', text: '{{proposal.summary}}', variant: 'details' },\n { block: 'text', text: '{{proposal.note}}', variant: 'body' },\n { block: 'text', text: 'When you are ready, start the subscription from Billing. The plan is already selected there, beside the others so you can compare them first.', variant: 'body' },\n { block: 'button', label: 'Review the {{plan.name}} plan', href: '{{billingUrl}}' },\n { block: 'text', text: 'Nothing changes until you start the subscription.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you own {{org.name}} on ' +\n '{{brand.productName}} and its team proposed a plan for it.',\n source: 'apps/console/app/api/admin/org-upgrade-proposal/route.ts',\n },\n {\n key: 'client-build-preview',\n name: 'Client build preview',\n description:\n 'Sent to a business owner when the platform team has built their ' +\n 'website with them, at an event or on their doorstep, with the link ' +\n 'to look at it and the address it will live at.',\n deliveredBy: 'resend',\n defaultSubject: 'Your new website for {{business.name}} is ready to look at',\n mergeTokens: [\n {\n name: 'business.name',\n description: 'Name of the business the website was built for',\n sample: 'Harbor Plumbing',\n },\n {\n name: 'preview.url',\n description: 'Where the website can be seen now',\n sample: 'https://harbor-plumbing.example.com',\n },\n {\n name: 'site.address',\n description: 'The address the website will live at: the domain the owner chose, or its free address',\n sample: 'www.example.com',\n },\n ],\n // Mirrors the fallback text in libs/tenant/data/admin/src/lib/server/client-build.ts.\n defaultBody: [\n { block: 'text', text: '{{business.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your new website is ready to look at', variant: 'heading' },\n { block: 'text', text: 'We built the website for {{business.name}} with you today. Open it on your phone and look around: every page, picture and word can still be changed.', variant: 'body' },\n { block: 'text', text: 'Website: {{preview.url}}\\nAddress: {{site.address}}', variant: 'details' },\n { block: 'button', label: 'See your website', href: '{{preview.url}}' },\n { block: 'text', text: 'Nothing is charged until you choose a plan.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because the {{brand.productName}} team built a ' +\n 'website for {{business.name}} with you and you gave us this address.',\n source: 'apps/console/app/api/admin/client-build/route.ts',\n },\n {\n key: 'usage-summary',\n name: 'Monthly usage summary',\n description:\n 'Monthly per-organization usage and metered-cost summary, sent by ' +\n 'the scheduled job.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} usage summary for {{month.label}}',\n mergeTokens: [\n {\n name: 'month',\n description: 'Billing month as YYYY-MM',\n sample: '2026-06',\n },\n {\n name: 'month.label',\n description: 'Billing month as a reader writes it',\n sample: 'June 2026',\n },\n {\n name: 'org.name',\n description: 'Organization the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'usage.summary',\n description: 'Pre-formatted usage lines',\n sample:\n 'Plan: Starter\\nPage views: 12,400\\n' +\n 'Metered usage beyond your plan: none, so nothing extra is billed for it.',\n },\n { name: 'billingUrl', description: 'The workspace Billing page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing` },\n ],\n // Mirrors the summary lines assembled in usage-email/route.ts.\n defaultBody: [\n { block: 'text', text: '{{month.label}} · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your usage for {{month.label}}', variant: 'heading' },\n { block: 'text', text: 'Here is how {{org.name}} used {{brand.productName}} in {{month.label}}: your plan, storage, page views and anything metered beyond the plan.', variant: 'body' },\n { block: 'text', text: '{{usage.summary}}', variant: 'details' },\n { block: 'text', text: 'Billing shows the full meters beside each plan limit, and the invoices for every month.', variant: 'body' },\n { block: 'button', label: 'Open billing', href: '{{billingUrl}}' },\n { block: 'text', text: 'Usage that goes over your plan is billed with the next invoice. A larger plan includes more, and you can compare them from Billing.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this monthly summary because you manage ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/billing/usage-email/route.ts',\n },\n {\n key: 'erasure-hold-alert',\n name: 'Erasure hold staff alert',\n description:\n 'Internal alert to STAFF_ALERT_EMAIL when GDPR erasure requests ' +\n 'pass their 7-day hold.',\n deliveredBy: 'resend',\n defaultSubject: '{{count}} erasure request(s) past the 7-day hold',\n mergeTokens: [\n {\n name: 'count',\n description: 'How many organizations are past the hold',\n sample: '3',\n },\n {\n name: 'orgs.list',\n description: 'The organizations, one per line',\n sample: 'Test Org (org_123) — requested 2026-07-01\\nNorth Bakery (org_456) — requested 2026-07-02',\n },\n { name: 'healthUrl', description: 'Staff → Health, where pending erasures can be run', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/health` },\n ],\n // Mirrors the staff-alert text in audit-archive/route.ts. It reports\n // and asks for nothing: `run-erasures` erases these orgs at 04:00 UTC,\n // an hour after this sends, and a failure raises its own alert.\n defaultBody: [\n { block: 'text', text: 'Staff · data erasure', variant: 'eyebrow' },\n { block: 'text', text: '{{count}} erasure request(s) past the hold', variant: 'heading' },\n { block: 'text', text: 'These workspaces are past their 7-day erasure hold. The nightly erasure job erases them at 04:00 UTC, five a run and oldest first, and keeps no copy, so nothing is needed from you.', variant: 'body' },\n { block: 'text', text: '{{orgs.list}}', variant: 'details' },\n { block: 'text', text: 'A workspace still listed tomorrow either failed to erase, which raises its own \"could not be erased\" alert, or is waiting behind a longer queue. Pending erasures on Staff → Health can run the due ones sooner.', variant: 'body' },\n { block: 'button', label: 'Open Staff → Health', href: '{{healthUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s staff alerts.',\n source: 'apps/console/app/api/admin/audit-archive/route.ts',\n },\n {\n key: 'welcome',\n name: 'Welcome',\n description:\n 'Sent to a new owner the first time they create an organization ' +\n '(not on every organization they later create).',\n deliveredBy: 'resend',\n defaultSubject: 'Welcome to {{brand.productName}}',\n mergeTokens: [\n {\n name: 'name',\n description: \"The new owner's display name\",\n sample: 'Alex',\n },\n {\n name: 'org.name',\n description: 'The organization they just created',\n sample: 'Test Org',\n },\n {\n name: 'consoleUrl',\n description: 'Console dashboard URL',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n { name: 'welcome.intro', description: 'What is ready, and what to do first, for how the workspace started', sample: WELCOME_SAMPLES['welcome.intro'] },\n { name: 'welcome.steps', description: 'The next steps, one per line, each \"Step — link\"', sample: WELCOME_SAMPLES['welcome.steps'] },\n ],\n // Mirrors the fallbackText in orgs/create/route.ts.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Welcome to {{brand.productName}}, {{name}}', variant: 'heading' },\n { block: 'text', text: '{{welcome.intro}}', variant: 'body' },\n { block: 'text', text: '{{welcome.steps}}', variant: 'links' },\n { block: 'button', label: 'Open {{org.name}}', href: '{{consoleUrl}}' },\n { block: 'text', text: 'Questions as you build? The guides answer most of them, and support is a click away: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you created an organization on ' +\n '{{brand.productName}}.',\n source: 'apps/console/app/api/orgs/create/route.ts',\n },\n {\n key: 'member-added',\n name: 'Added to an organization',\n description:\n `Sent when an existing ${BRAND.ORG_NAME} account is added directly ` +\n 'to an organization. People who do not have an account yet get the ' +\n 'organization invite email instead.',\n deliveredBy: 'resend',\n defaultSubject: \"You've been added to {{org.name}}\",\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization they were added to',\n sample: 'Test Org',\n },\n {\n name: 'member.role',\n description: 'Role they were given',\n sample: 'Editor',\n },\n {\n name: 'signInUrl',\n description: 'Console URL to open the organization',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in orgs/members/route.ts.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'You’re in {{org.name}}', variant: 'heading' },\n { block: 'text', text: 'You were added to {{org.name}} as {{member.role}}. Sign in and pick it from the workspace menu to see its sites.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nYour role: {{member.role}}', variant: 'details' },\n { block: 'button', label: 'Open {{org.name}}', href: '{{signInUrl}}' },\n { block: 'text', text: 'Not expecting this? Ask whoever runs {{org.name}}, or contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you were added to {{org.name}} ' +\n 'on {{brand.productName}}.',\n source: 'apps/console/app/api/orgs/members/route.ts',\n },\n {\n key: 'erasure-confirmation',\n name: 'Erasure completed',\n description:\n 'Sent to an organization owner once its data has been permanently ' +\n 'erased under a GDPR request.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} data has been erased',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization that was erased',\n sample: 'Test Org',\n },\n ],\n // Mirrors the fallbackText in admin/run-erasures/route.ts.\n defaultBody: [\n { block: 'text', text: 'Data erasure · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your data has been erased', variant: 'heading' },\n { block: 'text', text: '{{org.name}} and all of its data have been permanently erased from {{brand.productName}}, as you asked. This is complete and cannot be undone.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nStatus: Erased', variant: 'details' },\n { block: 'text', text: 'Nothing more is needed from you. Your sign-in stays, so you can start a new workspace any time.', variant: 'body' },\n { block: 'text', text: 'Questions about the erasure? Contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you asked {{brand.productName}} ' +\n 'to erase {{org.name}}’s data.',\n source: 'apps/console/app/api/admin/run-erasures/route.ts',\n },\n {\n key: 'erasure-requested',\n name: 'Erasure requested',\n description:\n 'Confirms to an organization owner that a GDPR erasure request was ' +\n 'recorded, and that deletion follows after a 7-day hold.',\n deliveredBy: 'resend',\n defaultSubject: 'We received your erasure request',\n mergeTokens: [\n {\n name: 'org.name',\n description: 'The organization to be erased',\n sample: 'Test Org',\n },\n { name: 'erasure.date', description: 'The day the 7-day hold ends and erasure runs', sample: 'July 8, 2026' },\n ],\n // Mirrors the fallbackText in admin/erasure-request/route.ts.\n defaultBody: [\n { block: 'text', text: 'Data erasure · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your erasure request is recorded', variant: 'heading' },\n { block: 'text', text: 'We have recorded a request to erase {{org.name}} and all of its data from {{brand.productName}}: every site, form submission, order, file and member.', variant: 'body' },\n { block: 'text', text: 'Workspace: {{org.name}}\\nErased on: {{erasure.date}}', variant: 'details' },\n { block: 'text', text: 'Erasure is permanent. It waits out a 7-day hold first, so if this was not intended, contact support before {{erasure.date}} and we will cancel it.', variant: 'body' },\n { block: 'button', label: 'Contact support', href: '{{brand.supportUrl}}' },\n { block: 'text', text: 'Want a copy of anything first? Export it from the workspace before the hold ends.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you own {{org.name}} on ' +\n '{{brand.productName}}.',\n source: 'apps/console/app/api/admin/erasure-request/route.ts',\n },\n // Admin-initiated password mail (AGL-910). Unlike the self-serve\n // `password-reset` below, Aglyn composes and sends these itself — the\n // reset LINK still comes from Firebase (generatePasswordResetLink), but\n // the message around it is ours, so both are designable.\n {\n key: 'admin-password-reset',\n name: 'Password reset (sent by an admin)',\n description:\n 'Password reset link sent on someone else\\'s behalf from the ' +\n 'console — by staff from a user\\'s detail page, or by an ' +\n 'organization admin from a team member\\'s page.',\n deliveredBy: 'resend',\n defaultSubject: 'Reset your {{brand.productName}} password',\n mergeTokens: [\n {\n name: 'resetUrl',\n description: 'One-time link that opens the reset form',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/reset-password?oobCode=…`,\n },\n {\n name: 'actor.name',\n description: 'Who asked for the reset',\n sample: '{{brand.productName}} support',\n },\n ],\n // Mirrors the fallbackText in _lib/password-admin.ts.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Reset your password', variant: 'heading' },\n { block: 'text', text: '{{actor.name}} started a password reset for your {{brand.productName}} account. Choose a new password with the button below.', variant: 'body' },\n { block: 'button', label: 'Set a new password', href: '{{resetUrl}}' },\n { block: 'text', text: 'The link works once and expires shortly. If you were not expecting this, ignore this email and your password stays as it is.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because an administrator started a ' +\n 'password reset for your {{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/password-admin.ts',\n },\n {\n key: 'password-changed-by-admin',\n name: 'Password changed by an admin',\n description:\n 'Notice sent to the account holder after an admin sets their ' +\n 'password directly. Always sent — it is how someone finds out an ' +\n 'administrator changed their credentials.',\n deliveredBy: 'resend',\n defaultSubject: 'Your {{brand.productName}} password was changed',\n mergeTokens: [\n {\n name: 'actor.name',\n description: 'Who changed the password',\n sample: '{{brand.productName}} support',\n },\n {\n name: 'signInUrl',\n description: 'Where to sign in with the new password',\n sample: SAMPLE_CONSOLE_ORIGIN,\n },\n ],\n // Mirrors the fallbackText in _lib/password-admin.ts.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Your password was changed', variant: 'heading' },\n { block: 'text', text: '{{actor.name}} set a new password on your {{brand.productName}} account and signed you out everywhere. Sign back in with the new password.', variant: 'body' },\n { block: 'text', text: 'Changed by: {{actor.name}}', variant: 'details' },\n { block: 'button', label: 'Sign in', href: '{{signInUrl}}' },\n { block: 'text', text: 'If you did not expect this, contact whoever administers your account straight away, or support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because an administrator changed the ' +\n 'password on your {{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/password-admin.ts',\n },\n // Security alerts (AGL-665). Factual and actionable: what happened, from\n // where, and one button to the account-security surface. These must be\n // believed, so the send path only fires them on genuinely new devices —\n // never on every sign-in.\n {\n key: 'security-new-device',\n name: 'New device sign-in',\n description:\n 'Security alert sent when an account signs in from a device it has ' +\n 'not used before. Not sent on routine sign-ins from known devices.',\n deliveredBy: 'resend',\n defaultSubject: 'New sign-in to your {{brand.productName}} account',\n mergeTokens: [\n {\n name: 'device.name',\n description: 'Browser and operating system that signed in',\n sample: 'Chrome on macOS',\n },\n {\n name: 'device.location',\n description: 'Approximate location, from the request IP',\n sample: 'Denver, CO, US',\n },\n {\n name: 'device.ip',\n description: 'IP address the sign-in came from',\n sample: '203.0.113.7',\n },\n {\n name: 'device.time',\n description: 'When the sign-in happened (UTC)',\n sample: '2026-08-08 14:03 UTC',\n },\n {\n name: 'accountSecurityUrl',\n description:\n 'Manage-account Security section — Recent sign-ins, where the ' +\n 'device can be signed out, plus password and passkeys',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user/security`,\n },\n ],\n // Mirrors the fallbackText in _lib/security-alerts.ts.\n defaultBody: [\n { block: 'text', text: 'Security alert', variant: 'eyebrow' },\n { block: 'text', text: 'New device sign-in', variant: 'heading' },\n { block: 'text', text: 'Your {{brand.productName}} account was just signed in to from a device it has not used before.', variant: 'body' },\n { block: 'text', text: 'Device: {{device.name}}\\nLocation: {{device.location}}\\nIP address: {{device.ip}}\\nWhen: {{device.time}}', variant: 'details' },\n { block: 'text', text: 'If this was you, there is nothing to do. If it was not, sign this device out from Recent sign-ins and change your password right away.', variant: 'body' },\n { block: 'button', label: 'Review your devices', href: '{{accountSecurityUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because your {{brand.productName}} ' +\n 'account signed in from a new device.',\n source: 'apps/console/app/api/_lib/security-alerts.ts',\n },\n {\n key: 'security-passkey-added',\n name: 'New passkey added',\n description:\n 'Security alert sent when a passkey is registered on an account. ' +\n 'The trigger ships with passkey support (AGL-662); until then no ' +\n 'call site sends this.',\n deliveredBy: 'resend',\n defaultSubject: 'A passkey was added to your {{brand.productName}} account',\n mergeTokens: [\n {\n name: 'passkey.label',\n description: 'Name the passkey was saved under',\n sample: 'MacBook Touch ID',\n },\n {\n name: 'device.time',\n description: 'When the passkey was added (UTC)',\n sample: '2026-08-08 14:03 UTC',\n },\n {\n name: 'accountSecurityUrl',\n description: 'Manage-account page where credentials are reviewed',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user`,\n },\n ],\n // Mirrors the fallbackText in _lib/security-alerts.ts.\n defaultBody: [\n { block: 'text', text: 'Security alert', variant: 'eyebrow' },\n { block: 'text', text: 'New passkey added', variant: 'heading' },\n { block: 'text', text: 'A passkey was just added to your {{brand.productName}} account. It can sign you in without your password.', variant: 'body' },\n { block: 'text', text: 'Passkey: {{passkey.label}}\\nWhen: {{device.time}}', variant: 'details' },\n { block: 'text', text: 'If you added it, there is nothing to do. If you did not, remove it and change your password right away.', variant: 'body' },\n { block: 'button', label: 'Review account security', href: '{{accountSecurityUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because a passkey was added to your ' +\n '{{brand.productName}} account.',\n source: 'apps/console/app/api/_lib/security-alerts.ts',\n },\n // Aglyn composes and sends both of these now (AGL-1112). They were\n // Firebase's, from a template nobody could edit — the subject still\n // carried `[aglyn.io]`, a domain the company no longer uses, and the link\n // landed on `aglyn-main.firebaseapp.com`. Neither could be fixed: every\n // write under `notification.sendEmail` is refused with\n // `EMAIL_TEMPLATE_UPDATE_NOT_ALLOWED`.\n //\n // Firebase still MINTS the one-time code, which is the part that has to\n // be its. Only the message around it, and the host the link points at,\n // became ours. So editing these here now does what it says.\n {\n key: 'password-reset',\n name: 'Forgot password',\n description:\n 'Password reset link, sent when someone asks for one from Account ' +\n 'recovery.',\n deliveredBy: 'resend',\n defaultSubject: 'Reset your {{brand.productName}} password',\n mergeTokens: [\n {\n name: 'resetUrl',\n description: 'One-time link that opens the choose-a-new-password page',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/reset-password?oobCode=\\u2026`,\n },\n ],\n // Mirrors the fallbackText in the route, so the designed and undesigned\n // versions say the same thing.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Reset your password', variant: 'heading' },\n { block: 'text', text: 'Someone asked to reset the password for your {{brand.productName}} account. If it was you, choose a new one with the button below.', variant: 'body' },\n { block: 'button', label: 'Choose a new password', href: '{{resetUrl}}' },\n { block: 'text', text: 'The link works once and expires shortly. If this was not you, ignore this email and your password stays as it is.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone asked to reset the ' +\n 'password on your {{brand.productName}} account.',\n source: 'apps/console/app/api/auth/send-password-reset/route.ts',\n },\n {\n key: 'email-verification',\n name: 'Confirm email',\n description:\n 'Address verification link, sent after sign-up and whenever someone ' +\n 'asks for another from the verify page.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email address',\n mergeTokens: [\n {\n name: 'verifyUrl',\n description: 'One-time link that confirms the address',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/verify-email?oobCode=\\u2026`,\n },\n ],\n defaultBody: [\n { block: 'text', text: 'One last step', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm your email', variant: 'heading' },\n { block: 'text', text: 'Confirm this address to finish setting up your {{brand.productName}} account. It keeps your account secure, and it is where we tell you about your sites: new form submissions, orders and bookings.', variant: 'body' },\n { block: 'button', label: 'Confirm my email', href: '{{verifyUrl}}' },\n { block: 'text', text: 'If you did not sign up for {{brand.productName}}, you can ignore this email.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address was used to sign ' +\n 'up for {{brand.productName}}.',\n source: 'apps/console/app/api/auth/send-verification/route.ts',\n },\n // Its own entry rather than a second use of the one above, because every\n // line of that one is about signing up: \"finish setting up your account\",\n // \"if you did not create an account\", a footer saying the address was\n // used to sign up. This mail goes to an address someone is ADDING to an\n // account that already exists, and the one thing its reader needs to hear\n // is that ignoring it changes nothing.\n {\n key: 'email-address-confirmation',\n name: 'Confirm added email',\n description:\n 'Confirmation link, sent when someone adds another email address to ' +\n 'their account under Manage Account → Email addresses.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email address',\n mergeTokens: [\n {\n name: 'confirmUrl',\n description: 'One-time link that adds the address to the account',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/user?confirmEmail=…`,\n },\n ],\n // Mirrors the fallbackText in the route.\n defaultBody: [\n { block: 'text', text: 'Account security', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm this email address', variant: 'heading' },\n { block: 'text', text: 'Confirm this address to add it to your {{brand.productName}} account. Once it is confirmed you can sign in with it and choose it for your email.', variant: 'body' },\n { block: 'button', label: 'Confirm email address', href: '{{confirmUrl}}' },\n { block: 'text', text: 'If you did not ask to add this address, ignore this email. Nothing has changed, and the address has not been added to any account.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because someone asked to add this address ' +\n 'to a {{brand.productName}} account.',\n source: 'apps/console/app/api/account/emails/route.ts',\n },\n // AGL-3691. A message a staffer writes to one account from its staff\n // page, sent in the platform's design. The subject heads the body, so the\n // email states its topic even to a reader who skipped the subject line\n // (AGL-3432). It leaves from the platform sender with Reply-To set to the\n // staffer, so an answer reaches a person rather than `noreply@`.\n {\n key: 'staff-follow-up',\n name: 'Follow-up from the team',\n description:\n 'A message a staff member writes to one account from its page in ' +\n 'the staff console, sent in the platform design. Replies go to the ' +\n 'staff member who sent it.',\n deliveredBy: 'resend',\n defaultSubject: '{{message.subject}}',\n mergeTokens: [\n {\n name: 'name',\n description: \"The account holder's first name, or nothing\",\n sample: 'Alex',\n },\n {\n name: 'message.subject',\n description: 'What the message is about, in one line',\n sample: 'Your site is ready to publish',\n },\n {\n name: 'message.body',\n description: 'The message itself, as the staff member wrote it',\n sample:\n 'I saw you started a site yesterday. Reply here if anything ' +\n 'got in the way and I will sort it out.',\n },\n {\n name: 'sender.name',\n description: 'The staff member who wrote it',\n sample: 'Zach',\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{message.subject}}', variant: 'heading' },\n { block: 'text', text: 'Hi {{name}},', variant: 'body' },\n { block: 'text', text: '{{message.body}}', variant: 'body' },\n { block: 'text', text: '{{sender.name}}\\n{{brand.productName}}', variant: 'body' },\n { block: 'text', text: 'Reply to this email to reach {{sender.name}} directly.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you have a {{brand.productName}} ' +\n 'account and our team wrote to you about it.',\n source: 'apps/console/app/api/admin/users/system-email/route.ts',\n },\n // AGL-3367. The platform's other senders, each of which composed its\n // own plain text and so went out with no header or footer. A sender whose\n // message is assembled per send (a digest's list, an alert's figures)\n // hands its composed text in as one body token: the built-in copy is that\n // text in the brand's chrome, and a design can wrap it in anything else.\n {\n key: 'notification',\n name: 'Notification',\n description:\n 'The email copy of a console notification, sent to people who ' +\n 'turned email on for that kind of notification: staff alerts, ' +\n 'workspace-admin and site-manager notices.',\n deliveredBy: 'resend',\n defaultSubject: '{{notification.title}}',\n mergeTokens: [\n {\n name: 'notification.title',\n description: 'The notification, in one line',\n sample: 'Subscription canceled',\n },\n {\n name: 'notification.body',\n description: 'The detail under it, when it has any',\n sample: 'Test Org canceled, leaving the Advanced plan.',\n },\n {\n name: 'notification.details',\n description:\n 'What the email alone carries, one line each, when there is any: ' +\n 'a form submission’s answers',\n sample: 'Name: Jane Doe\\nEmail: jane@example.com\\nMessage: Do you deliver on Saturdays?',\n },\n {\n name: 'notification.context',\n description: 'The site and workspace it is about, when it is about one',\n sample: 'Copper Kettle Catering · Test Org',\n },\n {\n name: 'notification.action',\n description: 'What the button opens: \"View submission\", \"View order\", or \"Open in\" the product',\n sample: 'View submission',\n },\n {\n name: 'notification.replyNote',\n description: 'Who a reply reaches, when it reaches the person who wrote in',\n sample: 'Reply to this email to answer maria.delgado@example.com.',\n },\n {\n name: 'notification.url',\n description: 'Where the notification opens in the console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications`,\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where email can be turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{notification.context}}', variant: 'eyebrow' },\n { block: 'text', text: '{{notification.title}}', variant: 'heading' },\n { block: 'text', text: '{{notification.body}}', variant: 'body' },\n { block: 'text', text: '{{notification.details}}', variant: 'details' },\n { block: 'button', label: '{{notification.action}}', href: '{{notification.url}}' },\n { block: 'text', text: '{{notification.replyNote}}', variant: 'caption' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this because email is on for these ' +\n 'notifications in your {{brand.productName}} settings.',\n source: 'libs/tenant/data/admin/src/lib/server/notifications.ts',\n },\n {\n key: 'staff-alert',\n name: 'Staff alert',\n description:\n 'Operational alerts to STAFF_ALERT_EMAIL: free-tier AI spend, usage ' +\n 'margins, SSO re-verification and the like.',\n deliveredBy: 'resend',\n defaultSubject: '{{alert.subject}}',\n mergeTokens: [\n {\n name: 'alert.subject',\n description: 'The alert, in one line',\n sample: 'Free AI spend at 80% of today’s ceiling',\n },\n {\n name: 'alert.body',\n description: 'The alert as its sender wrote it',\n sample: 'Free-tier AI spend for 2026-09-28 (UTC) is at $40.00 of the $50.00 ceiling.',\n },\n { name: 'alert.url', description: 'Where the alert is handled; the staff console when the sender names nowhere', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/lockdown` },\n { name: 'alert.urlLabel', description: 'The button’s words for that page', sample: 'Open Staff → Lockdown' },\n ],\n // The subject heads the body (AGL-3432): a reader who skips the\n // subject line still sees what the alert is about.\n defaultBody: [\n { block: 'text', text: 'Staff alert', variant: 'eyebrow' },\n { block: 'text', text: '{{alert.subject}}', variant: 'heading' },\n { block: 'text', text: '{{alert.body}}', variant: 'body' },\n { block: 'button', label: '{{alert.urlLabel}}', href: '{{alert.url}}' },\n { block: 'text', text: 'Sent to the staff alert inbox. Every alert is also on Staff → Overview.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s staff alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/staff-alert-email.ts',\n },\n {\n key: 'operator-alert',\n name: 'Operator alert',\n description:\n 'Emailed to the operator for every operator alert delivered right ' +\n 'away: fraud and risk, a lost dispute, a failed erasure, a degraded ' +\n 'health check, a webhook failing its signature, and every other type ' +\n 'listed on Staff → Operator alerts. Goes to STAFF_ALERT_EMAIL, else ' +\n 'the operator support address, else every staff account.',\n deliveredBy: 'resend',\n defaultSubject: '{{alert.title}}',\n mergeTokens: [\n {\n name: 'alert.title',\n description: 'The alert, in one line',\n sample: 'Card testing on northwind.test',\n },\n {\n name: 'alert.body',\n description: 'What happened, as staff are told it',\n sample:\n '38 declined card attempts in 10 minutes on the checkout of ' +\n 'northwind.test. Checkout is rate limited while this is reviewed.',\n },\n {\n name: 'alert.url',\n description: 'The item in the staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/abuse-reports`,\n },\n { name: 'alert.eyebrow', description: 'The alert’s level and area', sample: 'Must know · Payments & payouts' },\n { name: 'alert.details', description: 'Which alert, which workspace or site, and when, as \"Label: value\" lines', sample: 'Alert: Card testing\\nLevel: Must know\\nSite id: host_123\\nRaised: 2026-09-28 14:03 UTC' },\n { name: 'settingsUrl', description: 'Staff → Operator alerts', sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/operator-alerts` },\n ],\n defaultBody: [\n { block: 'text', text: '{{alert.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{alert.title}}', variant: 'heading' },\n { block: 'text', text: '{{alert.body}}', variant: 'body' },\n { block: 'text', text: '{{alert.details}}', variant: 'details' },\n { block: 'button', label: 'Review it', href: '{{alert.url}}' },\n { block: 'text', text: 'Choose which alerts email you, and which wait for the daily digest, on Staff → Operator alerts: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s operator alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/operator-alerts.ts',\n },\n {\n key: 'operator-alert-digest',\n name: 'Operator alert digest',\n description:\n 'Once a day, every operator alert set to the digest on Staff → ' +\n 'Operator alerts — new support tickets and replies, listings waiting ' +\n 'for review, and any type staff moved there — in one email. Goes to ' +\n 'the same inbox as the operator alert.',\n deliveredBy: 'resend',\n defaultSubject: '{{digest.title}}',\n mergeTokens: [\n {\n name: 'digest.title',\n description: 'The count and the day, in one line, “alert” or “alerts” as the count needs',\n sample: '3 operator alerts on 2026-09-28',\n },\n {\n name: 'digest.date',\n description: 'The day the digest covers, UTC',\n sample: '2026-09-28',\n },\n {\n name: 'digest.count',\n description: 'How many alerts it holds',\n sample: '3',\n },\n {\n name: 'digest.body',\n description: 'The alerts, one paragraph each',\n sample:\n '• New support ticket: Checkout button missing\\n' +\n 'northwind opened a ticket.\\n\\n' +\n '• Plugin listing waiting for review\\n' +\n 'Acme Forms 2.1.0 was submitted for review.',\n },\n {\n name: 'digest.url',\n description: 'The staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/operator-alerts`,\n },\n ],\n defaultBody: [\n { block: 'text', text: 'Daily digest · {{digest.date}}', variant: 'eyebrow' },\n { block: 'text', text: '{{digest.title}}', variant: 'heading' },\n { block: 'text', text: 'The routine alerts from the last day, batched so they arrive together. None of them needed you right away.', variant: 'body' },\n { block: 'text', text: '{{digest.body}}', variant: 'body' },\n { block: 'button', label: 'Open operator alerts', href: '{{digest.url}}' },\n { block: 'text', text: 'Choose which alerts wait for this digest on Staff → Operator alerts.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address gets ' +\n '{{brand.productName}}’s operator alerts.',\n source: 'libs/tenant/data/admin/src/lib/server/operator-alerts.ts',\n },\n {\n key: 'support-ticket-alert',\n name: 'Support ticket to success manager',\n description:\n 'Copies an organization’s named success manager on a support ticket ' +\n 'it opened or replied to.',\n deliveredBy: 'resend',\n defaultSubject: '{{ticket.heading}} — {{org.name}}: {{ticket.subject}}',\n mergeTokens: [\n {\n name: 'ticket.heading',\n description: '“New ticket” or “Ticket reply”',\n sample: 'New ticket',\n },\n {\n name: 'ticket.subject',\n description: 'The ticket’s subject',\n sample: 'Domain will not verify',\n },\n {\n name: 'ticket.body',\n description: 'Who wrote, and what they wrote',\n sample: 'Test Org opened a support ticket.\\nFrom: owner@example.com',\n },\n {\n name: 'ticket.url',\n description: 'The ticket in the staff console',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/admin/support`,\n },\n {\n name: 'manager.name',\n description: 'The success manager’s name',\n sample: 'Sam',\n },\n {\n name: 'org.name',\n description: 'The organization the ticket is from',\n sample: 'Test Org',\n },\n { name: 'ticket.opening', description: 'Who opened or replied, as one sentence', sample: 'Test Org opened a support ticket.' },\n { name: 'ticket.message', description: 'What the customer wrote', sample: 'We added the TXT record yesterday and the domain still says pending.' },\n { name: 'ticket.details', description: 'The workspace, sender, subject and ticket id as \"Label: value\" lines', sample: 'Workspace: Test Org\\nFrom: owner@example.com\\nSubject: Domain will not verify\\nTicket id: tkt_123' },\n ],\n defaultBody: [\n { block: 'text', text: '{{ticket.heading}} · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{ticket.subject}}', variant: 'heading' },\n { block: 'text', text: '{{manager.name}}, {{ticket.opening}} You are its success manager, so it is copied to you.', variant: 'body' },\n { block: 'text', text: '{{ticket.details}}', variant: 'details' },\n { block: 'text', text: '{{ticket.message}}', variant: 'body' },\n { block: 'button', label: 'Open the ticket', href: '{{ticket.url}}' },\n { block: 'text', text: 'Answer from Staff → Support so the reply is threaded on the ticket and the customer sees it in their console.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you are the success manager for ' +\n '{{org.name}} on {{brand.productName}}.',\n source: 'apps/console/app/api/_lib/success-manager.ts',\n },\n {\n key: 'workspace-notice',\n name: 'Workspace notice',\n description:\n 'Operational notices to a workspace’s people: usage alerts and SSO ' +\n 'domain lapses to its owners and admins, and a stopped outreach ' +\n 'mailbox to the member who connected it.',\n deliveredBy: 'resend',\n defaultSubject: '{{notice.subject}}',\n mergeTokens: [\n {\n name: 'notice.subject',\n description: 'The notice, in one line',\n sample: 'Sequences paused your mailbox avery@example.com',\n },\n {\n name: 'notice.body',\n description: 'The notice as its sender wrote it',\n sample: 'Sequences paused the mailbox Avery Quinn <avery@example.com>.\\n\\nSequences paused it after 3 bounces in a row.',\n },\n {\n name: 'org.name',\n description: 'The workspace the notice is about',\n sample: 'Test Org',\n },\n { name: 'notice.lead', description: 'What happened and what to do, without the link', sample: 'Sequences paused avery@example.com after 3 bounces in a row. 4 enrollments are active on it and waiting. Re-check the addresses, then open Mailboxes and select Resume.' },\n { name: 'notice.details', description: 'The facts, as \"Label: value\" lines', sample: 'Mailbox: avery@example.com\\nStatus: Paused by Sequences\\nEnrollments waiting: 4' },\n { name: 'notice.url', description: 'Where the reader acts on it', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/outreach/mailboxes` },\n { name: 'notice.action', description: 'The button’s words', sample: 'Open Mailboxes to resume' },\n { name: 'notice.reason', description: 'Why this reader is getting it', sample: 'You are getting this because the mailbox is yours, or you manage the organization it belongs to.' },\n ],\n // The subject heads the body (AGL-3432): a reader who skips the\n // subject line still sees what the notice is about.\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{notice.subject}}', variant: 'heading' },\n { block: 'text', text: '{{notice.lead}}', variant: 'body' },\n { block: 'text', text: '{{notice.details}}', variant: 'details' },\n { block: 'button', label: '{{notice.action}}', href: '{{notice.url}}' },\n { block: 'text', text: '{{notice.reason}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you’re a member of {{org.name}} on ' +\n '{{brand.productName}}.',\n source: 'libs/tenant/data/admin/src/lib/server/org-member-notice.ts',\n },\n {\n key: 'member-email-alias-confirmation',\n name: 'Member email address confirmation',\n description:\n 'Sent to an address a workspace member asked to add as one of their ' +\n 'own, so mail from it is filed under the people it was written to.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your address for {{org.name}}',\n mergeTokens: [\n {\n name: 'member.name',\n description: 'The member who asked',\n sample: 'Alex',\n },\n {\n name: 'address',\n description: 'The address being confirmed',\n sample: 'alex@example.com',\n },\n {\n name: 'org.name',\n description: 'The workspace',\n sample: 'Test Org',\n },\n {\n name: 'confirmUrl',\n description: 'The one-time confirmation link',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/account`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm this address', variant: 'heading' },\n { block: 'text', text: '{{member.name}} asked to add {{address}} as one of their own email addresses in {{org.name}}. Open the link while signed in as that member to confirm it.', variant: 'body' },\n { block: 'text', text: 'Address: {{address}}\\nWorkspace: {{org.name}}\\nFor: {{member.name}}', variant: 'details' },\n { block: 'button', label: 'Confirm the address', href: '{{confirmUrl}}' },\n { block: 'text', text: 'Once confirmed, email sent from {{address}} with the workspace’s capture address in BCC is filed under the person it was written to. The link works for 24 hours. If you did not expect this, ignore it.', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because a member of {{org.name}} on ' +\n '{{brand.productName}} asked to add this address to their account.',\n source: 'libs/tenant/data/admin/src/lib/server/member-email-aliases.ts',\n },\n {\n key: 'crm-daily-digest',\n name: 'Daily CRM digest',\n description:\n 'Each morning, a member’s overdue and due-today tasks and unworked ' +\n 'leads, for members who turned the digest on.',\n deliveredBy: 'resend',\n defaultSubject: '{{digest.subject}}',\n mergeTokens: [\n {\n name: 'digest.subject',\n description: 'The summary line',\n sample: '2 tasks overdue, 3 new leads',\n },\n {\n name: 'digest.body',\n description: 'The tasks and leads, one per line, with their links',\n sample: 'Overdue (2)\\n- Call back Jordan · Sep 27, 9:00 AM',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the digest is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n { name: 'digest.eyebrow', description: 'The workspace and the day', sample: 'Test Org · Friday, September 28' },\n { name: 'digest.summary', description: 'What is owed today, in one line', sample: '1 task due today, 2 overdue, 3 unworked leads.' },\n { name: 'digest.overdueHeading', description: 'The overdue list’s heading, empty when there is none', sample: 'Overdue (2)' },\n { name: 'digest.overdue', description: 'Overdue tasks, one \"Title — when\" per line', sample: 'Call back Jordan — Main site · Thu, Sep 27, 9:00 AM CDT\\nSend the proposal — Fri, Sep 28, 8:00 AM CDT' },\n { name: 'digest.todayHeading', description: 'The due-today list’s heading', sample: 'Due today (1)' },\n { name: 'digest.today', description: 'Tasks due today, one per line', sample: 'Follow up with Priya — Main site · Fri, Sep 28, 3:00 PM CDT' },\n { name: 'digest.leadsHeading', description: 'The unworked leads list’s heading', sample: 'Unworked leads (3)' },\n { name: 'digest.leads', description: 'Unworked leads, one \"Name — site · first seen\" per line', sample: 'Jane Doe — Main site · first seen Sep 26\\nsam@example.com — Main site · first seen Sep 27' },\n { name: 'digest.nurturing', description: 'The leads in sequences or campaigns, or empty', sample: '2 leads are in sequences or campaigns.' },\n { name: 'digest.url', description: 'Where the reader starts: the Tasks section, else the leads', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks` },\n { name: 'digest.action', description: 'The button’s words', sample: 'Open your tasks' },\n { name: 'digest.links', description: 'Each site’s leads, one \"Leads on Site — URL\" per line', sample: `Leads on Main site — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/leads` },\n ],\n defaultBody: [\n { block: 'text', text: '{{digest.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: 'Your day in the CRM', variant: 'heading' },\n { block: 'text', text: '{{digest.summary}}', variant: 'body' },\n { block: 'text', text: '{{digest.overdueHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.overdue}}', variant: 'details' },\n { block: 'text', text: '{{digest.todayHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.today}}', variant: 'details' },\n { block: 'text', text: '{{digest.leadsHeading}}', variant: 'subheading' },\n { block: 'text', text: '{{digest.leads}}', variant: 'details' },\n { block: 'text', text: '{{digest.nurturing}}', variant: 'caption' },\n { block: 'button', label: '{{digest.action}}', href: '{{digest.url}}' },\n { block: 'text', text: '{{digest.links}}', variant: 'links' },\n { block: 'text', text: 'Turn the digest off, or change what you are emailed about: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this each morning because the Daily CRM digest is ' +\n 'on in your {{brand.productName}} notification settings.',\n source: 'libs/plugins/crm/src/lib/server/daily-digest-route.ts',\n },\n {\n key: 'crm-task-reminder',\n name: 'CRM task reminder',\n description: 'A reminder for CRM tasks that have come due.',\n deliveredBy: 'resend',\n defaultSubject: '{{reminder.subject}}',\n mergeTokens: [\n {\n name: 'reminder.subject',\n description: 'The task, or how many are due',\n sample: 'Reminder: Call back Jordan',\n },\n {\n name: 'reminder.body',\n description: 'The tasks, each with its link',\n sample: '- Call back Jordan · due today at 9:00 AM',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where reminders are turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n { name: 'reminder.eyebrow', description: 'The workspace the task is in', sample: 'Test Org' },\n { name: 'reminder.intro', description: 'What this is, in one sentence', sample: 'A reminder about your task. Open it to see the contact or deal it is for.' },\n { name: 'reminder.details', description: 'Each task as \"Title — due …\"', sample: 'Call back Jordan — due today at 9:00 AM CDT' },\n { name: 'reminder.url', description: 'The task, or the first one when there are several', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1` },\n { name: 'reminder.action', description: 'The button’s words', sample: 'Open the task' },\n { name: 'reminder.links', description: 'For several tasks, each one’s link as \"Title — URL\"; empty for one', sample: `Call back Jordan — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-1\\nSend the proposal — ${SAMPLE_CONSOLE_ORIGIN}/test-org/crm/tasks#t-2` },\n ],\n defaultBody: [\n { block: 'text', text: '{{reminder.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{reminder.subject}}', variant: 'heading' },\n { block: 'text', text: '{{reminder.intro}}', variant: 'body' },\n { block: 'text', text: '{{reminder.details}}', variant: 'details' },\n { block: 'button', label: '{{reminder.action}}', href: '{{reminder.url}}' },\n { block: 'text', text: '{{reminder.links}}', variant: 'links' },\n { block: 'text', text: 'Change what you are emailed about: {{settingsUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because task reminders are on in your ' +\n '{{brand.productName}} notification settings.',\n source: 'libs/plugins/crm/src/lib/server/task-reminders-route.ts',\n },\n {\n key: 'ai-insights-digest',\n name: 'Weekly insights digest',\n description:\n 'The week’s AI insights for a site, for members who turned the ' +\n 'digest on for that workspace.',\n deliveredBy: 'resend',\n defaultSubject: 'Your weekly insights for {{site.name}}',\n mergeTokens: [\n {\n name: 'site.name',\n description: 'The site the insights are about',\n sample: 'Test Site',\n },\n {\n name: 'digest.body',\n description: 'The insights, numbered, with their links',\n sample: '1. Visits from search rose 18% on last week.',\n },\n { name: 'digest.eyebrow', description: 'The workspace and the week', sample: 'Test Org · Oct 5 – Oct 11' },\n { name: 'digest.intro', description: 'What the insights are, in one sentence', sample: 'What Test Site\\'s figures showed last week. Each one is traced to the figures it cites, so you can check it on the Analytics page.' },\n { name: 'digest.insights', description: 'The insights, numbered', sample: '1. Visits from search rose 18% on last week.\\n\\n2. The pricing page was the most viewed page, with 312 views.' },\n { name: 'digest.analyticsUrl', description: 'The site’s Analytics page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/hosts/test-site/analytics` },\n { name: 'digest.why', description: 'Why it came, what it cost and how to turn it off', sample: `You asked for weekly insights for Test Org. Writing these used 21 of Test Org’s AI credits. Turn them off in Notifications: ${SAMPLE_CONSOLE_ORIGIN}/manage/notifications` },\n ],\n defaultBody: [\n { block: 'text', text: '{{digest.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: 'Weekly insights for {{site.name}}', variant: 'heading' },\n { block: 'text', text: '{{digest.intro}}', variant: 'body' },\n { block: 'text', text: '{{digest.insights}}', variant: 'body' },\n { block: 'button', label: 'Open {{site.name}} analytics', href: '{{digest.analyticsUrl}}' },\n { block: 'text', text: '{{digest.why}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you turned on weekly insights in ' +\n '{{brand.productName}}.',\n source: 'libs/plugins/ai/src/lib/insights/ai-insight-digest.ts',\n },\n {\n key: 'weekly-summary',\n name: 'Weekly summary · workspace',\n description:\n 'Each Monday, how a workspace did the week before: its totals across ' +\n 'sites, a line for each site, and its deals. For its owners and ' +\n 'admins. Free: nothing is generated.',\n deliveredBy: 'resend',\n defaultSubject: '{{summary.subject}}',\n mergeTokens: [\n {\n name: 'summary.subject',\n description: 'The subject line, leading with the week’s figures',\n sample: 'Your week at Test Org: 1,204 visitors, 9 new leads, 6 bookings',\n },\n {\n name: 'summary.title',\n description: 'The heading',\n sample: 'Test Org last week',\n },\n {\n name: 'summary.period',\n description: 'The week the figures cover',\n sample: 'Oct 5 – Oct 11, compared with the week before',\n },\n {\n name: 'summary.html',\n description: 'The figures, drawn as tiles and ranked lists in the email’s theme',\n sample: '<div style=\"padding:16px 0 8px;\"><div style=\"font-family:Helvetica, Arial, sans-serif;font-size:12px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;\">Traffic</div></div>',\n },\n {\n name: 'summary.buttonLabel',\n description: 'The button’s words',\n sample: 'Open Test Org',\n },\n {\n name: 'summary.url',\n description: 'Where the button goes',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org`,\n },\n {\n name: 'org.name',\n description: 'The workspace the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the summary is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{summary.title}}', variant: 'heading' },\n { block: 'text', text: '{{summary.period}}', variant: 'caption' },\n { block: 'html', html: '{{summary.html}}' },\n { block: 'button', label: '{{summary.buttonLabel}}', href: '{{summary.url}}' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this each Monday because you manage {{org.name}} and ' +\n 'the Weekly summary is on in your {{brand.productName}} notification settings.',\n source: 'libs/tenant/data/admin/src/lib/server/weekly-summary.ts',\n },\n {\n key: 'weekly-summary-site',\n name: 'Weekly summary · site',\n description:\n 'Each Monday, how one site did the week before — visitors, top pages, ' +\n 'sources, forms, new leads, bookings, sales, campaigns and more — for ' +\n 'the workspace’s owners and admins and the site’s own admins. Free: ' +\n 'nothing is generated.',\n deliveredBy: 'resend',\n defaultSubject: '{{summary.subject}}',\n mergeTokens: [\n {\n name: 'summary.subject',\n description: 'The subject line, leading with the week’s figures',\n sample: 'Test Site last week: 1,204 visitors, 9 new leads',\n },\n {\n name: 'summary.title',\n description: 'The heading',\n sample: 'Test Site last week',\n },\n {\n name: 'summary.period',\n description: 'The week the figures cover',\n sample: 'Oct 5 – Oct 11, compared with the week before',\n },\n {\n name: 'summary.html',\n description: 'The figures, drawn as tiles and ranked lists in the email’s theme',\n sample: '<div style=\"padding:16px 0 8px;\"><div style=\"font-family:Helvetica, Arial, sans-serif;font-size:12px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;\">Traffic</div></div>',\n },\n {\n name: 'summary.buttonLabel',\n description: 'The button’s words',\n sample: 'Open Test Site',\n },\n {\n name: 'summary.url',\n description: 'Where the button goes',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/hosts/test-site`,\n },\n {\n name: 'org.name',\n description: 'The workspace the summary is for',\n sample: 'Test Org',\n },\n {\n name: 'settingsUrl',\n description: 'Notification settings, where the summary is turned off',\n sample: `${SAMPLE_CONSOLE_ORIGIN}/manage/notifications/settings`,\n },\n ],\n defaultBody: [\n { block: 'text', text: '{{summary.title}}', variant: 'heading' },\n { block: 'text', text: '{{summary.period}}', variant: 'caption' },\n { block: 'html', html: '{{summary.html}}' },\n { block: 'button', label: '{{summary.buttonLabel}}', href: '{{summary.url}}' },\n {\n block: 'text',\n text: 'Change what you are emailed about: {{settingsUrl}}',\n variant: 'caption',\n },\n ],\n footerReason:\n 'You’re receiving this each Monday because you manage {{org.name}} and ' +\n 'the Weekly summary is on in your {{brand.productName}} notification settings.',\n source: 'libs/tenant/data/admin/src/lib/server/weekly-summary.ts',\n },\n {\n key: 'legal-intake-receipt',\n name: 'Report and notice receipt',\n description:\n 'The receipt for an abuse report, a copyright notice or a ' +\n 'counter-notice, carrying its reference.',\n deliveredBy: 'resend',\n defaultSubject: '{{receipt.subject}}',\n mergeTokens: [\n {\n name: 'receipt.subject',\n description: 'What was received, and its reference',\n sample: 'Report received — AR-3F9K2',\n },\n {\n name: 'receipt.body',\n description: 'The receipt as the intake wrote it',\n sample: 'We have received your report about https://example.com.\\n\\nYour reference is AR-3F9K2.',\n },\n { name: 'receipt.eyebrow', description: 'The reference', sample: 'Receipt · AR-3F9K2' },\n { name: 'receipt.heading', description: 'What was received', sample: 'We received your report' },\n { name: 'receipt.intro', description: 'What it was about', sample: 'We have received your report about https://example.com.' },\n { name: 'receipt.details', description: 'Reference, address and time, as \"Label: value\" lines', sample: 'Reference: AR-3F9K2\\nAbout: https://example.com\\nReceived: 2026-09-28 14:03 UTC' },\n { name: 'receipt.next', description: 'What happens next', sample: 'We do not publish what we decide about individual sites, and we will not share your details with the site\\'s owner unless the law requires it.' },\n { name: 'receipt.keep', description: 'Keep this email, and the sign-off', sample: 'Keep this email. It is your record that we received the message above, and the reference is how we will find it if you write to us about it.' },\n ],\n defaultBody: [\n { block: 'text', text: '{{receipt.eyebrow}}', variant: 'eyebrow' },\n { block: 'text', text: '{{receipt.heading}}', variant: 'heading' },\n { block: 'text', text: '{{receipt.intro}}', variant: 'body' },\n { block: 'text', text: '{{receipt.details}}', variant: 'details' },\n { block: 'text', text: 'What happens next', variant: 'subheading' },\n { block: 'text', text: '{{receipt.next}}', variant: 'body' },\n { block: 'text', text: '{{receipt.keep}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because this address was given on a report ' +\n 'or notice sent to {{brand.productName}}.',\n source: 'apps/tenant/app/api/_legal-intake/acknowledge.ts',\n },\n {\n key: 'plugin-review-update',\n name: 'Plugin review update',\n description:\n 'Tells a marketplace publisher’s owners and admins what review ' +\n 'decided about their submission.',\n deliveredBy: 'resend',\n defaultSubject: '{{review.subject}}',\n mergeTokens: [\n {\n name: 'review.subject',\n description: 'The decision, in one line',\n sample: 'Your plugin was approved',\n },\n {\n name: 'review.body',\n description: 'The decision as review wrote it',\n sample: 'Test Plugin 1.2.0 passed review and is live in the marketplace.',\n },\n { name: 'review.details', description: 'Plugin, version and outcome as \"Label: value\" lines', sample: 'Plugin: Test Plugin\\nVersion: 1.2.0\\nOutcome: Approved' },\n { name: 'review.url', description: 'The publisher’s Marketplace page', sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/marketplace` },\n ],\n defaultBody: [\n { block: 'text', text: 'Marketplace review', variant: 'eyebrow' },\n { block: 'text', text: '{{review.subject}}', variant: 'heading' },\n { block: 'text', text: '{{review.body}}', variant: 'body' },\n { block: 'text', text: '{{review.details}}', variant: 'details' },\n { block: 'button', label: 'Open your marketplace listings', href: '{{review.url}}' },\n { block: 'text', text: 'Questions about a review? Contact support: {{brand.supportUrl}}', variant: 'caption' },\n ],\n footerReason:\n 'You’re receiving this because you manage a plugin published on ' +\n '{{brand.productName}}.',\n source: 'libs/plugins/marketplace/src/lib/server/publisher-review-email.ts',\n },\n // Stripe-delivered billing email (AGL-767). Aglyn never composes these —\n // Stripe sends them from the Dashboard's Customer-emails and Subscription\n // settings, so they are listed for visibility only and are not designable.\n // Whether each actually sends is a Dashboard toggle the code cannot read;\n // the descriptions say \"if enabled\" rather than asserting it is on.\n {\n key: 'stripe-receipt',\n name: 'Payment receipt',\n description:\n 'Receipt for a successful subscription or invoice payment. Sent by ' +\n 'Stripe if \"Successful payments\" is enabled under Customer emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your receipt from ${BRAND.ORG_NAME}`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n {\n key: 'stripe-payment-failed',\n name: 'Payment failed',\n description:\n 'Dunning notice when a subscription charge fails and Stripe retries ' +\n 'it. Sent by Stripe if failed-payment emails are enabled under ' +\n 'Subscriptions and emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} payment could not be processed`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Subscriptions and emails',\n },\n {\n key: 'stripe-refund',\n name: 'Refund confirmation',\n description:\n 'Confirms a refund back to the customer. Sent by Stripe if ' +\n '\"Refunds\" is enabled under Customer emails.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} refund`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n {\n key: 'stripe-card-expiring',\n name: 'Card expiring soon',\n description:\n 'Reminder that the card on file is about to expire. Sent by Stripe ' +\n 'if expiring-card reminders are enabled under Subscriptions and ' +\n 'emails.',\n deliveredBy: 'stripe',\n defaultSubject: 'Your card on file is expiring soon',\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Subscriptions and emails',\n },\n {\n key: 'stripe-invoice',\n name: 'Invoice',\n description:\n 'A finalized invoice emailed to the organization. Sent by Stripe ' +\n 'when invoice emails are enabled for the billing configuration.',\n deliveredBy: 'stripe',\n defaultSubject: `Your ${BRAND.ORG_NAME} invoice`,\n mergeTokens: [],\n source: 'Stripe Dashboard → Settings → Customer emails',\n },\n ]\n\n/**\n * Every system email Aglyn sends, each with the universal brand tokens\n * appended to its own (AGL-2139).\n *\n * The template's own tokens come FIRST so the editor's palette still leads\n * with what is specific to that email; the brand block reads as the shared\n * footer it is.\n */\nexport const SYSTEM_EMAIL_TEMPLATES: readonly SystemEmailTemplateDefinition[] =\n // The risk notices (AGL-3368) are generated from their own catalog, one key\n // per kind, so they live in `risk-notice-emails.ts` beside it.\n // The getting-started emails (AGL-3692) likewise live beside their own\n // notes on which preference governs them, in `retention-emails.ts`.\n [\n ...BASE_SYSTEM_EMAIL_TEMPLATES,\n ...RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES,\n ...retentionSystemEmailTemplates(SAMPLE_CONSOLE_ORIGIN, SAMPLE_DOCS_ORIGIN),\n // Site Care requests (AGL-3959), beside their own sender's notes.\n ...SITE_CARE_SYSTEM_EMAIL_TEMPLATES,\n // Site Care projects (AGL-3970): the flat quote's acceptance, invoices,\n // payments and reversals.\n ...SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES,\n // A domain bought through the domains plugin (AGL-3962), whose keys and\n // copy live in `domain-emails.ts`.\n ...domainSystemEmailTemplates(SAMPLE_CONSOLE_ORIGIN),\n ].map((entry) => ({\n ...entry,\n mergeTokens: [...entry.mergeTokens, ...BRAND_MERGE_TOKENS],\n }))\n\n/** Firestore collection holding the designed templates. */\nexport const SYSTEM_EMAIL_COLLECTION = 'systemEmailTemplates'\n\nexport function getSystemEmailTemplate(\n key: string,\n): SystemEmailTemplateDefinition | undefined {\n return SYSTEM_EMAIL_TEMPLATES.find((entry) => entry.key === key)\n}\n\n/** True when a besigner template can actually change what is delivered. */\nexport function isSystemEmailEditable(\n definition: SystemEmailTemplateDefinition,\n): boolean {\n return definition.deliveredBy === 'resend'\n}\n\n/** The stored template document, when staff have designed one. */\nexport interface SystemEmailTemplateDoc {\n subject?: string\n preheader?: string\n versionId?: string\n updatedAt?: unknown\n updatedByEmail?: string\n}\n\n/** A besigner node in the flat, denormalized map a version stores. */\nexport interface SystemEmailNode {\n $id: string\n componentId: string\n pluginId?: string\n parentId?: string\n props?: Record<string, unknown>\n nodes?: string[]\n}\n\nconst PLACEHOLDER_DEFAULT_BODY: readonly SystemEmailDefaultBlock[] = [\n { block: 'text', text: 'Hello,', variant: 'body' },\n]\n\n/**\n * Turns a template's `defaultBody` into the besigner node map the editor\n * seeds and the send-time default renders (AGL-764/766).\n *\n * One place builds this so the two never diverge — the version a staffer\n * opens is byte-for-byte what a test/send renders when nothing is published.\n * Rooted at {@link EMAIL_NODE_ROOT_ID} so `renderEmailHtml` finds it (AGL-765),\n * with deterministic ids: a version doc only needs ids unique within itself,\n * and determinism keeps the map stable and diffable.\n */\nexport function buildDefaultEmailNodeMap(\n // Structural so the tenant catalog (AGL-770) can seed the same way — every\n // definition that carries a `defaultBody` builds an identical node map.\n definition: { defaultBody?: readonly SystemEmailDefaultBlock[] },\n): Record<string, SystemEmailNode> {\n const blocks = definition.defaultBody?.length\n ? definition.defaultBody\n : PLACEHOLDER_DEFAULT_BODY\n const sectionId = 'default-section'\n const childIds: string[] = []\n const map: Record<string, SystemEmailNode> = {}\n\n blocks.forEach((block, index) => {\n const id = `default-${index}`\n childIds.push(id)\n map[id] =\n block.block === 'button'\n ? {\n $id: id,\n componentId: 'emailButton',\n pluginId: 'email',\n parentId: sectionId,\n props: { children: block.label, href: block.href },\n }\n : block.block === 'html'\n ? {\n $id: id,\n componentId: 'emailHtml',\n pluginId: 'email',\n parentId: sectionId,\n props: { html: block.html },\n }\n : {\n $id: id,\n componentId: 'emailText',\n pluginId: 'email',\n parentId: sectionId,\n props: { children: block.text, variant: block.variant ?? 'body' },\n }\n })\n\n map[EMAIL_NODE_ROOT_ID] = {\n $id: EMAIL_NODE_ROOT_ID,\n componentId: 'div',\n nodes: [sectionId],\n }\n map[sectionId] = {\n $id: sectionId,\n componentId: 'emailSection',\n pluginId: 'email',\n parentId: EMAIL_NODE_ROOT_ID,\n nodes: childIds,\n }\n return map\n}\n"],"names":["SAMPLE_CONSOLE_ORIGIN","process","env","NEXT_PUBLIC_CONSOLE_URL","trim","replace","SAMPLE_DOCS_ORIGIN","NEXT_PUBLIC_DOCS_ORIGIN","NEXT_PUBLIC_AGLYN_DOCS_URL","SAMPLE_SUPPORT_URL","NEXT_PUBLIC_PLATFORM_SUPPORT_URL","NEXT_PUBLIC_OPERATOR_SUPPORT_EMAIL","BRAND","EMAIL_NODE_ROOT_ID","domainSystemEmailTemplates","RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES","retentionSystemEmailTemplates","SITE_CARE_SYSTEM_EMAIL_TEMPLATES","SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES","welcomeEmailMergeValues","WELCOME_SAMPLES","orgName","slug","consoleOrigin","docsOrigin","BRAND_MERGE_TOKENS","name","description","sample","ORG_NAME","BASE_SYSTEM_EMAIL_TEMPLATES","key","deliveredBy","defaultSubject","mergeTokens","defaultBody","block","text","variant","label","href","footerReason","source","html","SYSTEM_EMAIL_TEMPLATES","map","entry","SYSTEM_EMAIL_COLLECTION","getSystemEmailTemplate","find","isSystemEmailEditable","definition","PLACEHOLDER_DEFAULT_BODY","buildDefaultEmailNodeMap","blocks","length","sectionId","childIds","forEach","index","id","push","$id","componentId","pluginId","parentId","props","children","nodes"],"mappings":"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"}
|