@aglyn/shared-util-email 1.0.0-beta.275 → 1.0.0-beta.282

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/shared-util-email",
3
- "version": "1.0.0-beta.275",
3
+ "version": "1.0.0-beta.282",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,8 +25,8 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/shared-data-enums": "1.0.0-beta.275",
29
- "@aglyn/shared-util-http": "1.0.0-beta.275",
28
+ "@aglyn/shared-data-enums": "1.0.0-beta.282",
29
+ "@aglyn/shared-util-http": "1.0.0-beta.282",
30
30
  "@msgpack/msgpack": "^3.1.3",
31
31
  "@swc/helpers": "0.5.23"
32
32
  },
package/src/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export * from './lib/retention-emails';
31
31
  export * from './lib/site-care-emails';
32
32
  export * from './lib/site-care-project-emails';
33
33
  export * from './lib/domain-emails';
34
+ export * from './lib/pos-hardware-emails';
34
35
  export * from './lib/welcome-email';
35
36
  export * from './lib/tenant-email-catalog';
36
37
  export * from './lib/host-email-render';
package/src/index.js CHANGED
@@ -35,6 +35,7 @@ export * from "./lib/retention-emails.js";
35
35
  export * from "./lib/site-care-emails.js";
36
36
  export * from "./lib/site-care-project-emails.js";
37
37
  export * from "./lib/domain-emails.js";
38
+ export * from "./lib/pos-hardware-emails.js";
38
39
  export * from "./lib/welcome-email.js";
39
40
  export * from "./lib/tenant-email-catalog.js";
