@aglyn/shared-util-email 1.0.0-beta.277 → 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 +3 -3
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/domain-emails.d.ts +2 -0
- package/src/lib/domain-emails.js +111 -5
- package/src/lib/domain-emails.js.map +1 -1
- package/src/lib/email-linkify.d.ts +1 -1
- package/src/lib/email-linkify.js +9 -17
- package/src/lib/email-linkify.js.map +1 -1
- package/src/lib/mail-provider-resend.js +7 -1
- package/src/lib/mail-provider-resend.js.map +1 -1
- package/src/lib/mail-provider-webhook.js +3 -1
- package/src/lib/mail-provider-webhook.js.map +1 -1
- package/src/lib/mail-provider.d.ts +3 -1
- package/src/lib/mail-provider.js.map +1 -1
- package/src/lib/pos-hardware-emails.d.ts +23 -0
- package/src/lib/pos-hardware-emails.js +310 -0
- package/src/lib/pos-hardware-emails.js.map +1 -0
- package/src/lib/send-email.d.ts +31 -0
- package/src/lib/send-email.js +83 -3
- package/src/lib/send-email.js.map +1 -1
- package/src/lib/system-email-catalog.js +173 -13
- package/src/lib/system-email-catalog.js.map +1 -1
- package/src/lib/tenant-emails.generated.js +69 -0
- package/src/lib/tenant-emails.generated.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/shared-util-email",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
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.
|
|
29
|
-
"@aglyn/shared-util-http": "1.0.0-beta.
|
|
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[];
|
package/src/lib/domain-emails.js
CHANGED
|
@@ -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,
|
|
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: "
|
|
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
|
|
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
|
|
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":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;2CAe2C,GAO3C,OAAO,MAAMA,oBAAoB;IAC/BC,WAAW;IACXC,UAAU;IACVC,kBAAkB;IAClBC,eAAe;IACfC,SAAS;IACTC,eAAe;IACfC,UAAU;IACVC,SAAS;IACTC,cAAc;IACdC,qBAAqB;IACrBC,kBAAkB;AACpB,EAAU;AAEV,MAAMC,SAAS;AAEf,SAASC,OAAOC,MAAc;IAC5B,OAAO;QACLC,QAAQ;YAAEC,MAAM;YAAeC,aAAa;YAAmBC,QAAQ;QAAiB;QACxFC,MAAM;YAAEH,MAAM;YAAaC,aAAa;YAAkCC,QAAQ;QAAc;QAChGE,KAAK;YAAEJ,MAAM;YAAYC,aAAa;YAAiBC,QAAQ;QAAW;QAC1EG,WAAW;YACTL,MAAM;YACNC,aACE;YACFC,QAAQ,GAAGJ,OAAO,wCAAwC,CAAC;QAC7D;QACAQ,YAAY;YACVN,MAAM;YACNC,aAAa;YACbC,QAAQ,GAAGJ,OAAO,iBAAiB,CAAC;QACtC;QACAS,WAAW;YACTP,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAM,cAAc;YAAER,MAAM;YAAuBC,aAAa;YAA4BC,QAAQ;QAAS;QACvGO,UAAU;YAAET,MAAM;YAAmBC,aAAa;YAA8BC,QAAQ;QAAe;QACvGQ,UAAU;YACRV,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAS,WAAW;YAAEX,MAAM;YAAoBC,aAAa;YAA+BC,QAAQ;QAAe;QAC1GU,YAAY;YACVZ,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAW,iBAAiB;YACfb,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAY,UAAU;YACRd,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAa,QAAQ;YAAEf,MAAM;YAAiBC,aAAa;YAAqBC,QAAQ;QAAS;QACpFc,QAAQ;YACNhB,MAAM;YACNC,aAAa;YACbC,QACE;QACJ;QACAe,SAAS;YACPjB,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAgB,aAAa;YACXlB,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAiB,cAAc;YACZnB,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;QACAkB,WAAW;YACTpB,MAAM;YACNC,aACE;YACFC,QACE;QACJ;QACAmB,aAAa;YACXrB,MAAM;YACNC,aAAa;YACbC,QAAQ;QACV;IACF;AACF;AAEA,OAAO,SAASoB,2BACdxB,MAAc;IAEd,MAAMyB,IAAI1B,OAAOC;IACjB,MAAM0B,SACJ,8DACA;IACF,OAAO;QACL;YACEC,KAAKzC,kBAAkBC,SAAS;YAChCe,MAAM;YACNC,aACE,0EACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBACXL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEhB,SAAS;gBAAEgB,EAAEf,YAAY;gBAAEe,EAAEd,QAAQ;gBAChEc,EAAEX,UAAU;gBAAEW,EAAEV,eAAe;gBAAEU,EAAEH,SAAS;gBAAEG,EAAElB,SAAS;aAC1D;YACDwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA4BC,SAAS;gBAAU;gBACtE;oBAAEF,OAAO;oBAAQC,MAAM;oBAA8DC,SAAS;gBAAO;gBACrG;oBAAEF,OAAO;oBAAQC,MAAM;oBAAmKC,SAAS;gBAAU;gBAC7M;oBAAEF,OAAO;oBAAQC,MAAM;oBAA2BC,SAAS;gBAAa;gBACxE;oBAAEF,OAAO;oBAAQC,MAAM;oBAAkPC,SAAS;gBAAO;gBACzR;oBAAEF,OAAO;oBAAUG,OAAO;oBAAsBC,MAAM;gBAAuB;gBAC7E;oBAAEJ,OAAO;oBAAQC,MAAM;oBAAmIC,SAAS;gBAAU;aAC9K;YACDG,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBE,QAAQ;YAC/Bc,MAAM;YACNC,aACE,uEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEN,OAAO;gBAAEM,EAAEP,MAAM;gBAAEO,EAAElB,SAAS;aAAC;YACxEwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAwCC,SAAS;gBAAU;gBAClF;oBAAEF,OAAO;oBAAQC,MAAM;oBAAsBC,SAAS;gBAAO;gBAC7D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqBC,SAAS;gBAAO;gBAC5D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA+EC,SAAS;gBAAO;gBACtH;oBAAEF,OAAO;oBAAUG,OAAO;oBAAuBC,MAAM;gBAAuB;aAC/E;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBG,gBAAgB;YACvCa,MAAM;YACNC,aACE,0EACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEV,eAAe;gBAAEU,EAAET,QAAQ;gBAAES,EAAElB,SAAS;aAAC;YAClFwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAmBC,SAAS;gBAAU;gBAC7D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA8CC,SAAS;gBAAU;gBACxF;oBAAEF,OAAO;oBAAQC,MAAM;oBAAkSC,SAAS;gBAAO;gBACzU;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqLC,SAAS;gBAAO;gBAC5N;oBAAEF,OAAO;oBAAUG,OAAO;oBAA+BC,MAAM;gBAAuB;aACvF;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBI,aAAa;YACpCY,MAAM;YACNC,aACE,wEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEf,YAAY;gBAAEe,EAAEd,QAAQ;gBAAEc,EAAEb,QAAQ;gBAAEa,EAAElB,SAAS;aAAC;YAC3FwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAiDC,SAAS;gBAAU;gBAC3F;oBAAEF,OAAO;oBAAQC,MAAM;oBAAuHC,SAAS;gBAAO;gBAC9J;oBAAEF,OAAO;oBAAQC,MAAM;oBAAwIC,SAAS;gBAAU;gBAClL;oBAAEF,OAAO;oBAAQC,MAAM;oBAAwLC,SAAS;gBAAO;gBAC/N;oBAAEF,OAAO;oBAAUG,OAAO;oBAAqBC,MAAM;gBAAuB;aAC7E;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBK,OAAO;YAC9BW,MAAM;YACNC,aAAa;YACbyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAER,MAAM;gBAAEQ,EAAEZ,SAAS;gBAAEY,EAAElB,SAAS;aAAC;YAC1EwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA8BC,SAAS;gBAAU;gBACxE;oBAAEF,OAAO;oBAAQC,MAAM;oBAAiFC,SAAS;gBAAO;gBACxH;oBAAEF,OAAO;oBAAQC,MAAM;oBAAsEC,SAAS;gBAAU;gBAChH;oBAAEF,OAAO;oBAAUG,OAAO;oBAAsBC,MAAM;gBAAuB;gBAC7E;oBAAEJ,OAAO;oBAAQC,MAAM;oBAAgEC,SAAS;gBAAU;aAC3G;YACDG,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBM,aAAa;YACpCU,MAAM;YACNC,aACE,wEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEf,YAAY;gBAAEe,EAAEL,WAAW;gBAAEK,EAAEZ,SAAS;gBAAEY,EAAEjB,UAAU;gBAAEiB,EAAElB,SAAS;aAAC;YAC7GwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqCC,SAAS;gBAAU;gBAC/E;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqGC,SAAS;gBAAO;gBAC5I;oBAAEF,OAAO;oBAAQC,MAAM;oBAAkFC,SAAS;gBAAU;gBAC5H;oBAAEF,OAAO;oBAAQC,MAAM;oBAAgNC,SAAS;gBAAO;gBACvP;oBAAEF,OAAO;oBAAUG,OAAO;oBAAyBC,MAAM;gBAAiB;gBAC1E;oBAAEJ,OAAO;oBAAQC,MAAM;oBAAmCC,SAAS;gBAAU;aAC9E;YACDG,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBO,QAAQ;YAC/BS,MAAM;YACNC,aACE,oEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEZ,SAAS;gBAAEY,EAAEJ,YAAY;gBAAEI,EAAElB,SAAS;aAAC;YAChFwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAmDC,SAAS;gBAAU;gBAC7F;oBAAEF,OAAO;oBAAQC,MAAM;oBAAgKC,SAAS;gBAAO;gBACvM;oBAAEF,OAAO;oBAAQC,MAAM;oBAA+EC,SAAS;gBAAO;gBACtH;oBAAEF,OAAO;oBAAUG,OAAO;oBAAwBC,MAAM;gBAAuB;aAChF;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBQ,OAAO;YAC9BQ,MAAM;YACNC,aAAa;YACbyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAElB,SAAS;aAAC;YACnDwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAiBC,SAAS;gBAAU;gBAC3D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA+BC,SAAS;gBAAU;gBACzE;oBAAEF,OAAO;oBAAQC,MAAM;oBAA8IC,SAAS;gBAAO;gBACrL;oBAAEF,OAAO;oBAAQC,MAAM;oBAA2IC,SAAS;gBAAO;gBAClL;oBAAEF,OAAO;oBAAUG,OAAO;oBAA+BC,MAAM;gBAAuB;aACvF;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBS,YAAY;YACnCO,MAAM;YACNC,aACE,2EACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEpB,IAAI;gBAAEoB,EAAEnB,GAAG;gBAAEmB,EAAEF,WAAW;gBAAEE,EAAElB,SAAS;aAAC;YAClEwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAA8BC,SAAS;gBAAU;gBACxE;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqDC,SAAS;gBAAU;gBAC/F;oBAAEF,OAAO;oBAAQC,MAAM;oBAAyIC,SAAS;gBAAO;gBAChL;oBAAEF,OAAO;oBAAQC,MAAM;oBAA0IC,SAAS;gBAAO;gBACjL;oBAAEF,OAAO;oBAAUG,OAAO;oBAA+BC,MAAM;gBAAuB;aACvF;YACDC,cAAcX;YACdY,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBU,mBAAmB;YAC1CM,MAAM;YACNC,aACE,wEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEnB,GAAG;gBAAEmB,EAAER,MAAM;gBAAEQ,EAAEZ,SAAS;gBAAEY,EAAEf,YAAY;gBAAEe,EAAElB,SAAS;aAAC;YAClFwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAgBC,SAAS;gBAAU;gBAC1D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAkCC,SAAS;gBAAU;gBAC5E;oBAAEF,OAAO;oBAAQC,MAAM;oBAA0KC,SAAS;gBAAO;gBACjN;oBAAEF,OAAO;oBAAQC,MAAM;oBAAkHC,SAAS;gBAAU;gBAC5J;oBAAEF,OAAO;oBAAQC,MAAM;oBAA2IC,SAAS;gBAAO;gBAClL;oBAAEF,OAAO;oBAAUG,OAAO;oBAAyBC,MAAM;gBAAuB;aACjF;YACDC,cACE,8DACA;YACFC,QAAQxC;QACV;QACA;YACE6B,KAAKzC,kBAAkBW,gBAAgB;YACvCK,MAAM;YACNC,aACE,qEACA;YACFyB,aAAa;YACbC,gBAAgB;YAChBC,aAAa;gBAACL,EAAExB,MAAM;gBAAEwB,EAAEnB,GAAG;gBAAEmB,EAAEN,OAAO;gBAAEM,EAAEP,MAAM;gBAAEO,EAAElB,SAAS;aAAC;YAChEwB,aAAa;gBACX;oBAAEC,OAAO;oBAAQC,MAAM;oBAAgBC,SAAS;gBAAU;gBAC1D;oBAAEF,OAAO;oBAAQC,MAAM;oBAA0CC,SAAS;gBAAU;gBACpF;oBAAEF,OAAO;oBAAQC,MAAM;oBAAsBC,SAAS;gBAAO;gBAC7D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAqBC,SAAS;gBAAO;gBAC5D;oBAAEF,OAAO;oBAAQC,MAAM;oBAAsMC,SAAS;gBAAO;gBAC7O;oBAAEF,OAAO;oBAAUG,OAAO;oBAAyBC,MAAM;gBAAuB;aACjF;YACDC,cACE,8DACA;YACFC,QAAQxC;QACV;KACD;AACH"}
|
package/src/lib/email-linkify.js
CHANGED
|
@@ -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
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
|
|
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
|
|
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(
|
|
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&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 `&` 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
|
|
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&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 `&` 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
|
/**
|