@company-semantics/contracts 27.14.0 → 28.0.0
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 +1 -1
- package/src/email/render/__tests__/__snapshots__/render-snapshot.test.ts.snap +134 -83
- package/src/email/render/auth-otp.ts +25 -43
- package/src/email/render/blocks.ts +183 -150
- package/src/email/render/chat-shared.ts +15 -42
- package/src/email/render/company-md-access-approved.ts +16 -40
- package/src/email/render/company-md-access-denied.ts +23 -39
- package/src/email/render/company-md-access-requested.ts +21 -41
- package/src/email/render/index.ts +12 -47
- package/src/email/render/org-invite.ts +9 -32
- package/src/email/render/ownership-transfer-completed.ts +19 -17
- package/src/email/render/ownership-transfer.ts +36 -21
- package/src/email/render/render-email.ts +110 -100
- package/src/email/render/security-alert.ts +27 -27
- package/src/email/render/share-granted.ts +25 -51
- package/src/email/render/unit-owner-granted.ts +24 -43
- package/src/email/render/base-text.ts +0 -26
|
@@ -1,56 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Company.md access-approved email (sent to the requester).
|
|
2
|
+
* Company.md access-approved email (sent to the requester).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import { baseTextLayout } from "./base-text";
|
|
8
7
|
import {
|
|
9
8
|
ACCESS_PHRASE,
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
type Block,
|
|
10
|
+
bold,
|
|
12
11
|
ctaBox,
|
|
13
12
|
footer,
|
|
14
13
|
greeting,
|
|
15
|
-
|
|
14
|
+
paragraph,
|
|
15
|
+
signature,
|
|
16
16
|
} from "./blocks";
|
|
17
17
|
import { COMPANY_NAME } from "./constants";
|
|
18
|
-
import { escapeHtml } from "./escape-html";
|
|
19
18
|
|
|
20
19
|
export type AccessApprovedPayload =
|
|
21
20
|
EmailPayloads["companyMd.access_request_approved"];
|
|
22
21
|
|
|
23
|
-
export function
|
|
24
|
-
payload: AccessApprovedPayload,
|
|
25
|
-
): string {
|
|
26
|
-
const { approverName, docTitle, accessLevel, docUrl } = payload;
|
|
27
|
-
|
|
28
|
-
const sections: string[] = [];
|
|
29
|
-
sections.push("Hi,");
|
|
30
|
-
sections.push("");
|
|
31
|
-
sections.push(
|
|
32
|
-
`${approverName} approved your request to access "${docTitle}" — you ${ACCESS_PHRASE[accessLevel]}.`,
|
|
33
|
-
);
|
|
34
|
-
sections.push("");
|
|
35
|
-
sections.push(asciiCtaBox("OPEN"));
|
|
36
|
-
sections.push("");
|
|
37
|
-
sections.push(docUrl);
|
|
38
|
-
sections.push("");
|
|
39
|
-
sections.push(`This notification was sent via ${COMPANY_NAME}.`);
|
|
40
|
-
|
|
41
|
-
return baseTextLayout(sections.join("\n"));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function renderAccessApprovedHtml(
|
|
45
|
-
payload: AccessApprovedPayload,
|
|
46
|
-
): string {
|
|
22
|
+
export function renderAccessApproved(payload: AccessApprovedPayload): Block[] {
|
|
47
23
|
const { approverName, docTitle, accessLevel, docUrl } = payload;
|
|
48
24
|
|
|
49
|
-
return
|
|
25
|
+
return [
|
|
50
26
|
greeting(),
|
|
51
|
-
paragraph(
|
|
52
|
-
|
|
53
|
-
|
|
27
|
+
paragraph([
|
|
28
|
+
bold(approverName),
|
|
29
|
+
" approved your request to access ",
|
|
30
|
+
bold(`"${docTitle}"`),
|
|
31
|
+
` — you ${ACCESS_PHRASE[accessLevel]}.`,
|
|
32
|
+
]),
|
|
54
33
|
ctaBox({
|
|
55
34
|
label: "OPEN",
|
|
56
35
|
href: docUrl,
|
|
@@ -58,10 +37,7 @@ export function renderAccessApprovedHtml(
|
|
|
58
37
|
fontSize: "16px",
|
|
59
38
|
maxWidth: "220px",
|
|
60
39
|
}),
|
|
61
|
-
footer(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"none",
|
|
65
|
-
),
|
|
66
|
-
]);
|
|
40
|
+
footer(`This notification was sent via ${COMPANY_NAME}.`),
|
|
41
|
+
signature(),
|
|
42
|
+
];
|
|
67
43
|
}
|
|
@@ -1,58 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Company.md access-denied email (sent to the requester). No CTA.
|
|
2
|
+
* Company.md access-denied email (sent to the requester). No CTA.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import { baseTextLayout } from "./base-text";
|
|
8
7
|
import {
|
|
9
|
-
|
|
8
|
+
type Block,
|
|
9
|
+
bold,
|
|
10
|
+
chatUser,
|
|
10
11
|
footer,
|
|
11
12
|
greeting,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
chatUserBoxText,
|
|
13
|
+
paragraph,
|
|
14
|
+
signature,
|
|
15
15
|
} from "./blocks";
|
|
16
16
|
import { COMPANY_NAME } from "./constants";
|
|
17
|
-
import { escapeHtml } from "./escape-html";
|
|
18
17
|
|
|
19
18
|
export type AccessDeniedPayload =
|
|
20
19
|
EmailPayloads["companyMd.access_request_denied"];
|
|
21
20
|
|
|
22
|
-
export function
|
|
21
|
+
export function renderAccessDenied(payload: AccessDeniedPayload): Block[] {
|
|
23
22
|
const { approverName, docTitle, reason } = payload;
|
|
24
23
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const blocks: Block[] = [
|
|
25
|
+
greeting(),
|
|
26
|
+
paragraph([
|
|
27
|
+
bold(approverName),
|
|
28
|
+
" declined your request to access ",
|
|
29
|
+
bold(`"${docTitle}"`),
|
|
30
|
+
".",
|
|
31
|
+
]),
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
if (reason) blocks.push(chatUser(reason, `Reason from ${approverName}`));
|
|
35
|
+
|
|
36
|
+
blocks.push(
|
|
37
|
+
footer(`This notification was sent via ${COMPANY_NAME}.`),
|
|
38
|
+
signature(),
|
|
30
39
|
);
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
sections.push("");
|
|
34
|
-
sections.push(chatUserBoxText(reason, `Reason from ${approverName}`));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
sections.push("");
|
|
38
|
-
sections.push(`This notification was sent via ${COMPANY_NAME}.`);
|
|
39
|
-
|
|
40
|
-
return baseTextLayout(sections.join("\n"));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function renderAccessDeniedHtml(payload: AccessDeniedPayload): string {
|
|
44
|
-
const { approverName, docTitle, reason } = payload;
|
|
45
|
-
|
|
46
|
-
return htmlShell([
|
|
47
|
-
greeting(),
|
|
48
|
-
paragraph(
|
|
49
|
-
`<b>${escapeHtml(approverName)}</b> declined your request to access <b>"${escapeHtml(docTitle)}"</b>.`,
|
|
50
|
-
),
|
|
51
|
-
reason ? chatUserBubble(reason, `Reason from ${approverName}`) : "",
|
|
52
|
-
footer(
|
|
53
|
-
`This notification was sent via ${COMPANY_NAME}.`,
|
|
54
|
-
undefined,
|
|
55
|
-
"none",
|
|
56
|
-
),
|
|
57
|
-
]);
|
|
41
|
+
return blocks;
|
|
58
42
|
}
|
|
@@ -1,66 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Company.md access-requested email (sent to the doc owner).
|
|
2
|
+
* Company.md access-requested email (sent to the doc owner).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import { baseTextLayout } from "./base-text";
|
|
8
7
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
type Block,
|
|
9
|
+
bold,
|
|
10
|
+
chatUser,
|
|
11
11
|
ctaBox,
|
|
12
12
|
footer,
|
|
13
13
|
greeting,
|
|
14
|
-
|
|
15
|
-
chatUserBubble,
|
|
16
|
-
chatUserBoxText,
|
|
14
|
+
paragraph,
|
|
17
15
|
signature,
|
|
18
16
|
} from "./blocks";
|
|
19
17
|
import { COMPANY_NAME } from "./constants";
|
|
20
|
-
import { escapeHtml } from "./escape-html";
|
|
21
18
|
|
|
22
19
|
export type AccessRequestedPayload =
|
|
23
20
|
EmailPayloads["companyMd.access_requested"];
|
|
24
21
|
|
|
25
22
|
const OWNER_NOTE = "You are receiving this because you own this document.";
|
|
26
23
|
|
|
27
|
-
export function
|
|
24
|
+
export function renderAccessRequested(
|
|
28
25
|
payload: AccessRequestedPayload,
|
|
29
|
-
):
|
|
26
|
+
): Block[] {
|
|
30
27
|
const { requesterName, docTitle, message, reviewUrl } = payload;
|
|
31
28
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
sections.push("");
|
|
43
|
-
sections.push(asciiCtaBox("REVIEW"));
|
|
44
|
-
sections.push("");
|
|
45
|
-
sections.push(reviewUrl);
|
|
46
|
-
sections.push("");
|
|
47
|
-
sections.push(`This notification was sent via ${COMPANY_NAME}.`);
|
|
48
|
-
sections.push(OWNER_NOTE);
|
|
49
|
-
|
|
50
|
-
return baseTextLayout(sections.join("\n"));
|
|
51
|
-
}
|
|
29
|
+
const blocks: Block[] = [
|
|
30
|
+
greeting(),
|
|
31
|
+
paragraph([
|
|
32
|
+
bold(requesterName),
|
|
33
|
+
" is requesting access to ",
|
|
34
|
+
bold(`"${docTitle}"`),
|
|
35
|
+
".",
|
|
36
|
+
]),
|
|
37
|
+
];
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
payload: AccessRequestedPayload,
|
|
55
|
-
): string {
|
|
56
|
-
const { requesterName, docTitle, message, reviewUrl } = payload;
|
|
39
|
+
if (message) blocks.push(chatUser(message, `Message from ${requesterName}`));
|
|
57
40
|
|
|
58
|
-
|
|
59
|
-
greeting(),
|
|
60
|
-
paragraph(
|
|
61
|
-
`<b>${escapeHtml(requesterName)}</b> is requesting access to <b>"${escapeHtml(docTitle)}"</b>.`,
|
|
62
|
-
),
|
|
63
|
-
message ? chatUserBubble(message, `Message from ${requesterName}`) : "",
|
|
41
|
+
blocks.push(
|
|
64
42
|
ctaBox({
|
|
65
43
|
label: "REVIEW",
|
|
66
44
|
href: reviewUrl,
|
|
@@ -70,5 +48,7 @@ export function renderAccessRequestedHtml(
|
|
|
70
48
|
}),
|
|
71
49
|
footer(`This notification was sent via ${COMPANY_NAME}.`, OWNER_NOTE),
|
|
72
50
|
signature(),
|
|
73
|
-
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return blocks;
|
|
74
54
|
}
|
|
@@ -10,13 +10,13 @@ export { COMPANY_NAME, SUPPORT_EMAIL, MONO_FONT_STACK } from "./constants";
|
|
|
10
10
|
|
|
11
11
|
// Primitives
|
|
12
12
|
export { escapeHtml } from "./escape-html";
|
|
13
|
-
export { baseTextLayout } from "./base-text";
|
|
14
13
|
|
|
15
|
-
//
|
|
14
|
+
// Dual-output building blocks (each returns a `Block` = { html, text })
|
|
16
15
|
export {
|
|
17
16
|
htmlShell,
|
|
18
|
-
|
|
17
|
+
textShell,
|
|
19
18
|
paragraph,
|
|
19
|
+
greeting,
|
|
20
20
|
keyValue,
|
|
21
21
|
footer,
|
|
22
22
|
signature,
|
|
@@ -24,14 +24,12 @@ export {
|
|
|
24
24
|
ACCESS_PHRASE,
|
|
25
25
|
chatDots,
|
|
26
26
|
ctaBox,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
chatAssistantBoxText,
|
|
34
|
-
clampMessage,
|
|
27
|
+
chatUser,
|
|
28
|
+
chatAssistant,
|
|
29
|
+
bold,
|
|
30
|
+
type Block,
|
|
31
|
+
type Inline,
|
|
32
|
+
type InlineContent,
|
|
35
33
|
type Spacing,
|
|
36
34
|
type CtaBoxOptions,
|
|
37
35
|
} from "./blocks";
|
|
@@ -45,39 +43,6 @@ export {
|
|
|
45
43
|
type RenderEmailOptions,
|
|
46
44
|
} from "./render-email";
|
|
47
45
|
|
|
48
|
-
//
|
|
49
|
-
export {
|
|
50
|
-
|
|
51
|
-
renderAuthOtpHtml,
|
|
52
|
-
type AuthOtpPayload,
|
|
53
|
-
type RenderOptions,
|
|
54
|
-
} from "./auth-otp";
|
|
55
|
-
export { renderOrgInviteBody, renderOrgInviteHtml } from "./org-invite";
|
|
56
|
-
export { renderChatSharedBody, renderChatSharedHtml } from "./chat-shared";
|
|
57
|
-
export {
|
|
58
|
-
renderSecurityAlertBody,
|
|
59
|
-
SECURITY_ALERT_TYPES,
|
|
60
|
-
type SecurityAlertType,
|
|
61
|
-
} from "./security-alert";
|
|
62
|
-
export {
|
|
63
|
-
renderUnitOwnerGrantedBody,
|
|
64
|
-
renderUnitOwnerGrantedHtml,
|
|
65
|
-
} from "./unit-owner-granted";
|
|
66
|
-
export {
|
|
67
|
-
renderShareGrantedBody,
|
|
68
|
-
renderShareGrantedHtml,
|
|
69
|
-
} from "./share-granted";
|
|
70
|
-
export { renderOwnershipTransferBody } from "./ownership-transfer";
|
|
71
|
-
export { renderOwnershipTransferCompletedBody } from "./ownership-transfer-completed";
|
|
72
|
-
export {
|
|
73
|
-
renderAccessRequestedBody,
|
|
74
|
-
renderAccessRequestedHtml,
|
|
75
|
-
} from "./company-md-access-requested";
|
|
76
|
-
export {
|
|
77
|
-
renderAccessApprovedBody,
|
|
78
|
-
renderAccessApprovedHtml,
|
|
79
|
-
} from "./company-md-access-approved";
|
|
80
|
-
export {
|
|
81
|
-
renderAccessDeniedBody,
|
|
82
|
-
renderAccessDeniedHtml,
|
|
83
|
-
} from "./company-md-access-denied";
|
|
46
|
+
// Template payload types + alert vocabulary
|
|
47
|
+
export type { AuthOtpPayload, RenderOptions } from "./auth-otp";
|
|
48
|
+
export { SECURITY_ALERT_TYPES, type SecurityAlertType } from "./security-alert";
|
|
@@ -1,49 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Org invite email (join a workspace).
|
|
2
|
+
* Org invite email (join a workspace).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import { baseTextLayout } from "./base-text";
|
|
8
7
|
import {
|
|
9
|
-
|
|
10
|
-
paragraph,
|
|
8
|
+
type Block,
|
|
11
9
|
ctaBox,
|
|
12
10
|
footer,
|
|
13
|
-
htmlShell,
|
|
14
11
|
keyValue,
|
|
15
12
|
NOTICE,
|
|
13
|
+
paragraph,
|
|
16
14
|
signature,
|
|
17
15
|
} from "./blocks";
|
|
18
16
|
import { COMPANY_NAME } from "./constants";
|
|
19
|
-
import { escapeHtml } from "./escape-html";
|
|
20
17
|
|
|
21
18
|
export type OrgInvitePayload = EmailPayloads["org.invite"];
|
|
22
19
|
|
|
23
|
-
export function
|
|
24
|
-
const { inviterName, orgName, role, acceptUrl, expiresInDays } = payload;
|
|
25
|
-
|
|
26
|
-
const sections: string[] = [];
|
|
27
|
-
sections.push("Workspace invitation.");
|
|
28
|
-
sections.push(asciiCtaBox("JOIN"));
|
|
29
|
-
sections.push("");
|
|
30
|
-
sections.push(acceptUrl);
|
|
31
|
-
sections.push("");
|
|
32
|
-
sections.push(`From: ${inviterName}`);
|
|
33
|
-
sections.push(`Workspace: ${orgName}`);
|
|
34
|
-
sections.push(`Role: ${role}`);
|
|
35
|
-
sections.push(`Expires in: ${expiresInDays} days`);
|
|
36
|
-
sections.push("");
|
|
37
|
-
sections.push(`This invitation was sent via ${COMPANY_NAME}.`);
|
|
38
|
-
sections.push(NOTICE);
|
|
39
|
-
|
|
40
|
-
return baseTextLayout(sections.join("\n"));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function renderOrgInviteHtml(payload: OrgInvitePayload): string {
|
|
20
|
+
export function renderOrgInvite(payload: OrgInvitePayload): Block[] {
|
|
44
21
|
const { inviterName, orgName, role, acceptUrl, expiresInDays } = payload;
|
|
45
22
|
|
|
46
|
-
return
|
|
23
|
+
return [
|
|
47
24
|
paragraph("Workspace invitation."),
|
|
48
25
|
ctaBox({
|
|
49
26
|
label: "JOIN",
|
|
@@ -51,11 +28,11 @@ export function renderOrgInviteHtml(payload: OrgInvitePayload): string {
|
|
|
51
28
|
padding: "20px 24px",
|
|
52
29
|
fontSize: "16px",
|
|
53
30
|
}),
|
|
54
|
-
keyValue("From",
|
|
55
|
-
keyValue("Workspace",
|
|
56
|
-
keyValue("Role", role
|
|
31
|
+
keyValue("From", inviterName),
|
|
32
|
+
keyValue("Workspace", orgName),
|
|
33
|
+
keyValue("Role", role),
|
|
57
34
|
keyValue("Expires in", `${expiresInDays} days`, "normal"),
|
|
58
35
|
footer(`This invitation was sent via ${COMPANY_NAME}.`, NOTICE),
|
|
59
36
|
signature(),
|
|
60
|
-
]
|
|
37
|
+
];
|
|
61
38
|
}
|
|
@@ -4,28 +4,30 @@
|
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { type Block, bold, footer, paragraph, signature } from "./blocks";
|
|
8
8
|
|
|
9
9
|
export type OwnershipTransferCompletedPayload =
|
|
10
10
|
EmailPayloads["org.ownership_transfer_completed"];
|
|
11
11
|
|
|
12
|
-
export function
|
|
12
|
+
export function renderOwnershipTransferCompleted(
|
|
13
13
|
payload: OwnershipTransferCompletedPayload,
|
|
14
|
-
):
|
|
14
|
+
): Block[] {
|
|
15
15
|
const { orgName, newOwnerEmail } = payload;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
return [
|
|
18
|
+
paragraph([
|
|
19
|
+
"The ownership of ",
|
|
20
|
+
bold(`"${orgName}"`),
|
|
21
|
+
" has been transferred to ",
|
|
22
|
+
bold(newOwnerEmail),
|
|
23
|
+
".",
|
|
24
|
+
]),
|
|
25
|
+
paragraph(
|
|
26
|
+
"You are no longer the owner of this workspace, but you remain an admin.",
|
|
27
|
+
),
|
|
28
|
+
footer(
|
|
29
|
+
"If you did not authorize this transfer, please contact support immediately.",
|
|
30
|
+
),
|
|
31
|
+
signature(),
|
|
32
|
+
];
|
|
31
33
|
}
|
|
@@ -4,33 +4,48 @@
|
|
|
4
4
|
|
|
5
5
|
import type { EmailPayloads } from "../types";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
type Block,
|
|
9
|
+
bold,
|
|
10
|
+
chatUser,
|
|
11
|
+
ctaBox,
|
|
12
|
+
footer,
|
|
13
|
+
keyValue,
|
|
14
|
+
paragraph,
|
|
15
|
+
signature,
|
|
16
|
+
} from "./blocks";
|
|
9
17
|
|
|
10
18
|
export type OwnershipTransferPayload = EmailPayloads["org.ownership_transfer"];
|
|
11
19
|
|
|
12
|
-
export function
|
|
20
|
+
export function renderOwnershipTransfer(
|
|
13
21
|
payload: OwnershipTransferPayload,
|
|
14
|
-
):
|
|
22
|
+
): Block[] {
|
|
15
23
|
const { orgName, acceptUrl, expiresInDays, note } = payload;
|
|
16
24
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
const blocks: Block[] = [
|
|
26
|
+
paragraph([
|
|
27
|
+
"You have been invited to become the owner of ",
|
|
28
|
+
bold(`"${orgName}"`),
|
|
29
|
+
".",
|
|
30
|
+
]),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
if (note) blocks.push(chatUser(note, "Message from the current owner"));
|
|
34
|
+
|
|
35
|
+
blocks.push(
|
|
36
|
+
ctaBox({
|
|
37
|
+
label: "ACCEPT",
|
|
38
|
+
href: acceptUrl,
|
|
39
|
+
padding: "16px 24px",
|
|
40
|
+
fontSize: "16px",
|
|
41
|
+
maxWidth: "220px",
|
|
42
|
+
}),
|
|
43
|
+
keyValue("Expires in", `${expiresInDays} days`, "normal"),
|
|
44
|
+
footer(
|
|
45
|
+
"If you did not expect this invitation, you can safely ignore this email.",
|
|
46
|
+
),
|
|
47
|
+
signature(),
|
|
33
48
|
);
|
|
34
49
|
|
|
35
|
-
return
|
|
50
|
+
return blocks;
|
|
36
51
|
}
|