40
41
  export * from "./lib/host-email-render.js";
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/shared/util/email/src/index.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\nexport * from './lib/send-email'\n// Who carries the mail (AGL-3080): the provider contract, and the selection\n// of the deployment's provider from the built-ins and any a plugin\n// registered. The providers themselves are imported by their own paths —\n// `@aglyn/shared-util-email/mail-provider-resend`, `…/mail-provider-webhook`\n// — because nothing outside the seam should name one.\nexport * from './lib/mail-provider'\nexport * from './lib/mail-providers'\nexport * from './lib/send-rate'\nexport * from './lib/sender-reputation'\nexport * from './lib/send-ceilings'\nexport * from './lib/sending-domain'\nexport * from './lib/tracking-host'\nexport * from './lib/sending-mailbox'\nexport * from './lib/host-sender'\nexport * from './lib/platform-sending-domain'\nexport * from './lib/email-health'\nexport * from './lib/system-email-catalog'\nexport * from './lib/retention-emails'\nexport * from './lib/site-care-emails'\nexport * from './lib/site-care-project-emails'\nexport * from './lib/domain-emails'\nexport * from './lib/welcome-email'\nexport * from './lib/tenant-email-catalog'\nexport * from './lib/host-email-render'\nexport * from './lib/email-render'\nexport * from './lib/text-email-html'\nexport * from './lib/marketing-send'\n// The List-Unsubscribe setting sequences and campaigns share (AGL-3307).\nexport * from './lib/list-unsubscribe'\nexport * from './lib/email-delivery-events'\n// Received mail in the platform's vocabulary, which the CRM's capture route\n// files from (AGL-2657); the provider reads it.\n// Its neighbor `./lib/svix-signature` is deliberately NOT re-exported here:\n// it holds a `crypto` HMAC, and this barrel is reached from the browser\n// through `@aglyn/shared-ui-email-campaigns`, so a webhook imports it by its\n// own path — `@aglyn/shared-util-email/svix-signature`.\nexport * from './lib/received-email'\nexport * from './lib/email-revenue-window'\n// Exported so the console drift guard can pin it against @aglyn/aglyn.\nexport * from './lib/email-media-src'\n// Same arrangement, same reason (AGL-1223): a copy of `decodeStoredNodes`\n// this scope:shared lib may not import, pinned by `email-nodes-drift.spec.ts`.\nexport * from './lib/stored-email-nodes'\nexport * from './lib/email-merge'\n// The deliverability engine every send path asks (AGL-3328): the gateway an\n// MX names and its ledger, the bounce reader, and the address verdicts. Pure\n// — the DNS lookup and the store are injected by `@aglyn/tenant-data-admin`,\n// so nothing here reaches `node:dns` from the browser.\nexport * from './lib/mail-gateway'\nexport * from './lib/mail-bounce'\nexport * from './lib/email-deliverability'\n// The sender's side of the same engine (AGL-3328): SPF, DKIM and DMARC for\n// the domain mail leaves from, and whether they align. Pure as well; the\n// lookups are `@aglyn/tenant-data-admin`'s.\nexport * from './lib/sender-readiness'\n// The outbound phishing screen a young workspace's campaigns and automated\n// email pass (AGL-3356). Pure; the hold it leads to is `tenant-data-admin`'s.\nexport * from './lib/outbound-phishing-screen'\n// The send seam's gate for that screen — the store a hold writes is injected\n// by `@aglyn/tenant-data-admin`, like the governor's.\nexport * from './lib/outbound-screen-gate'\n// The same screen read over a published page (AGL-3356): lookalike links and\n// embeds, author-defined credential fields, a brand's call to action.\nexport * from './lib/hosted-page-screen'\n// The reputation lookup every foreign link a page, an email or a redirect\n// points at passes (AGL-3451). Pure; the lookup is injected by\n// `@aglyn/tenant-data-admin`, which holds the credential and the cache.\nexport * from './lib/link-reputation'\n// The site's theme palette as plain data (AGL-3370), so a palette token an\n// author picked resolves in mail. Built without MUI; `shared-ui-theme`'s\n// parity spec holds it equal to the theme.\nexport * from './lib/email-palette'\nexport * from './lib/email-design-chrome'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,cAAc,sBAAkB;AAChC,4EAA4E;AAC5E,mEAAmE;AACnE,yEAAyE;AACzE,6EAA6E;AAC7E,sDAAsD;AACtD,cAAc,yBAAqB;AACnC,cAAc,0BAAsB;AACpC,cAAc,qBAAiB;AAC/B,cAAc,6BAAyB;AACvC,cAAc,yBAAqB;AACnC,cAAc,0BAAsB;AACpC,cAAc,yBAAqB;AACnC,cAAc,2BAAuB;AACrC,cAAc,uBAAmB;AACjC,cAAc,mCAA+B;AAC7C,cAAc,wBAAoB;AAClC,cAAc,gCAA4B;AAC1C,cAAc,4BAAwB;AACtC,cAAc,4BAAwB;AACtC,cAAc,oCAAgC;AAC9C,cAAc,yBAAqB;AACnC,cAAc,yBAAqB;AACnC,cAAc,gCAA4B;AAC1C,cAAc,6BAAyB;AACvC,cAAc,wBAAoB;AAClC,cAAc,2BAAuB;AACrC,cAAc,0BAAsB;AACpC,yEAAyE;AACzE,cAAc,4BAAwB;AACtC,cAAc,iCAA6B;AAC3C,4EAA4E;AAC5E,gDAAgD;AAChD,4EAA4E;AAC5E,wEAAwE;AACxE,6EAA6E;AAC7E,wDAAwD;AACxD,cAAc,0BAAsB;AACpC,cAAc,gCAA4B;AAC1C,uEAAuE;AACvE,cAAc,2BAAuB;AACrC,0EAA0E;AAC1E,+EAA+E;AAC/E,cAAc,8BAA0B;AACxC,cAAc,uBAAmB;AACjC,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,uDAAuD;AACvD,cAAc,wBAAoB;AAClC,cAAc,uBAAmB;AACjC,cAAc,gCAA4B;AAC1C,2EAA2E;AAC3E,yEAAyE;AACzE,4CAA4C;AAC5C,cAAc,4BAAwB;AACtC,2EAA2E;AAC3E,8EAA8E;AAC9E,cAAc,oCAAgC;AAC9C,6EAA6E;AAC7E,sDAAsD;AACtD,cAAc,gCAA4B;AAC1C,6EAA6E;AAC7E,sEAAsE;AACtE,cAAc,8BAA0B;AACxC,0EAA0E;AAC1E,+DAA+D;AAC/D,wEAAwE;AACxE,cAAc,2BAAuB;AACrC,2EAA2E;AAC3E,yEAAyE;AACzE,2CAA2C;AAC3C,cAAc,yBAAqB;AACnC,cAAc,+BAA2B"}
1
+ {"version":3,"sources":["../../../../../../libs/shared/util/email/src/index.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\nexport * from './lib/send-email'\n// Who carries the mail (AGL-3080): the provider contract, and the selection\n// of the deployment's provider from the built-ins and any a plugin\n// registered. The providers themselves are imported by their own paths —\n// `@aglyn/shared-util-email/mail-provider-resend`, `…/mail-provider-webhook`\n// — because nothing outside the seam should name one.\nexport * from './lib/mail-provider'\nexport * from './lib/mail-providers'\nexport * from './lib/send-rate'\nexport * from './lib/sender-reputation'\nexport * from './lib/send-ceilings'\nexport * from './lib/sending-domain'\nexport * from './lib/tracking-host'\nexport * from './lib/sending-mailbox'\nexport * from './lib/host-sender'\nexport * from './lib/platform-sending-domain'\nexport * from './lib/email-health'\nexport * from './lib/system-email-catalog'\nexport * from './lib/retention-emails'\nexport * from './lib/site-care-emails'\nexport * from './lib/site-care-project-emails'\nexport * from './lib/domain-emails'\nexport * from './lib/pos-hardware-emails'\nexport * from './lib/welcome-email'\nexport * from './lib/tenant-email-catalog'\nexport * from './lib/host-email-render'\nexport * from './lib/email-render'\nexport * from './lib/text-email-html'\nexport * from './lib/marketing-send'\n// The List-Unsubscribe setting sequences and campaigns share (AGL-3307).\nexport * from './lib/list-unsubscribe'\nexport * from './lib/email-delivery-events'\n// Received mail in the platform's vocabulary, which the CRM's capture route\n// files from (AGL-2657); the provider reads it.\n// Its neighbor `./lib/svix-signature` is deliberately NOT re-exported here:\n// it holds a `crypto` HMAC, and this barrel is reached from the browser\n// through `@aglyn/shared-ui-email-campaigns`, so a webhook imports it by its\n// own path — `@aglyn/shared-util-email/svix-signature`.\nexport * from './lib/received-email'\nexport * from './lib/email-revenue-window'\n// Exported so the console drift guard can pin it against @aglyn/aglyn.\nexport * from './lib/email-media-src'\n// Same arrangement, same reason (AGL-1223): a copy of `decodeStoredNodes`\n// this scope:shared lib may not import, pinned by `email-nodes-drift.spec.ts`.\nexport * from './lib/stored-email-nodes'\nexport * from './lib/email-merge'\n// The deliverability engine every send path asks (AGL-3328): the gateway an\n// MX names and its ledger, the bounce reader, and the address verdicts. Pure\n// — the DNS lookup and the store are injected by `@aglyn/tenant-data-admin`,\n// so nothing here reaches `node:dns` from the browser.\nexport * from './lib/mail-gateway'\nexport * from './lib/mail-bounce'\nexport * from './lib/email-deliverability'\n// The sender's side of the same engine (AGL-3328): SPF, DKIM and DMARC for\n// the domain mail leaves from, and whether they align. Pure as well; the\n// lookups are `@aglyn/tenant-data-admin`'s.\nexport * from './lib/sender-readiness'\n// The outbound phishing screen a young workspace's campaigns and automated\n// email pass (AGL-3356). Pure; the hold it leads to is `tenant-data-admin`'s.\nexport * from './lib/outbound-phishing-screen'\n// The send seam's gate for that screen — the store a hold writes is injected\n// by `@aglyn/tenant-data-admin`, like the governor's.\nexport * from './lib/outbound-screen-gate'\n// The same screen read over a published page (AGL-3356): lookalike links and\n// embeds, author-defined credential fields, a brand's call to action.\nexport * from './lib/hosted-page-screen'\n// The reputation lookup every foreign link a page, an email or a redirect\n// points at passes (AGL-3451). Pure; the lookup is injected by\n// `@aglyn/tenant-data-admin`, which holds the credential and the cache.\nexport * from './lib/link-reputation'\n// The site's theme palette as plain data (AGL-3370), so a palette token an\n// author picked resolves in mail. Built without MUI; `shared-ui-theme`'s\n// parity spec holds it equal to the theme.\nexport * from './lib/email-palette'\nexport * from './lib/email-design-chrome'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,cAAc,sBAAkB;AAChC,4EAA4E;AAC5E,mEAAmE;AACnE,yEAAyE;AACzE,6EAA6E;AAC7E,sDAAsD;AACtD,cAAc,yBAAqB;AACnC,cAAc,0BAAsB;AACpC,cAAc,qBAAiB;AAC/B,cAAc,6BAAyB;AACvC,cAAc,yBAAqB;AACnC,cAAc,0BAAsB;AACpC,cAAc,yBAAqB;AACnC,cAAc,2BAAuB;AACrC,cAAc,uBAAmB;AACjC,cAAc,mCAA+B;AAC7C,cAAc,wBAAoB;AAClC,cAAc,gCAA4B;AAC1C,cAAc,4BAAwB;AACtC,cAAc,4BAAwB;AACtC,cAAc,oCAAgC;AAC9C,cAAc,yBAAqB;AACnC,cAAc,+BAA2B;AACzC,cAAc,yBAAqB;AACnC,cAAc,gCAA4B;AAC1C,cAAc,6BAAyB;AACvC,cAAc,wBAAoB;AAClC,cAAc,2BAAuB;AACrC,cAAc,0BAAsB;AACpC,yEAAyE;AACzE,cAAc,4BAAwB;AACtC,cAAc,iCAA6B;AAC3C,4EAA4E;AAC5E,gDAAgD;AAChD,4EAA4E;AAC5E,wEAAwE;AACxE,6EAA6E;AAC7E,wDAAwD;AACxD,cAAc,0BAAsB;AACpC,cAAc,gCAA4B;AAC1C,uEAAuE;AACvE,cAAc,2BAAuB;AACrC,0EAA0E;AAC1E,+EAA+E;AAC/E,cAAc,8BAA0B;AACxC,cAAc,uBAAmB;AACjC,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,uDAAuD;AACvD,cAAc,wBAAoB;AAClC,cAAc,uBAAmB;AACjC,cAAc,gCAA4B;AAC1C,2EAA2E;AAC3E,yEAAyE;AACzE,4CAA4C;AAC5C,cAAc,4BAAwB;AACtC,2EAA2E;AAC3E,8EAA8E;AAC9E,cAAc,oCAAgC;AAC9C,6EAA6E;AAC7E,sDAAsD;AACtD,cAAc,gCAA4B;AAC1C,6EAA6E;AAC7E,sEAAsE;AACtE,cAAc,8BAA0B;AACxC,0EAA0E;AAC1E,+DAA+D;AAC/D,wEAAwE;AACxE,cAAc,2BAAuB;AACrC,2EAA2E;AAC3E,yEAAyE;AACzE,2CAA2C;AAC3C,cAAc,yBAAqB;AACnC,cAAc,+BAA2B"}
@@ -25,5 +25,7 @@ export declare const DOMAIN_EMAIL_KEYS: {
25
25
  readonly expiring: "domain-expiring";
26
26
  readonly expired: "domain-expired";
27
27
  readonly transferCode: "domain-transfer-code";
28
+ readonly transferInCompleted: "domain-transfer-in-completed";
29
+ readonly transferInFailed: "domain-transfer-in-failed";
28
30
  };
29
31
  export declare function domainSystemEmailTemplates(origin: string): SystemEmailTemplateDefinition[];
@@ -18,7 +18,8 @@
18
18
  *
19
19
  * The domains plugin writes every one of these: the purchase, the refund
20
20
  * when a registration fails, ICANN's registrant check, the renewal notice
21
- * and its outcome, the expiry, and the transfer code. Each is a key of its
21
+ * and its outcome, the expiry, the transfer code, and a transfer in from
22
+ * another registrar finishing or failing (AGL-4040). Each is a key of its
22
23
  * own so staff can redesign one without touching the others.
23
24
  *
24
25
  * They live here, beside the catalog, because system emails have no plugin
@@ -36,7 +37,9 @@
36
37
  renewalFailed: 'domain-renewal-failed',
37
38
  expiring: 'domain-expiring',
38
39
  expired: 'domain-expired',
39
- transferCode: 'domain-transfer-code'
40
+ transferCode: 'domain-transfer-code',
41
+ transferInCompleted: 'domain-transfer-in-completed',
42
+ transferInFailed: 'domain-transfer-in-failed'
40
43
  };
41
44
  const SOURCE = 'libs/plugins/domains/src/lib/server/domain-emails.ts';
42
45
  function tokens(origin) {
@@ -58,7 +61,7 @@ function tokens(origin) {
58
61
  },
59
62
  manageUrl: {
60
63
  name: 'domain.manageUrl',
61
- description: "The site's Custom Domain page",
64
+ description: "Where the domain is managed: its site's Custom Domain page, or the workspace's Domains page for a domain no site uses",
62
65
  sample: `${origin}/test-org/hosts/test-bakery/admin/domain`
63
66
  },
64
67
  billingUrl: {
@@ -131,6 +134,11 @@ function tokens(origin) {
131
134
  description: 'Why the domain will not renew, in a sentence',
132
135
  sample: 'Auto-renew is turned off for it.'
133
136
  },
137
+ whereLine: {
138
+ name: 'domain.whereLine',
139
+ description: 'Where the new domain is going, in a sentence: being connected to its site, or into the workspace with no site yet',
140
+ sample: 'It is being connected to Test Bakery. It usually serves within a few minutes, with its security certificate set up for you. There are no DNS records to add.'
141
+ },
134
142
  requestedBy: {
135
143
  name: 'domain.requestedBy',
136
144
  description: 'Who asked for the transfer code',
@@ -145,7 +153,7 @@ export function domainSystemEmailTemplates(origin) {
145
153
  {
146
154
  key: DOMAIN_EMAIL_KEYS.purchased,
147
155
  name: 'Domain purchased',
148
- description: "Sent to a workspace's owners and admins when a domain bought for one " + 'of its sites is registered.',
156
+ description: "Sent to a workspace's owners and admins when a domain it bought, for " + 'one of its sites or for the workspace, is registered.',
149
157
  deliveredBy: 'resend',
150
158
  defaultSubject: '{{domain.name}} is yours',
151
159
  mergeTokens: [
@@ -157,6 +165,7 @@ export function domainSystemEmailTemplates(origin) {
157
165
  t.renewsOn,
158
166
  t.registrant,
159
167
  t.registrantEmail,
168
+ t.whereLine,
160
169
  t.manageUrl
161
170
  ],
162
171
  defaultBody: [
@@ -172,7 +181,7 @@ export function domainSystemEmailTemplates(origin) {
172
181
  },
173
182
  {
174
183
  block: 'text',
175
- text: '{{domain.name}} is registered to you and is being connected to {{site.name}}. It usually serves within a few minutes, with its security certificate set up for you. There are no DNS records to add.',
184
+ text: '{{domain.name}} is registered to you. {{domain.whereLine}}',
176
185
  variant: 'body'
177
186
  },
178
187
  {
@@ -580,6 +589,103 @@ export function domainSystemEmailTemplates(origin) {
580
589
  ],
581
590
  footerReason: footer,
582
591
  source: SOURCE
592
+ },
593
+ {
594
+ key: DOMAIN_EMAIL_KEYS.transferInCompleted,
595
+ name: 'Domain transfer in completed',
596
+ description: 'Sent when a domain the workspace moved here from another registrar ' + 'has arrived, with its new expiry date.',
597
+ deliveredBy: 'resend',
598
+ defaultSubject: '{{domain.name}} has moved here',
599
+ mergeTokens: [
600
+ t.domain,
601
+ t.org,
602
+ t.amount,
603
+ t.expiresOn,
604
+ t.renewalPrice,
605
+ t.manageUrl
606
+ ],
607
+ defaultBody: [
608
+ {
609
+ block: 'text',
610
+ text: '{{org.name}}',
611
+ variant: 'eyebrow'
612
+ },
613
+ {
614
+ block: 'text',
615
+ text: '{{domain.name}} has moved here',
616
+ variant: 'heading'
617
+ },
618
+ {
619
+ block: 'text',
620
+ text: 'The transfer of {{domain.name}} is complete, and a year was added to its registration. It is now in your workspace’s domains, where it renews with your other domains.',
621
+ variant: 'body'
622
+ },
623
+ {
624
+ block: 'text',
625
+ text: 'Charged: {{domain.amount}}\nRegistered until: {{domain.expiresOn}}\nRenews for: {{domain.renewalPrice}} a year',
626
+ variant: 'details'
627
+ },
628
+ {
629
+ block: 'text',
630
+ text: 'Its DNS stays where it was, so anything already using the domain keeps working. To use it for a site, connect it from the Domains page.',
631
+ variant: 'body'
632
+ },
633
+ {
634
+ block: 'button',
635
+ label: 'Open the Domains page',
636
+ href: '{{domain.manageUrl}}'
637
+ }
638
+ ],
639
+ footerReason: 'You’re receiving this because you manage {{org.name}} on ' + '{{brand.productName}} and it moved {{domain.name}} here.',
640
+ source: SOURCE
641
+ },
642
+ {
643
+ key: DOMAIN_EMAIL_KEYS.transferInFailed,
644
+ name: 'Domain transfer in failed',
645
+ description: 'Sent when a domain the workspace paid to move here could not be ' + 'transferred, and the charge was refunded.',
646
+ deliveredBy: 'resend',
647
+ defaultSubject: '{{domain.name}} couldn’t be moved here',
648
+ mergeTokens: [
649
+ t.domain,
650
+ t.org,
651
+ t.failure,
652
+ t.refund,
653
+ t.manageUrl
654
+ ],
655
+ defaultBody: [
656
+ {
657
+ block: 'text',
658
+ text: '{{org.name}}',
659
+ variant: 'eyebrow'
660
+ },
661
+ {
662
+ block: 'text',
663
+ text: '{{domain.name}} couldn’t be moved here',
664
+ variant: 'heading'
665
+ },
666
+ {
667
+ block: 'text',
668
+ text: '{{domain.failure}}',
669
+ variant: 'body'
670
+ },
671
+ {
672
+ block: 'text',
673
+ text: '{{domain.refund}}',
674
+ variant: 'body'
675
+ },
676
+ {
677
+ block: 'text',
678
+ text: 'The domain is still yours at your current registrar, and its website and email keep working. To try again, unlock it there, get a new transfer code, and start the transfer from the Domains page.',
679
+ variant: 'body'
680
+ },
681
+ {
682
+ block: 'button',
683
+ label: 'Open the Domains page',
684
+ href: '{{domain.manageUrl}}'
685
+ }
686
+ ],
687
+ footerReason: 'You’re receiving this because you manage {{org.name}} on ' + '{{brand.productName}} and it asked to move {{domain.name}} here.',
688
+ source: SOURCE
583
689
  }
584
690
  ];
585
691
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/domain-emails.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 * A DOMAIN BOUGHT THROUGH THE PLATFORM, AS SYSTEM EMAILS (AGL-3962).\n *\n * The domains plugin writes every one of these: the purchase, the refund\n * when a registration fails, ICANN's registrant check, the renewal notice\n * and its outcome, the expiry, and the transfer code. Each is a key of its\n * own so staff can redesign one without touching the others.\n *\n * They live here, beside the catalog, because system emails have no plugin\n * seam: the staff System emails page reads this registry before any plugin\n * loads. `source` names the plugin file that sends each one.\n *\n * Prices and dates arrive formatted (`$15.99`, `Oct 19, 2027`), because the\n * sender knows the currency and the reader's locale and a template does not.\n *=========================================*/\n\nimport type {\n SystemEmailMergeToken,\n SystemEmailTemplateDefinition,\n} from './system-email-catalog'\n\nexport const DOMAIN_EMAIL_KEYS = {\n purchased: 'domain-purchased',\n refunded: 'domain-refunded',\n verifyRegistrant: 'domain-verify-registrant',\n renewalNotice: 'domain-renewal-notice',\n renewed: 'domain-renewed',\n renewalFailed: 'domain-renewal-failed',\n expiring: 'domain-expiring',\n expired: 'domain-expired',\n transferCode: 'domain-transfer-code',\n} as const\n\nconst SOURCE = 'libs/plugins/domains/src/lib/server/domain-emails.ts'\n\nfunction tokens(origin: string): Record<string, SystemEmailMergeToken> {\n return {\n domain: { name: 'domain.name', description: 'The domain name', sample: 'testbakery.com' },\n site: { name: 'site.name', description: 'The site the domain belongs to', sample: 'Test Bakery' },\n org: { name: 'org.name', description: 'The workspace', sample: 'Test Org' },\n manageUrl: {\n name: 'domain.manageUrl',\n description: \"The site's Custom Domain page\",\n sample: `${origin}/test-org/hosts/test-bakery/admin/domain`,\n },\n billingUrl: {\n name: 'billingUrl',\n description: \"The workspace's Billing page\",\n sample: `${origin}/test-org/billing`,\n },\n firstYear: {\n name: 'domain.firstYear',\n description: 'What the first year cost',\n sample: '$15.99',\n },\n renewalPrice: { name: 'domain.renewalPrice', description: 'The yearly renewal price', sample: '$15.99' },\n renewsOn: { name: 'domain.renewsOn', description: 'The date the domain renews', sample: 'Oct 19, 2027' },\n chargeOn: {\n name: 'domain.chargeOn',\n description: 'About when the renewal is charged',\n sample: 'Sep 19, 2027',\n },\n expiresOn: { name: 'domain.expiresOn', description: 'The date the domain expires', sample: 'Oct 19, 2027' },\n registrant: {\n name: 'domain.registrant',\n description: 'Who the domain is registered to',\n sample: 'Alex Test',\n },\n registrantEmail: {\n name: 'domain.registrantEmail',\n description: \"The registrant's email, which the registrar verifies\",\n sample: 'alex@testbakery.com',\n },\n verifyBy: {\n name: 'domain.verifyBy',\n description: 'The date the registrant email must be confirmed by',\n sample: 'Nov 2, 2026',\n },\n amount: { name: 'domain.amount', description: 'An amount charged', sample: '$15.99' },\n refund: {\n name: 'domain.refund',\n description: 'What was refunded, or that nothing was charged, in a sentence',\n sample:\n 'We refunded $15.99 to the card it was charged to. A refund usually reaches the card within 5 to 10 business days.',\n },\n failure: {\n name: 'domain.failure',\n description: 'Why it did not happen, in a sentence',\n sample: 'Someone else registered it a moment before your order reached the registrar.',\n },\n nextAttempt: {\n name: 'domain.nextAttempt',\n description: 'When the renewal charge will be tried again',\n sample: 'Sep 22, 2027',\n },\n expiryReason: {\n name: 'domain.expiryReason',\n description: 'Why the domain will not renew, in a sentence',\n sample: 'Auto-renew is turned off for it.',\n },\n requestedBy: {\n name: 'domain.requestedBy',\n description: 'Who asked for the transfer code',\n sample: 'alex@testbakery.com',\n },\n }\n}\n\nexport function domainSystemEmailTemplates(\n origin: string,\n): SystemEmailTemplateDefinition[] {\n const t = tokens(origin)\n const footer =\n 'You’re receiving this because you manage {{org.name}} on ' +\n '{{brand.productName}} and it bought {{domain.name}} through it.'\n return [\n {\n key: DOMAIN_EMAIL_KEYS.purchased,\n name: 'Domain purchased',\n description:\n \"Sent to a workspace's owners and admins when a domain bought for one \" +\n 'of its sites is registered.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} is yours',\n mergeTokens: [\n t.domain, t.site, t.org, t.firstYear, t.renewalPrice, t.renewsOn,\n t.registrant, t.registrantEmail, t.manageUrl,\n ],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} is yours', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} is registered to you and is being connected to {{site.name}}. It usually serves within a few minutes, with its security certificate set up for you. There are no DNS records to add.', variant: 'body' },\n { block: 'text', text: 'Domain: {{domain.name}}\\nFirst year: {{domain.firstYear}}\\nRenews: {{domain.renewsOn}} for {{domain.renewalPrice}} a year\\nRegistered to: {{domain.registrant}}', variant: 'details' },\n { block: 'text', text: 'One thing for you to do', variant: 'subheading' },\n { block: 'text', text: 'The registrar will email {{domain.registrantEmail}} asking you to confirm the address. ICANN, which oversees domain names, requires it, and a domain whose owner never confirms can be suspended. Open that email and confirm when it arrives.', variant: 'body' },\n { block: 'button', label: 'Manage your domain', href: '{{domain.manageUrl}}' },\n { block: 'text', text: 'Auto-renew is on. You can turn it off, or move the domain to another registrar, at any time from the site’s Custom Domain page.', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.refunded,\n name: 'Domain purchase refunded',\n description:\n 'Sent when a domain could not be registered after it was paid for, ' +\n 'and the charge was refunded.',\n deliveredBy: 'resend',\n defaultSubject: 'We couldn’t register {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.failure, t.refund, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'We couldn’t register {{domain.name}}', variant: 'heading' },\n { block: 'text', text: '{{domain.failure}}', variant: 'body' },\n { block: 'text', text: '{{domain.refund}}', variant: 'body' },\n { block: 'text', text: 'Another name may well be free. The Custom Domain page searches as you type.', variant: 'body' },\n { block: 'button', label: 'Find another domain', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.verifyRegistrant,\n name: 'Confirm the domain’s registrant email',\n description:\n \"Reminds a workspace's owners that ICANN's registrant email check for \" +\n 'a bought domain is still outstanding.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email to keep {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.registrantEmail, t.verifyBy, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{domain.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm your email to keep {{domain.name}}', variant: 'heading' },\n { block: 'text', text: 'The registrar sent a confirmation email to {{domain.registrantEmail}}, and it has not been confirmed yet. ICANN requires every domain owner to confirm this address, and a domain that is not confirmed by {{domain.verifyBy}} can be suspended, which takes the site offline at that address.', variant: 'body' },\n { block: 'text', text: 'Look for an email about verifying your domain contact information, including in your spam folder, and follow its link. If it never arrived, contact support: {{brand.supportUrl}}', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewalNotice,\n name: 'Domain renewal notice',\n description:\n 'Sent about 45 days before a bought domain renews, naming the price ' +\n 'and the date it will be charged.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} renews on {{domain.renewsOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.renewalPrice, t.renewsOn, t.chargeOn, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} renews on {{domain.renewsOn}}', variant: 'heading' },\n { block: 'text', text: 'Auto-renew is on for {{domain.name}}, so it will renew for another year and keep {{site.name}} at the same address.', variant: 'body' },\n { block: 'text', text: 'Renewal: {{domain.renewalPrice}} for one year\\nCharged: around {{domain.chargeOn}}, to the card on file\\nRenews: {{domain.renewsOn}}', variant: 'details' },\n { block: 'text', text: 'You will not be charged more than this for this renewal. If you no longer want the domain, turn auto-renew off before {{domain.chargeOn}} and it will expire on {{domain.renewsOn}}.', variant: 'body' },\n { block: 'button', label: 'Manage auto-renew', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewed,\n name: 'Domain renewed',\n description: 'Confirms a bought domain renewed for another year.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} is renewed until {{domain.expiresOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.amount, t.expiresOn, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} is renewed', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} renewed for another year, so {{site.name}} keeps its address.', variant: 'body' },\n { block: 'text', text: 'Charged: {{domain.amount}}\\nRegistered until: {{domain.expiresOn}}', variant: 'details' },\n { block: 'button', label: 'Manage your domain', href: '{{domain.manageUrl}}' },\n { block: 'text', text: 'The receipt is with your other invoices on the Billing page.', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewalFailed,\n name: 'Domain renewal payment failed',\n description:\n 'Sent when the charge for a domain renewal fails, with the next try ' +\n 'and the date the domain expires.',\n deliveredBy: 'resend',\n defaultSubject: 'We couldn’t renew {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.renewalPrice, t.nextAttempt, t.expiresOn, t.billingUrl, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'We couldn’t renew {{domain.name}}', variant: 'heading' },\n { block: 'text', text: 'The {{domain.renewalPrice}} renewal for {{domain.name}} could not be charged to the card on file.', variant: 'body' },\n { block: 'text', text: 'Next try: {{domain.nextAttempt}}\\nExpires if not renewed: {{domain.expiresOn}}', variant: 'details' },\n { block: 'text', text: 'Update the card on the Billing page and we will try again on {{domain.nextAttempt}}, or renew it right away from the Custom Domain page. If the domain expires, {{site.name}} goes back to its free address.', variant: 'body' },\n { block: 'button', label: 'Update payment method', href: '{{billingUrl}}' },\n { block: 'text', text: 'Renew now: {{domain.manageUrl}}', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.expiring,\n name: 'Domain expiring',\n description:\n 'Sent before a bought domain expires because it will not renew: ' +\n 'auto-renew is off, or its renewal could not be charged.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} expires on {{domain.expiresOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.expiresOn, t.expiryReason, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} expires on {{domain.expiresOn}}', variant: 'heading' },\n { block: 'text', text: '{{domain.expiryReason}} After {{domain.expiresOn}}, {{site.name}} goes back to its free address, and the domain may become available for anyone to register.', variant: 'body' },\n { block: 'text', text: 'To keep it, turn auto-renew on or renew it now from the Custom Domain page.', variant: 'body' },\n { block: 'button', label: 'Keep {{domain.name}}', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.expired,\n name: 'Domain expired',\n description: 'Sent when a bought domain has expired.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} has expired',\n mergeTokens: [t.domain, t.site, t.org, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} has expired', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} reached the end of its registration and was not renewed. {{site.name}} is back on its free address, so it is still online.', variant: 'body' },\n { block: 'text', text: 'For a short while after it expires, a domain can usually still be renewed by its owner. The Custom Domain page shows whether yours can.', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.transferCode,\n name: 'Domain transfer code requested',\n description:\n 'Tells a workspace’s owners that someone asked for the code that moves ' +\n 'a bought domain to another registrar.',\n deliveredBy: 'resend',\n defaultSubject: 'A transfer code was requested for {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.requestedBy, t.manageUrl],\n defaultBody: [\n { block: 'text', text: 'Security · {{domain.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'A transfer code was requested for {{domain.name}}', variant: 'heading' },\n { block: 'text', text: '{{domain.requestedBy}} asked for the code that moves {{domain.name}} to another registrar. The code was shown to them in the console.', variant: 'body' },\n { block: 'text', text: 'If that was expected, there is nothing to do. If not, tell your workspace’s owner and contact support right away: {{brand.supportUrl}}', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n ]\n}\n"],"names":["DOMAIN_EMAIL_KEYS","purchased","refunded","verifyRegistrant","renewalNotice","renewed","renewalFailed","expiring","expired","transferCode","SOURCE","tokens","origin","domain","name","description","sample","site","org","manageUrl","billingUrl","firstYear","renewalPrice","renewsOn","chargeOn","expiresOn","registrant","registrantEmail","verifyBy","amount","refund","failure","nextAttempt","expiryReason","requestedBy","domainSystemEmailTemplates","t","footer","key","deliveredBy","defaultSubject","mergeTokens","defaultBody","block","text","variant","label","href","footerReason","source"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/domain-emails.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 * A DOMAIN BOUGHT THROUGH THE PLATFORM, AS SYSTEM EMAILS (AGL-3962).\n *\n * The domains plugin writes every one of these: the purchase, the refund\n * when a registration fails, ICANN's registrant check, the renewal notice\n * and its outcome, the expiry, the transfer code, and a transfer in from\n * another registrar finishing or failing (AGL-4040). Each is a key of its\n * own so staff can redesign one without touching the others.\n *\n * They live here, beside the catalog, because system emails have no plugin\n * seam: the staff System emails page reads this registry before any plugin\n * loads. `source` names the plugin file that sends each one.\n *\n * Prices and dates arrive formatted (`$15.99`, `Oct 19, 2027`), because the\n * sender knows the currency and the reader's locale and a template does not.\n *=========================================*/\n\nimport type {\n SystemEmailMergeToken,\n SystemEmailTemplateDefinition,\n} from './system-email-catalog'\n\nexport const DOMAIN_EMAIL_KEYS = {\n purchased: 'domain-purchased',\n refunded: 'domain-refunded',\n verifyRegistrant: 'domain-verify-registrant',\n renewalNotice: 'domain-renewal-notice',\n renewed: 'domain-renewed',\n renewalFailed: 'domain-renewal-failed',\n expiring: 'domain-expiring',\n expired: 'domain-expired',\n transferCode: 'domain-transfer-code',\n transferInCompleted: 'domain-transfer-in-completed',\n transferInFailed: 'domain-transfer-in-failed',\n} as const\n\nconst SOURCE = 'libs/plugins/domains/src/lib/server/domain-emails.ts'\n\nfunction tokens(origin: string): Record<string, SystemEmailMergeToken> {\n return {\n domain: { name: 'domain.name', description: 'The domain name', sample: 'testbakery.com' },\n site: { name: 'site.name', description: 'The site the domain belongs to', sample: 'Test Bakery' },\n org: { name: 'org.name', description: 'The workspace', sample: 'Test Org' },\n manageUrl: {\n name: 'domain.manageUrl',\n description:\n \"Where the domain is managed: its site's Custom Domain page, or the workspace's Domains page for a domain no site uses\",\n sample: `${origin}/test-org/hosts/test-bakery/admin/domain`,\n },\n billingUrl: {\n name: 'billingUrl',\n description: \"The workspace's Billing page\",\n sample: `${origin}/test-org/billing`,\n },\n firstYear: {\n name: 'domain.firstYear',\n description: 'What the first year cost',\n sample: '$15.99',\n },\n renewalPrice: { name: 'domain.renewalPrice', description: 'The yearly renewal price', sample: '$15.99' },\n renewsOn: { name: 'domain.renewsOn', description: 'The date the domain renews', sample: 'Oct 19, 2027' },\n chargeOn: {\n name: 'domain.chargeOn',\n description: 'About when the renewal is charged',\n sample: 'Sep 19, 2027',\n },\n expiresOn: { name: 'domain.expiresOn', description: 'The date the domain expires', sample: 'Oct 19, 2027' },\n registrant: {\n name: 'domain.registrant',\n description: 'Who the domain is registered to',\n sample: 'Alex Test',\n },\n registrantEmail: {\n name: 'domain.registrantEmail',\n description: \"The registrant's email, which the registrar verifies\",\n sample: 'alex@testbakery.com',\n },\n verifyBy: {\n name: 'domain.verifyBy',\n description: 'The date the registrant email must be confirmed by',\n sample: 'Nov 2, 2026',\n },\n amount: { name: 'domain.amount', description: 'An amount charged', sample: '$15.99' },\n refund: {\n name: 'domain.refund',\n description: 'What was refunded, or that nothing was charged, in a sentence',\n sample:\n 'We refunded $15.99 to the card it was charged to. A refund usually reaches the card within 5 to 10 business days.',\n },\n failure: {\n name: 'domain.failure',\n description: 'Why it did not happen, in a sentence',\n sample: 'Someone else registered it a moment before your order reached the registrar.',\n },\n nextAttempt: {\n name: 'domain.nextAttempt',\n description: 'When the renewal charge will be tried again',\n sample: 'Sep 22, 2027',\n },\n expiryReason: {\n name: 'domain.expiryReason',\n description: 'Why the domain will not renew, in a sentence',\n sample: 'Auto-renew is turned off for it.',\n },\n whereLine: {\n name: 'domain.whereLine',\n description:\n 'Where the new domain is going, in a sentence: being connected to its site, or into the workspace with no site yet',\n sample:\n 'It is being connected to Test Bakery. It usually serves within a few minutes, with its security certificate set up for you. There are no DNS records to add.',\n },\n requestedBy: {\n name: 'domain.requestedBy',\n description: 'Who asked for the transfer code',\n sample: 'alex@testbakery.com',\n },\n }\n}\n\nexport function domainSystemEmailTemplates(\n origin: string,\n): SystemEmailTemplateDefinition[] {\n const t = tokens(origin)\n const footer =\n 'You’re receiving this because you manage {{org.name}} on ' +\n '{{brand.productName}} and it bought {{domain.name}} through it.'\n return [\n {\n key: DOMAIN_EMAIL_KEYS.purchased,\n name: 'Domain purchased',\n description:\n \"Sent to a workspace's owners and admins when a domain it bought, for \" +\n 'one of its sites or for the workspace, is registered.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} is yours',\n mergeTokens: [\n t.domain, t.site, t.org, t.firstYear, t.renewalPrice, t.renewsOn,\n t.registrant, t.registrantEmail, t.whereLine, t.manageUrl,\n ],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} is yours', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} is registered to you. {{domain.whereLine}}', variant: 'body' },\n { block: 'text', text: 'Domain: {{domain.name}}\\nFirst year: {{domain.firstYear}}\\nRenews: {{domain.renewsOn}} for {{domain.renewalPrice}} a year\\nRegistered to: {{domain.registrant}}', variant: 'details' },\n { block: 'text', text: 'One thing for you to do', variant: 'subheading' },\n { block: 'text', text: 'The registrar will email {{domain.registrantEmail}} asking you to confirm the address. ICANN, which oversees domain names, requires it, and a domain whose owner never confirms can be suspended. Open that email and confirm when it arrives.', variant: 'body' },\n { block: 'button', label: 'Manage your domain', href: '{{domain.manageUrl}}' },\n { block: 'text', text: 'Auto-renew is on. You can turn it off, or move the domain to another registrar, at any time from the site’s Custom Domain page.', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.refunded,\n name: 'Domain purchase refunded',\n description:\n 'Sent when a domain could not be registered after it was paid for, ' +\n 'and the charge was refunded.',\n deliveredBy: 'resend',\n defaultSubject: 'We couldn’t register {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.failure, t.refund, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'We couldn’t register {{domain.name}}', variant: 'heading' },\n { block: 'text', text: '{{domain.failure}}', variant: 'body' },\n { block: 'text', text: '{{domain.refund}}', variant: 'body' },\n { block: 'text', text: 'Another name may well be free. The Custom Domain page searches as you type.', variant: 'body' },\n { block: 'button', label: 'Find another domain', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.verifyRegistrant,\n name: 'Confirm the domain’s registrant email',\n description:\n \"Reminds a workspace's owners that ICANN's registrant email check for \" +\n 'a bought domain is still outstanding.',\n deliveredBy: 'resend',\n defaultSubject: 'Confirm your email to keep {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.registrantEmail, t.verifyBy, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{domain.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Confirm your email to keep {{domain.name}}', variant: 'heading' },\n { block: 'text', text: 'The registrar sent a confirmation email to {{domain.registrantEmail}}, and it has not been confirmed yet. ICANN requires every domain owner to confirm this address, and a domain that is not confirmed by {{domain.verifyBy}} can be suspended, which takes the site offline at that address.', variant: 'body' },\n { block: 'text', text: 'Look for an email about verifying your domain contact information, including in your spam folder, and follow its link. If it never arrived, contact support: {{brand.supportUrl}}', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewalNotice,\n name: 'Domain renewal notice',\n description:\n 'Sent about 45 days before a bought domain renews, naming the price ' +\n 'and the date it will be charged.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} renews on {{domain.renewsOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.renewalPrice, t.renewsOn, t.chargeOn, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} renews on {{domain.renewsOn}}', variant: 'heading' },\n { block: 'text', text: 'Auto-renew is on for {{domain.name}}, so it will renew for another year and keep {{site.name}} at the same address.', variant: 'body' },\n { block: 'text', text: 'Renewal: {{domain.renewalPrice}} for one year\\nCharged: around {{domain.chargeOn}}, to the card on file\\nRenews: {{domain.renewsOn}}', variant: 'details' },\n { block: 'text', text: 'You will not be charged more than this for this renewal. If you no longer want the domain, turn auto-renew off before {{domain.chargeOn}} and it will expire on {{domain.renewsOn}}.', variant: 'body' },\n { block: 'button', label: 'Manage auto-renew', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewed,\n name: 'Domain renewed',\n description: 'Confirms a bought domain renewed for another year.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} is renewed until {{domain.expiresOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.amount, t.expiresOn, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} is renewed', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} renewed for another year, so {{site.name}} keeps its address.', variant: 'body' },\n { block: 'text', text: 'Charged: {{domain.amount}}\\nRegistered until: {{domain.expiresOn}}', variant: 'details' },\n { block: 'button', label: 'Manage your domain', href: '{{domain.manageUrl}}' },\n { block: 'text', text: 'The receipt is with your other invoices on the Billing page.', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.renewalFailed,\n name: 'Domain renewal payment failed',\n description:\n 'Sent when the charge for a domain renewal fails, with the next try ' +\n 'and the date the domain expires.',\n deliveredBy: 'resend',\n defaultSubject: 'We couldn’t renew {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.renewalPrice, t.nextAttempt, t.expiresOn, t.billingUrl, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'We couldn’t renew {{domain.name}}', variant: 'heading' },\n { block: 'text', text: 'The {{domain.renewalPrice}} renewal for {{domain.name}} could not be charged to the card on file.', variant: 'body' },\n { block: 'text', text: 'Next try: {{domain.nextAttempt}}\\nExpires if not renewed: {{domain.expiresOn}}', variant: 'details' },\n { block: 'text', text: 'Update the card on the Billing page and we will try again on {{domain.nextAttempt}}, or renew it right away from the Custom Domain page. If the domain expires, {{site.name}} goes back to its free address.', variant: 'body' },\n { block: 'button', label: 'Update payment method', href: '{{billingUrl}}' },\n { block: 'text', text: 'Renew now: {{domain.manageUrl}}', variant: 'caption' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.expiring,\n name: 'Domain expiring',\n description:\n 'Sent before a bought domain expires because it will not renew: ' +\n 'auto-renew is off, or its renewal could not be charged.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} expires on {{domain.expiresOn}}',\n mergeTokens: [t.domain, t.site, t.org, t.expiresOn, t.expiryReason, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} expires on {{domain.expiresOn}}', variant: 'heading' },\n { block: 'text', text: '{{domain.expiryReason}} After {{domain.expiresOn}}, {{site.name}} goes back to its free address, and the domain may become available for anyone to register.', variant: 'body' },\n { block: 'text', text: 'To keep it, turn auto-renew on or renew it now from the Custom Domain page.', variant: 'body' },\n { block: 'button', label: 'Keep {{domain.name}}', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.expired,\n name: 'Domain expired',\n description: 'Sent when a bought domain has expired.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} has expired',\n mergeTokens: [t.domain, t.site, t.org, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{site.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} has expired', variant: 'heading' },\n { block: 'text', text: '{{domain.name}} reached the end of its registration and was not renewed. {{site.name}} is back on its free address, so it is still online.', variant: 'body' },\n { block: 'text', text: 'For a short while after it expires, a domain can usually still be renewed by its owner. The Custom Domain page shows whether yours can.', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.transferCode,\n name: 'Domain transfer code requested',\n description:\n 'Tells a workspace’s owners that someone asked for the code that moves ' +\n 'a bought domain to another registrar.',\n deliveredBy: 'resend',\n defaultSubject: 'A transfer code was requested for {{domain.name}}',\n mergeTokens: [t.domain, t.site, t.org, t.requestedBy, t.manageUrl],\n defaultBody: [\n { block: 'text', text: 'Security · {{domain.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'A transfer code was requested for {{domain.name}}', variant: 'heading' },\n { block: 'text', text: '{{domain.requestedBy}} asked for the code that moves {{domain.name}} to another registrar. The code was shown to them in the console.', variant: 'body' },\n { block: 'text', text: 'If that was expected, there is nothing to do. If not, tell your workspace’s owner and contact support right away: {{brand.supportUrl}}', variant: 'body' },\n { block: 'button', label: 'Open the Custom Domain page', href: '{{domain.manageUrl}}' },\n ],\n footerReason: footer,\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.transferInCompleted,\n name: 'Domain transfer in completed',\n description:\n 'Sent when a domain the workspace moved here from another registrar ' +\n 'has arrived, with its new expiry date.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} has moved here',\n mergeTokens: [t.domain, t.org, t.amount, t.expiresOn, t.renewalPrice, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} has moved here', variant: 'heading' },\n { block: 'text', text: 'The transfer of {{domain.name}} is complete, and a year was added to its registration. It is now in your workspace’s domains, where it renews with your other domains.', variant: 'body' },\n { block: 'text', text: 'Charged: {{domain.amount}}\\nRegistered until: {{domain.expiresOn}}\\nRenews for: {{domain.renewalPrice}} a year', variant: 'details' },\n { block: 'text', text: 'Its DNS stays where it was, so anything already using the domain keeps working. To use it for a site, connect it from the Domains page.', variant: 'body' },\n { block: 'button', label: 'Open the Domains page', href: '{{domain.manageUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because you manage {{org.name}} on ' +\n '{{brand.productName}} and it moved {{domain.name}} here.',\n source: SOURCE,\n },\n {\n key: DOMAIN_EMAIL_KEYS.transferInFailed,\n name: 'Domain transfer in failed',\n description:\n 'Sent when a domain the workspace paid to move here could not be ' +\n 'transferred, and the charge was refunded.',\n deliveredBy: 'resend',\n defaultSubject: '{{domain.name}} couldn’t be moved here',\n mergeTokens: [t.domain, t.org, t.failure, t.refund, t.manageUrl],\n defaultBody: [\n { block: 'text', text: '{{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{domain.name}} couldn’t be moved here', variant: 'heading' },\n { block: 'text', text: '{{domain.failure}}', variant: 'body' },\n { block: 'text', text: '{{domain.refund}}', variant: 'body' },\n { block: 'text', text: 'The domain is still yours at your current registrar, and its website and email keep working. To try again, unlock it there, get a new transfer code, and start the transfer from the Domains page.', variant: 'body' },\n { block: 'button', label: 'Open the Domains page', href: '{{domain.manageUrl}}' },\n ],\n footerReason:\n 'You’re receiving this because you manage {{org.name}} on ' +\n '{{brand.productName}} and it asked to move {{domain.name}} here.',\n source: SOURCE,\n },\n ]\n}\n"],"names":["DOMAIN_EMAIL_KEYS","purchased","refunded","verifyRegistrant","renewalNotice","renewed","renewalFailed","expiring","expired","transferCode","transferInCompleted","transferInFailed","SOURCE","tokens","origin","domain","name","description","sample","site","org","manageUrl","billingUrl","firstYear","renewalPrice","renewsOn","chargeOn","expiresOn","registrant","registrantEmail","verifyBy","amount","refund","failure","nextAttempt","expiryReason","whereLine","requestedBy","domainSystemEmailTemplates","t","footer","key","deliveredBy","defaultSubject","mergeTokens","defaultBody","block","text","variant","label","href","footerReason","source"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Links the bare URLs and email addresses in one escaped line.
2
+ * Links the bare URLs in one escaped line.
3
3
  *
4
4
  * Balanced closing parens and brackets are kept, because a URL can genuinely
5
5
  * end in one and a wrapping "(see https://…/a_(b))" is the rarer case.
@@ -48,31 +48,23 @@
48
48
  * page to resolve a relative path against — and matching bare `www.` would
49
49
  * turn ordinary prose into links nobody wrote.
50
50
  */ const BARE_URL = /https?:\/\/[^\s<>"]+/g;
51
- /**
52
- * Bare email addresses, linked as `mailto:`.
53
- *
54
- * Apple Mail, Gmail and Outlook detect an address in text and link it
55
- * themselves, in their own link color rather than the theme's. Linking it
56
- * here paints it the same accent-text shade as every other link. The domain
57
- * must end in a letters-only label, so a sentence's closing period stays
58
- * prose.
59
- */ const BARE_EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}/;
60
- /**
61
- * A URL or an address, URL first: an address inside a URL's query string
62
- * belongs to that URL.
63
- */ const BARE_LINK = new RegExp(`${BARE_URL.source}|${BARE_EMAIL.source}`, 'g');
64
- function anchor(href, label, color) {
51
+ /*
52
+ * Bare email addresses stay text. Linking them as `mailto:` painted them in
53
+ * the theme's link color, but a notification that names someone puts a link
54
+ * to THEIR domain in our mail, and a link whose domain is not the sender's
55
+ * is a spam-filter signal (Resend's insights flag every one). Apple Mail,
56
+ * Gmail and Outlook still detect the address and link it themselves.
57
+ */ function anchor(href, label, color) {
65
58
  return `<a href="${href}" target="_blank" ` + `style="color:${color};text-decoration:underline;word-break:break-word;">` + `${label}</a>`;
66
59
  }
67
60
  /**
68
- * Links the bare URLs and email addresses in one escaped line.
61
+ * Links the bare URLs in one escaped line.
69
62
  *
70
63
  * Balanced closing parens and brackets are kept, because a URL can genuinely
71
64
  * end in one and a wrapping "(see https://…/a_(b))" is the rarer case.
72
65
  * Anything the count says is unbalanced belongs to the prose.
73
66
  */ export function linkifyEscapedText(escaped, /** The link color: the sender's accent text shade, the platform's by default. */ color = PLATFORM_EMAIL_ACCENT.link) {
74
- return escaped.replace(BARE_LINK, (match)=>{
75
- if (!/^https?:\/\//.test(match)) return anchor(`mailto:${match}`, match, color);
67
+ return escaped.replace(BARE_URL, (match)=>{
76
68
  let url = match.replace(URL_TRAILING_PUNCTUATION, '');
77
69
  // `)` and `]` alike: a token's value dropped into "[{{brand.supportUrl}}]"
78
70
  // closes on a bracket the URL never opened.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/email-linkify.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 */\nimport { PLATFORM_EMAIL_ACCENT } from './email-palette'\n\n/**\n * Bare URLs in escaped text, made into links (AGL-3367).\n *\n * Shared by the two places a sender's plain words become HTML: the fallback\n * HTML part `sendEmail` synthesizes for a text-only message, and the\n * renderer's `emailText` block. The second is where a platform email's\n * composed body lands once it wears the system chrome, so without this a\n * digest that used to arrive with clickable links in its fallback part would\n * arrive branded and dead.\n */\n\n/**\n * Trailing characters stripped from a matched URL.\n *\n * A sentence that ends \"…see {@link https://example.com/billing}.\" puts the\n * period inside the match, because a period is a legal URL character and the\n * regex cannot tell prose from path. Closing brackets are handled separately\n * below, since a URL may legitimately end in one.\n *\n * `;` is deliberately absent: by the time this runs the text is already\n * escaped, so a query string reads `?a=1&amp;b=2` and trimming `;` would cut\n * an entity in half and corrupt the link.\n */\nconst URL_TRAILING_PUNCTUATION = /[.,!?'\"]+$/\n\n/**\n * Bare absolute URLs in already-escaped text.\n *\n * Matched AFTER escaping, not before, so the href and the visible label are\n * the same string and neither can reintroduce markup: `&` inside a query\n * string is `&amp;` by then, which is what an href attribute is supposed to\n * carry and parses back to `&` in the client.\n *\n * `http`/`https` only. Every URL our system copy emits is absolute — the\n * senders share one `consoleOrigin()` precisely because a mail client has no\n * page to resolve a relative path against — and matching bare `www.` would\n * turn ordinary prose into links nobody wrote.\n */\nconst BARE_URL = /https?:\\/\\/[^\\s<>\"]+/g\n\n/**\n * Bare email addresses, linked as `mailto:`.\n *\n * Apple Mail, Gmail and Outlook detect an address in text and link it\n * themselves, in their own link color rather than the theme's. Linking it\n * here paints it the same accent-text shade as every other link. The domain\n * must end in a letters-only label, so a sentence's closing period stays\n * prose.\n */\nconst BARE_EMAIL =\n /[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,}/\n\n/**\n * A URL or an address, URL first: an address inside a URL's query string\n * belongs to that URL.\n */\nconst BARE_LINK = new RegExp(`${BARE_URL.source}|${BARE_EMAIL.source}`, 'g')\n\nfunction anchor(href: string, label: string, color: string): string {\n return (\n `<a href=\"${href}\" target=\"_blank\" ` +\n `style=\"color:${color};text-decoration:underline;word-break:break-word;\">` +\n `${label}</a>`\n )\n}\n\n/**\n * Links the bare URLs and email addresses in one escaped line.\n *\n * Balanced closing parens and brackets are kept, because a URL can genuinely\n * end in one and a wrapping \"(see https://…/a_(b))\" is the rarer case.\n * Anything the count says is unbalanced belongs to the prose.\n */\nexport function linkifyEscapedText(\n escaped: string,\n /** The link color: the sender's accent text shade, the platform's by default. */\n color = PLATFORM_EMAIL_ACCENT.link,\n): string {\n return escaped.replace(BARE_LINK, (match) => {\n if (!/^https?:\\/\\//.test(match)) return anchor(`mailto:${match}`, match, color)\n let url = match.replace(URL_TRAILING_PUNCTUATION, '')\n // `)` and `]` alike: a token's value dropped into \"[{{brand.supportUrl}}]\"\n // closes on a bracket the URL never opened.\n for (;;) {\n const close = url.slice(-1)\n const open = close === ')' ? '(' : close === ']' ? '[' : ''\n if (!open || url.split(close).length <= url.split(open).length) break\n url = url.slice(0, -1)\n }\n if (!url) return match\n return `${anchor(url, url, color)}${match.slice(url.length)}`\n })\n}\n\n"],"names":["PLATFORM_EMAIL_ACCENT","URL_TRAILING_PUNCTUATION","BARE_URL","BARE_EMAIL","BARE_LINK","RegExp","source","anchor","href","label","color","linkifyEscapedText","escaped","link","replace","match","test","url","close","slice","open","split","length"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,SAASA,qBAAqB,QAAQ,qBAAiB;AAEvD;;;;;;;;;CASC,GAED;;;;;;;;;;;CAWC,GACD,MAAMC,2BAA2B;AAEjC;;;;;;;;;;;;CAYC,GACD,MAAMC,WAAW;AAEjB;;;;;;;;CAQC,GACD,MAAMC,aACJ;AAEF;;;CAGC,GACD,MAAMC,YAAY,IAAIC,OAAO,GAAGH,SAASI,MAAM,CAAC,CAAC,EAAEH,WAAWG,MAAM,EAAE,EAAE;AAExE,SAASC,OAAOC,IAAY,EAAEC,KAAa,EAAEC,KAAa;IACxD,OACE,CAAC,SAAS,EAAEF,KAAK,kBAAkB,CAAC,GACpC,CAAC,aAAa,EAAEE,MAAM,mDAAmD,CAAC,GAC1E,GAAGD,MAAM,IAAI,CAAC;AAElB;AAEA;;;;;;CAMC,GACD,OAAO,SAASE,mBACdC,OAAe,EACf,+EAA+E,GAC/EF,QAAQV,sBAAsBa,IAAI;IAElC,OAAOD,QAAQE,OAAO,CAACV,WAAW,CAACW;QACjC,IAAI,CAAC,eAAeC,IAAI,CAACD,QAAQ,OAAOR,OAAO,CAAC,OAAO,EAAEQ,OAAO,EAAEA,OAAOL;QACzE,IAAIO,MAAMF,MAAMD,OAAO,CAACb,0BAA0B;QAClD,2EAA2E;QAC3E,4CAA4C;QAC5C,OAAS;YACP,MAAMiB,QAAQD,IAAIE,KAAK,CAAC,CAAC;YACzB,MAAMC,OAAOF,UAAU,MAAM,MAAMA,UAAU,MAAM,MAAM;YACzD,IAAI,CAACE,QAAQH,IAAII,KAAK,CAACH,OAAOI,MAAM,IAAIL,IAAII,KAAK,CAACD,MAAME,MAAM,EAAE;YAChEL,MAAMA,IAAIE,KAAK,CAAC,GAAG,CAAC;QACtB;QACA,IAAI,CAACF,KAAK,OAAOF;QACjB,OAAO,GAAGR,OAAOU,KAAKA,KAAKP,SAASK,MAAMI,KAAK,CAACF,IAAIK,MAAM,GAAG;IAC/D;AACF"}
1
+ {"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/email-linkify.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 */\nimport { PLATFORM_EMAIL_ACCENT } from './email-palette'\n\n/**\n * Bare URLs in escaped text, made into links (AGL-3367).\n *\n * Shared by the two places a sender's plain words become HTML: the fallback\n * HTML part `sendEmail` synthesizes for a text-only message, and the\n * renderer's `emailText` block. The second is where a platform email's\n * composed body lands once it wears the system chrome, so without this a\n * digest that used to arrive with clickable links in its fallback part would\n * arrive branded and dead.\n */\n\n/**\n * Trailing characters stripped from a matched URL.\n *\n * A sentence that ends \"…see {@link https://example.com/billing}.\" puts the\n * period inside the match, because a period is a legal URL character and the\n * regex cannot tell prose from path. Closing brackets are handled separately\n * below, since a URL may legitimately end in one.\n *\n * `;` is deliberately absent: by the time this runs the text is already\n * escaped, so a query string reads `?a=1&amp;b=2` and trimming `;` would cut\n * an entity in half and corrupt the link.\n */\nconst URL_TRAILING_PUNCTUATION = /[.,!?'\"]+$/\n\n/**\n * Bare absolute URLs in already-escaped text.\n *\n * Matched AFTER escaping, not before, so the href and the visible label are\n * the same string and neither can reintroduce markup: `&` inside a query\n * string is `&amp;` by then, which is what an href attribute is supposed to\n * carry and parses back to `&` in the client.\n *\n * `http`/`https` only. Every URL our system copy emits is absolute — the\n * senders share one `consoleOrigin()` precisely because a mail client has no\n * page to resolve a relative path against — and matching bare `www.` would\n * turn ordinary prose into links nobody wrote.\n */\nconst BARE_URL = /https?:\\/\\/[^\\s<>\"]+/g\n\n/*\n * Bare email addresses stay text. Linking them as `mailto:` painted them in\n * the theme's link color, but a notification that names someone puts a link\n * to THEIR domain in our mail, and a link whose domain is not the sender's\n * is a spam-filter signal (Resend's insights flag every one). Apple Mail,\n * Gmail and Outlook still detect the address and link it themselves.\n */\n\nfunction anchor(href: string, label: string, color: string): string {\n return (\n `<a href=\"${href}\" target=\"_blank\" ` +\n `style=\"color:${color};text-decoration:underline;word-break:break-word;\">` +\n `${label}</a>`\n )\n}\n\n/**\n * Links the bare URLs in one escaped line.\n *\n * Balanced closing parens and brackets are kept, because a URL can genuinely\n * end in one and a wrapping \"(see https://…/a_(b))\" is the rarer case.\n * Anything the count says is unbalanced belongs to the prose.\n */\nexport function linkifyEscapedText(\n escaped: string,\n /** The link color: the sender's accent text shade, the platform's by default. */\n color = PLATFORM_EMAIL_ACCENT.link,\n): string {\n return escaped.replace(BARE_URL, (match) => {\n let url = match.replace(URL_TRAILING_PUNCTUATION, '')\n // `)` and `]` alike: a token's value dropped into \"[{{brand.supportUrl}}]\"\n // closes on a bracket the URL never opened.\n for (;;) {\n const close = url.slice(-1)\n const open = close === ')' ? '(' : close === ']' ? '[' : ''\n if (!open || url.split(close).length <= url.split(open).length) break\n url = url.slice(0, -1)\n }\n if (!url) return match\n return `${anchor(url, url, color)}${match.slice(url.length)}`\n })\n}\n\n"],"names":["PLATFORM_EMAIL_ACCENT","URL_TRAILING_PUNCTUATION","BARE_URL","anchor","href","label","color","linkifyEscapedText","escaped","link","replace","match","url","close","slice","open","split","length"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,SAASA,qBAAqB,QAAQ,qBAAiB;AAEvD;;;;;;;;;CASC,GAED;;;;;;;;;;;CAWC,GACD,MAAMC,2BAA2B;AAEjC;;;;;;;;;;;;CAYC,GACD,MAAMC,WAAW;AAEjB;;;;;;CAMC,GAED,SAASC,OAAOC,IAAY,EAAEC,KAAa,EAAEC,KAAa;IACxD,OACE,CAAC,SAAS,EAAEF,KAAK,kBAAkB,CAAC,GACpC,CAAC,aAAa,EAAEE,MAAM,mDAAmD,CAAC,GAC1E,GAAGD,MAAM,IAAI,CAAC;AAElB;AAEA;;;;;;CAMC,GACD,OAAO,SAASE,mBACdC,OAAe,EACf,+EAA+E,GAC/EF,QAAQN,sBAAsBS,IAAI;IAElC,OAAOD,QAAQE,OAAO,CAACR,UAAU,CAACS;QAChC,IAAIC,MAAMD,MAAMD,OAAO,CAACT,0BAA0B;QAClD,2EAA2E;QAC3E,4CAA4C;QAC5C,OAAS;YACP,MAAMY,QAAQD,IAAIE,KAAK,CAAC,CAAC;YACzB,MAAMC,OAAOF,UAAU,MAAM,MAAMA,UAAU,MAAM,MAAM;YACzD,IAAI,CAACE,QAAQH,IAAII,KAAK,CAACH,OAAOI,MAAM,IAAIL,IAAII,KAAK,CAACD,MAAME,MAAM,EAAE;YAChEL,MAAMA,IAAIE,KAAK,CAAC,GAAG,CAAC;QACtB;QACA,IAAI,CAACF,KAAK,OAAOD;QACjB,OAAO,GAAGR,OAAOS,KAAKA,KAAKN,SAASK,MAAMG,KAAK,CAACF,IAAIK,MAAM,GAAG;IAC/D;AACF"}
@@ -81,7 +81,7 @@ function setting(env, name) {
81
81
  });
82
82
  }
83
83
  /** One message as Resend's send endpoint takes it. */ export function resendSendPayload(message) {
84
- var _message_tags, _message_bcc;
84
+ var _message_tags, _message_bcc, _message_attachments;
85
85
  return _extends({
86
86
  from: message.from,
87
87
  to: message.to,
@@ -98,6 +98,12 @@ function setting(env, name) {
98
98
  reply_to: message.replyTo
99
99
  } : {}, ((_message_bcc = message.bcc) == null ? void 0 : _message_bcc.length) ? {
100
100
  bcc: message.bcc
101
+ } : {}, ((_message_attachments = message.attachments) == null ? void 0 : _message_attachments.length) ? {
102
+ attachments: message.attachments.map((attachment)=>({
103
+ filename: attachment.filename,
104
+ content: attachment.content,
105
+ content_type: attachment.contentType
106
+ }))
101
107
  } : {});
102
108
  }
103
109
  /**