@resq-systems/email-templates 0.6.0 → 0.6.2
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/lib/contract.d.ts +56 -43
- package/lib/contract.d.ts.map +1 -1
- package/lib/contract.js +12 -1
- package/lib/contract.js.map +1 -1
- package/lib/emails/incident-alert.d.ts +1 -0
- package/lib/emails/incident-alert.d.ts.map +1 -1
- package/lib/emails/incident-alert.js.map +1 -1
- package/lib/emails/index.d.ts +1 -1
- package/lib/emails/mission-approval.d.ts +1 -0
- package/lib/emails/mission-approval.d.ts.map +1 -1
- package/lib/emails/mission-approval.js.map +1 -1
- package/lib/emails/new-device-login.d.ts +1 -0
- package/lib/emails/new-device-login.d.ts.map +1 -1
- package/lib/emails/new-device-login.js.map +1 -1
- package/lib/emails/notification.d.ts +1 -0
- package/lib/emails/notification.d.ts.map +1 -1
- package/lib/emails/notification.js.map +1 -1
- package/lib/emails/org-invitation.d.ts +1 -0
- package/lib/emails/org-invitation.d.ts.map +1 -1
- package/lib/emails/org-invitation.js.map +1 -1
- package/lib/emails/otp.d.ts +1 -0
- package/lib/emails/otp.d.ts.map +1 -1
- package/lib/emails/otp.js.map +1 -1
- package/lib/emails/password-changed.d.ts +1 -0
- package/lib/emails/password-changed.d.ts.map +1 -1
- package/lib/emails/password-changed.js.map +1 -1
- package/lib/emails/password-reset.d.ts +1 -0
- package/lib/emails/password-reset.d.ts.map +1 -1
- package/lib/emails/password-reset.js.map +1 -1
- package/lib/emails/primitives.d.ts.map +1 -1
- package/lib/emails/primitives.js +7 -0
- package/lib/emails/primitives.js.map +1 -1
- package/lib/emails/theme.d.ts +86 -8
- package/lib/emails/theme.d.ts.map +1 -1
- package/lib/emails/theme.js +51 -3
- package/lib/emails/theme.js.map +1 -1
- package/lib/emails/tokens.d.ts +2 -1
- package/lib/emails/tokens.d.ts.map +1 -1
- package/lib/emails/tokens.js +7 -0
- package/lib/emails/tokens.js.map +1 -1
- package/lib/emails/welcome.d.ts +1 -0
- package/lib/emails/welcome.d.ts.map +1 -1
- package/lib/emails/welcome.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/mailer.d.ts +118 -11
- package/lib/mailer.d.ts.map +1 -1
- package/lib/mailer.js +48 -2
- package/lib/mailer.js.map +1 -1
- package/lib/node_modules/@react-email/tailwind/dist/index.d.ts +1 -1
- package/lib/node_modules/{tailwindcss → @react-email/tailwind/node_modules/tailwindcss}/dist/colors.d.ts +1 -1
- package/lib/node_modules/@react-email/tailwind/node_modules/tailwindcss/dist/colors.d.ts.map +1 -0
- package/lib/node_modules/{tailwindcss → @react-email/tailwind/node_modules/tailwindcss}/dist/lib.d.ts +1 -1
- package/lib/node_modules/@react-email/tailwind/node_modules/tailwindcss/dist/lib.d.ts.map +1 -0
- package/lib/node_modules/{tailwindcss → @react-email/tailwind/node_modules/tailwindcss}/dist/resolve-config-QUZ9b-Gn.d.ts +1 -1
- package/lib/node_modules/@react-email/tailwind/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts.map +1 -0
- package/lib/node_modules/{tailwindcss → @react-email/tailwind/node_modules/tailwindcss}/dist/types-DWdTiksJ.d.ts +1 -1
- package/lib/node_modules/@react-email/tailwind/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts.map +1 -0
- package/lib/registry.d.ts.map +1 -1
- package/lib/registry.js +6 -0
- package/lib/registry.js.map +1 -1
- package/lib/render.d.ts +9 -2
- package/lib/render.d.ts.map +1 -1
- package/lib/render.js +16 -2
- package/lib/render.js.map +1 -1
- package/lib/schemas.d.ts +9 -0
- package/lib/schemas.d.ts.map +1 -1
- package/lib/schemas.js +16 -0
- package/lib/schemas.js.map +1 -1
- package/lib/send/index.d.ts +1 -1
- package/lib/send/resend-sender.d.ts +11 -0
- package/lib/send/resend-sender.d.ts.map +1 -1
- package/lib/send/resend-sender.js +17 -0
- package/lib/send/resend-sender.js.map +1 -1
- package/lib/send/send-email.d.ts +21 -0
- package/lib/send/send-email.d.ts.map +1 -1
- package/lib/send/send-email.js +26 -0
- package/lib/send/send-email.js.map +1 -1
- package/lib/send/sender.d.ts +26 -2
- package/lib/send/sender.d.ts.map +1 -1
- package/lib/suite.d.ts.map +1 -1
- package/lib/suite.js +7 -0
- package/lib/suite.js.map +1 -1
- package/lib/templates.d.ts +9 -0
- package/lib/templates.d.ts.map +1 -1
- package/lib/templates.js +16 -0
- package/lib/templates.js.map +1 -1
- package/package.json +7 -7
- package/lib/node_modules/tailwindcss/dist/colors.d.ts.map +0 -1
- package/lib/node_modules/tailwindcss/dist/lib.d.ts.map +0 -1
- package/lib/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts.map +0 -1
- package/lib/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts.map +0 -1
package/lib/emails/theme.d.ts
CHANGED
|
@@ -2,21 +2,45 @@ import { EmailCategory } from "../schemas.js";
|
|
|
2
2
|
import { TailwindConfig } from "../node_modules/@react-email/tailwind/dist/index.js";
|
|
3
3
|
import { ReactElement } from "react";
|
|
4
4
|
//#region src/emails/theme.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Font stacks the theme exposes to Tailwind's `fontFamily` extension. Each array
|
|
7
|
+
* is a CSS font-family stack in priority order (preferred face first, generic
|
|
8
|
+
* fallback last); multi-word names are pre-quoted so they drop straight into a
|
|
9
|
+
* `font-family` value.
|
|
10
|
+
*/
|
|
5
11
|
interface EmailThemeFonts {
|
|
12
|
+
/** Stack for display/heading text. */
|
|
6
13
|
display: string[];
|
|
14
|
+
/** Stack for body/sans text. */
|
|
7
15
|
sans: string[];
|
|
16
|
+
/** Stack for monospace text (codes, metadata). */
|
|
8
17
|
mono: string[];
|
|
9
18
|
}
|
|
10
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Organization identity rendered into email chrome (header, signature, footer).
|
|
21
|
+
*
|
|
22
|
+
* All `*Url` fields are absolute URLs. {@link EmailOrgIdentity.registeredAddress}
|
|
23
|
+
* leads with the legal entity name, so it stands alone as a complete CAN-SPAM
|
|
24
|
+
* postal line without a separate `legalName` line in the footer.
|
|
25
|
+
*/
|
|
11
26
|
interface EmailOrgIdentity {
|
|
27
|
+
/** Short brand name used in sign-offs, e.g. "— The {brandName} team". */
|
|
12
28
|
brandName: string;
|
|
29
|
+
/** Product name shown in the header lockup beside the logo. */
|
|
13
30
|
productName: string;
|
|
31
|
+
/** Full legal entity name. */
|
|
14
32
|
legalName: string;
|
|
33
|
+
/** Registered postal address, prefixed with the legal name; a complete CAN-SPAM line. */
|
|
15
34
|
registeredAddress: string;
|
|
35
|
+
/** Support inbox address, rendered as a `mailto:` link. */
|
|
16
36
|
supportEmail: string;
|
|
37
|
+
/** Marketing/website URL (absolute). Never used as an unsubscribe target. */
|
|
17
38
|
websiteUrl: string;
|
|
39
|
+
/** Absolute URL of the Terms page. */
|
|
18
40
|
termsUrl: string;
|
|
41
|
+
/** Absolute URL of the Privacy page. */
|
|
19
42
|
privacyUrl: string;
|
|
43
|
+
/** Absolute URL of the header logo image. */
|
|
20
44
|
logoUrl: string;
|
|
21
45
|
}
|
|
22
46
|
/** The full, resolved theme every template renders against. */
|
|
@@ -30,22 +54,58 @@ interface EmailTheme {
|
|
|
30
54
|
/** Optional stylesheet `<link>` injected in `<Head>` for brand webfonts. */
|
|
31
55
|
fontsHref?: string;
|
|
32
56
|
}
|
|
33
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* A partial theme a consumer supplies to rebrand; unset keys fall back to the
|
|
59
|
+
* base. All object fields are **shallow**-merged over the base one level deep (see
|
|
60
|
+
* {@link resolveEmailTheme}), so supplying `colors` replaces only the named color
|
|
61
|
+
* tokens, not the whole palette.
|
|
62
|
+
*/
|
|
34
63
|
interface EmailThemeOverride {
|
|
64
|
+
/** Color tokens to override (email-safe hex); merged over the base palette. */
|
|
35
65
|
colors?: Record<string, string>;
|
|
66
|
+
/** Font stacks to override; unspecified stacks keep the base. */
|
|
36
67
|
fonts?: Partial<EmailThemeFonts>;
|
|
37
68
|
/** Override organization identity fields (shallow-merged over the base). */
|
|
38
69
|
org?: Partial<EmailOrgIdentity>;
|
|
39
|
-
/**
|
|
70
|
+
/** Replace the webfont `<link>` href, or pass `null` to drop it entirely. */
|
|
40
71
|
fontsHref?: string | null;
|
|
41
72
|
}
|
|
42
73
|
/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */
|
|
43
74
|
declare const defaultEmailTheme: EmailTheme;
|
|
44
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Merge an override onto a base theme, producing a new resolved theme.
|
|
77
|
+
*
|
|
78
|
+
* Pure — never mutates `base`. `colors`, `fonts`, and `org` are **shallow**-merged
|
|
79
|
+
* (override keys replace base keys one level deep), so a partial `fonts` override
|
|
80
|
+
* keeps the base's other stacks. `fontsHref` follows a three-way rule: `null`
|
|
81
|
+
* drops the webfont link entirely, absent/`undefined` keeps the base href, and any
|
|
82
|
+
* string replaces it.
|
|
83
|
+
*
|
|
84
|
+
* @param base - The theme to start from.
|
|
85
|
+
* @param override - Fields to overlay; when omitted, `base` is returned by reference.
|
|
86
|
+
* @returns The merged theme, or `base` itself when there is no override.
|
|
87
|
+
*/
|
|
45
88
|
declare function resolveEmailTheme(base: EmailTheme, override?: EmailThemeOverride): EmailTheme;
|
|
46
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* Merge an override onto the default ResQ Systems theme.
|
|
91
|
+
*
|
|
92
|
+
* Pure convenience wrapper over {@link resolveEmailTheme} with
|
|
93
|
+
* {@link defaultEmailTheme} as the base.
|
|
94
|
+
*
|
|
95
|
+
* @param override - Fields to overlay on the default theme.
|
|
96
|
+
* @returns The resolved theme.
|
|
97
|
+
*/
|
|
47
98
|
declare function mergeEmailTheme(override?: EmailThemeOverride): EmailTheme;
|
|
48
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Build the `<Tailwind config>` object from a resolved theme.
|
|
101
|
+
*
|
|
102
|
+
* Pure — projects the theme's colors and font stacks into a Tailwind
|
|
103
|
+
* `theme.extend` config atop the pixel-based preset (email clients need px units,
|
|
104
|
+
* not rem).
|
|
105
|
+
*
|
|
106
|
+
* @param theme - The resolved theme to project.
|
|
107
|
+
* @returns The config object to pass to react-email's `<Tailwind>`.
|
|
108
|
+
*/
|
|
49
109
|
declare function buildTailwindConfig(theme: EmailTheme): {
|
|
50
110
|
presets: TailwindConfig[];
|
|
51
111
|
theme: {
|
|
@@ -67,13 +127,25 @@ declare const EmailThemeContext: import("react").Context<EmailTheme>;
|
|
|
67
127
|
* Wrap an element so it renders against a theme override (used by `renderEmail`).
|
|
68
128
|
* Returns the element unchanged when there is no override, so the default theme
|
|
69
129
|
* flows through context.
|
|
130
|
+
*
|
|
131
|
+
* Pure — builds a new provider element and does not mutate `element`.
|
|
132
|
+
*
|
|
133
|
+
* @param element - The email element tree to wrap.
|
|
134
|
+
* @param override - Theme fields to overlay; when omitted, `element` is returned unchanged.
|
|
135
|
+
* @returns `element`, wrapped in an {@link EmailThemeContext} provider when an override is given.
|
|
70
136
|
*/
|
|
71
137
|
declare function withEmailTheme(element: ReactElement, override?: EmailThemeOverride): ReactElement;
|
|
72
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Per-send message policy carried through context to the legal footer.
|
|
140
|
+
*
|
|
141
|
+
* The unsubscribe affordance renders only when {@link EmailMessage.category} is
|
|
142
|
+
* `"marketing"` **and** {@link EmailMessage.unsubscribeUrl} is set; a marketing
|
|
143
|
+
* send with no `unsubscribeUrl` simply omits it (there is no homepage fallback).
|
|
144
|
+
*/
|
|
73
145
|
interface EmailMessage {
|
|
74
146
|
/** Compliance class; defaults to `transactional`. */
|
|
75
147
|
category: EmailCategory;
|
|
76
|
-
/**
|
|
148
|
+
/** Absolute unsubscribe/preferences URL; only consulted for `marketing` sends. */
|
|
77
149
|
unsubscribeUrl?: string;
|
|
78
150
|
}
|
|
79
151
|
/** Context carrying the active message policy; defaults to a transactional send. */
|
|
@@ -82,6 +154,12 @@ declare const EmailMessageContext: import("react").Context<EmailMessage>;
|
|
|
82
154
|
* Wrap an element so it renders against a message policy (used by `renderEmail`).
|
|
83
155
|
* Returns the element unchanged when no message is given, so the default
|
|
84
156
|
* transactional policy flows through context.
|
|
157
|
+
*
|
|
158
|
+
* Pure — builds a new provider element and does not mutate `element`.
|
|
159
|
+
*
|
|
160
|
+
* @param element - The email element tree to wrap.
|
|
161
|
+
* @param message - The per-send policy; when omitted, `element` is returned unchanged.
|
|
162
|
+
* @returns `element`, wrapped in an {@link EmailMessageContext} provider when a message is given.
|
|
85
163
|
*/
|
|
86
164
|
declare function withEmailMessage(element: ReactElement, message?: EmailMessage): ReactElement;
|
|
87
165
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","names":[],"sources":["../../src/emails/theme.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme.d.ts","names":[],"sources":["../../src/emails/theme.tsx"],"mappings":";;;;;;;;;;UAqCiB;;EAEhB;;EAEA;;EAEA;;;;;;;;;UAUgB;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;UAIgB;;EAEhB,QAAQ;;EAER,OAAO;;EAEP,KAAK;;EAEL;;;;;;;;UASgB;;EAEhB,SAAS;;EAET,QAAQ,QAAQ;;EAEhB,MAAM,QAAQ;;EAEd;;;cAQY,mBAAmB;;;;;;;;;;;;;;iBAwBhB,kBAAkB,MAAM,YAAY,WAAW,qBAAqB;;;;;;;;;;iBAmBpE,gBAAgB,WAAW,qBAAqB;;;;;;;;;;;iBAchD,oBAAoB,OAAO;WAAA;;;;;;;QAOtC;QACA;QACA;;;;;;cAQQ,mCAAiB,QAAA;;;;;;;;;;;;iBAad,eAAe,SAAS,cAAc,WAAW,qBAAqB;;;;;;;;UAYrE;;EAEhB,UAAU;;EAEV;;;cAIY,qCAAmB,QAAA;;;;;;;;;;;;iBAahB,iBAAiB,SAAS,cAAc,UAAU,eAAe"}
|
package/lib/emails/theme.js
CHANGED
|
@@ -17,6 +17,13 @@ import { createContext, createElement } from "react";
|
|
|
17
17
|
* See the License for the specific language governing permissions and
|
|
18
18
|
* limitations under the License.
|
|
19
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* @fileoverview Email theming system — the resolved `EmailTheme` shape, override
|
|
22
|
+
* merging, the Tailwind config builder, and React contexts carrying the active theme
|
|
23
|
+
* and per-send message policy.
|
|
24
|
+
*
|
|
25
|
+
* @module @resq-systems/email-templates/emails/theme
|
|
26
|
+
*/
|
|
20
27
|
/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */
|
|
21
28
|
const defaultEmailTheme = {
|
|
22
29
|
colors: { ...emailColors },
|
|
@@ -28,7 +35,19 @@ const defaultEmailTheme = {
|
|
|
28
35
|
org: { ...emailOrg },
|
|
29
36
|
fontsHref: emailFonts.googleFontsHref
|
|
30
37
|
};
|
|
31
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Merge an override onto a base theme, producing a new resolved theme.
|
|
40
|
+
*
|
|
41
|
+
* Pure — never mutates `base`. `colors`, `fonts`, and `org` are **shallow**-merged
|
|
42
|
+
* (override keys replace base keys one level deep), so a partial `fonts` override
|
|
43
|
+
* keeps the base's other stacks. `fontsHref` follows a three-way rule: `null`
|
|
44
|
+
* drops the webfont link entirely, absent/`undefined` keeps the base href, and any
|
|
45
|
+
* string replaces it.
|
|
46
|
+
*
|
|
47
|
+
* @param base - The theme to start from.
|
|
48
|
+
* @param override - Fields to overlay; when omitted, `base` is returned by reference.
|
|
49
|
+
* @returns The merged theme, or `base` itself when there is no override.
|
|
50
|
+
*/
|
|
32
51
|
function resolveEmailTheme(base, override) {
|
|
33
52
|
if (!override) return base;
|
|
34
53
|
return {
|
|
@@ -47,11 +66,28 @@ function resolveEmailTheme(base, override) {
|
|
|
47
66
|
fontsHref: override.fontsHref === null ? void 0 : override.fontsHref ?? base.fontsHref
|
|
48
67
|
};
|
|
49
68
|
}
|
|
50
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Merge an override onto the default ResQ Systems theme.
|
|
71
|
+
*
|
|
72
|
+
* Pure convenience wrapper over {@link resolveEmailTheme} with
|
|
73
|
+
* {@link defaultEmailTheme} as the base.
|
|
74
|
+
*
|
|
75
|
+
* @param override - Fields to overlay on the default theme.
|
|
76
|
+
* @returns The resolved theme.
|
|
77
|
+
*/
|
|
51
78
|
function mergeEmailTheme(override) {
|
|
52
79
|
return resolveEmailTheme(defaultEmailTheme, override);
|
|
53
80
|
}
|
|
54
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Build the `<Tailwind config>` object from a resolved theme.
|
|
83
|
+
*
|
|
84
|
+
* Pure — projects the theme's colors and font stacks into a Tailwind
|
|
85
|
+
* `theme.extend` config atop the pixel-based preset (email clients need px units,
|
|
86
|
+
* not rem).
|
|
87
|
+
*
|
|
88
|
+
* @param theme - The resolved theme to project.
|
|
89
|
+
* @returns The config object to pass to react-email's `<Tailwind>`.
|
|
90
|
+
*/
|
|
55
91
|
function buildTailwindConfig(theme) {
|
|
56
92
|
return {
|
|
57
93
|
presets: [pixelBasedPreset],
|
|
@@ -71,6 +107,12 @@ const EmailThemeContext = createContext(defaultEmailTheme);
|
|
|
71
107
|
* Wrap an element so it renders against a theme override (used by `renderEmail`).
|
|
72
108
|
* Returns the element unchanged when there is no override, so the default theme
|
|
73
109
|
* flows through context.
|
|
110
|
+
*
|
|
111
|
+
* Pure — builds a new provider element and does not mutate `element`.
|
|
112
|
+
*
|
|
113
|
+
* @param element - The email element tree to wrap.
|
|
114
|
+
* @param override - Theme fields to overlay; when omitted, `element` is returned unchanged.
|
|
115
|
+
* @returns `element`, wrapped in an {@link EmailThemeContext} provider when an override is given.
|
|
74
116
|
*/
|
|
75
117
|
function withEmailTheme(element, override) {
|
|
76
118
|
if (!override) return element;
|
|
@@ -82,6 +124,12 @@ const EmailMessageContext = createContext({ category: "transactional" });
|
|
|
82
124
|
* Wrap an element so it renders against a message policy (used by `renderEmail`).
|
|
83
125
|
* Returns the element unchanged when no message is given, so the default
|
|
84
126
|
* transactional policy flows through context.
|
|
127
|
+
*
|
|
128
|
+
* Pure — builds a new provider element and does not mutate `element`.
|
|
129
|
+
*
|
|
130
|
+
* @param element - The email element tree to wrap.
|
|
131
|
+
* @param message - The per-send policy; when omitted, `element` is returned unchanged.
|
|
132
|
+
* @returns `element`, wrapped in an {@link EmailMessageContext} provider when a message is given.
|
|
85
133
|
*/
|
|
86
134
|
function withEmailMessage(element, message) {
|
|
87
135
|
if (!message) return element;
|
package/lib/emails/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","names":[],"sources":["../../src/emails/theme.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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\nimport { pixelBasedPreset } from \"@react-email/components\";\nimport { type ReactElement, createContext, createElement } from \"react\";\nimport type { EmailCategory } from \"../schemas.js\";\nimport { emailColors, emailFonts, emailOrg } from \"./tokens.js\";\n\nexport interface EmailThemeFonts {\n\tdisplay: string[];\n\tsans: string[];\n\tmono: string[];\n}\n\n/** Organization identity rendered into email chrome (header, signature, footer). */\nexport interface EmailOrgIdentity {\n\tbrandName: string;\n\tproductName: string;\n\tlegalName: string;\n\tregisteredAddress: string;\n\tsupportEmail: string;\n\twebsiteUrl: string;\n\ttermsUrl: string;\n\tprivacyUrl: string;\n\tlogoUrl: string;\n}\n\n/** The full, resolved theme every template renders against. */\nexport interface EmailTheme {\n\t/** Color tokens → Tailwind `theme.extend.colors` (email-safe hex). */\n\tcolors: Record<string, string>;\n\t/** Font stacks → Tailwind `theme.extend.fontFamily` (pre-quoted multi-word names). */\n\tfonts: EmailThemeFonts;\n\t/** Organization identity for header lockup, signatures, and legal footer. */\n\torg: EmailOrgIdentity;\n\t/** Optional stylesheet `<link>` injected in `<Head>` for brand webfonts. */\n\tfontsHref?: string;\n}\n\n/** A partial theme a consumer supplies to rebrand; unset keys fall back to the base. */\nexport interface EmailThemeOverride {\n\tcolors?: Record<string, string>;\n\tfonts?: Partial<EmailThemeFonts>;\n\t/** Override organization identity fields (shallow-merged over the base). */\n\torg?: Partial<EmailOrgIdentity>;\n\t/** Pass `null` to drop the webfont link entirely. */\n\tfontsHref?: string | null;\n}\n\n/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */\nexport const defaultEmailTheme: EmailTheme = {\n\tcolors: { ...emailColors },\n\tfonts: {\n\t\tdisplay: [...emailFonts.stacks.display],\n\t\tsans: [...emailFonts.stacks.body],\n\t\tmono: [...emailFonts.stacks.mono],\n\t},\n\torg: { ...emailOrg },\n\tfontsHref: emailFonts.googleFontsHref,\n};\n\n/** Merge an override onto a base theme (colors/fonts shallow-merge; `fontsHref: null` removes it). */\nexport function resolveEmailTheme(base: EmailTheme, override?: EmailThemeOverride): EmailTheme {\n\tif (!override) return base;\n\treturn {\n\t\tcolors: { ...base.colors, ...override.colors },\n\t\tfonts: { ...base.fonts, ...override.fonts },\n\t\torg: { ...base.org, ...override.org },\n\t\tfontsHref: override.fontsHref === null ? undefined : (override.fontsHref ?? base.fontsHref),\n\t};\n}\n\n/** Merge an override onto the default ResQ Systems theme. */\nexport function mergeEmailTheme(override?: EmailThemeOverride): EmailTheme {\n\treturn resolveEmailTheme(defaultEmailTheme, override);\n}\n\n/** Build the `<Tailwind config>` object from a resolved theme. */\nexport function buildTailwindConfig(theme: EmailTheme) {\n\treturn {\n\t\tpresets: [pixelBasedPreset],\n\t\ttheme: {\n\t\t\textend: {\n\t\t\t\tcolors: { ...theme.colors },\n\t\t\t\tfontFamily: {\n\t\t\t\t\tdisplay: [...theme.fonts.display],\n\t\t\t\t\tsans: [...theme.fonts.sans],\n\t\t\t\t\tmono: [...theme.fonts.mono],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n}\n\n/** Context carrying the active theme; defaults to the ResQ Systems brand. */\nexport const EmailThemeContext = createContext<EmailTheme>(defaultEmailTheme);\n\n/**\n * Wrap an element so it renders against a theme override (used by `renderEmail`).\n * Returns the element unchanged when there is no override, so the default theme\n * flows through context.\n */\nexport function withEmailTheme(element: ReactElement, override?: EmailThemeOverride): ReactElement {\n\tif (!override) return element;\n\treturn createElement(EmailThemeContext.Provider, { value: mergeEmailTheme(override) }, element);\n}\n\n/** Per-send message policy carried through context to the legal footer. */\nexport interface EmailMessage {\n\t/** Compliance class; defaults to `transactional`. */\n\tcategory: EmailCategory;\n\t/** Where the unsubscribe/preferences link points (used for `marketing`). */\n\tunsubscribeUrl?: string;\n}\n\n/** Context carrying the active message policy; defaults to a transactional send. */\nexport const EmailMessageContext = createContext<EmailMessage>({ category: \"transactional\" });\n\n/**\n * Wrap an element so it renders against a message policy (used by `renderEmail`).\n * Returns the element unchanged when no message is given, so the default\n * transactional policy flows through context.\n */\nexport function withEmailMessage(element: ReactElement, message?: EmailMessage): ReactElement {\n\tif (!message) return element;\n\treturn createElement(EmailMessageContext.Provider, { value: message }, element);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+DA,MAAa,oBAAgC;CAC5C,QAAQ,EAAE,GAAG,YAAY;CACzB,OAAO;EACN,SAAS,CAAC,GAAG,WAAW,OAAO,OAAO;EACtC,MAAM,CAAC,GAAG,WAAW,OAAO,IAAI;EAChC,MAAM,CAAC,GAAG,WAAW,OAAO,IAAI;CACjC;CACA,KAAK,EAAE,GAAG,SAAS;CACnB,WAAW,WAAW;AACvB;;AAGA,SAAgB,kBAAkB,MAAkB,UAA2C;CAC9F,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO;EACN,QAAQ;GAAE,GAAG,KAAK;GAAQ,GAAG,SAAS;EAAO;EAC7C,OAAO;GAAE,GAAG,KAAK;GAAO,GAAG,SAAS;EAAM;EAC1C,KAAK;GAAE,GAAG,KAAK;GAAK,GAAG,SAAS;EAAI;EACpC,WAAW,SAAS,cAAc,OAAO,KAAA,IAAa,SAAS,aAAa,KAAK;CAClF;AACD;;AAGA,SAAgB,gBAAgB,UAA2C;CAC1E,OAAO,kBAAkB,mBAAmB,QAAQ;AACrD;;AAGA,SAAgB,oBAAoB,OAAmB;CACtD,OAAO;EACN,SAAS,CAAC,gBAAgB;EAC1B,OAAO,EACN,QAAQ;GACP,QAAQ,EAAE,GAAG,MAAM,OAAO;GAC1B,YAAY;IACX,SAAS,CAAC,GAAG,MAAM,MAAM,OAAO;IAChC,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;IAC1B,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;GAC3B;EACD,EACD;CACD;AACD;;AAGA,MAAa,oBAAoB,cAA0B,iBAAiB;;;;;;AAO5E,SAAgB,eAAe,SAAuB,UAA6C;CAClG,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,cAAc,kBAAkB,UAAU,EAAE,OAAO,gBAAgB,QAAQ,EAAE,GAAG,OAAO;AAC/F;;AAWA,MAAa,sBAAsB,cAA4B,EAAE,UAAU,gBAAgB,CAAC;;;;;;AAO5F,SAAgB,iBAAiB,SAAuB,SAAsC;CAC7F,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,cAAc,oBAAoB,UAAU,EAAE,OAAO,QAAQ,GAAG,OAAO;AAC/E"}
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"sources":["../../src/emails/theme.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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 * @fileoverview Email theming system — the resolved `EmailTheme` shape, override\n * merging, the Tailwind config builder, and React contexts carrying the active theme\n * and per-send message policy.\n *\n * @module @resq-systems/email-templates/emails/theme\n */\n\nimport { pixelBasedPreset } from \"@react-email/components\";\nimport { type ReactElement, createContext, createElement } from \"react\";\nimport type { EmailCategory } from \"../schemas.js\";\nimport { emailColors, emailFonts, emailOrg } from \"./tokens.js\";\n\n//#region Types\n\n/**\n * Font stacks the theme exposes to Tailwind's `fontFamily` extension. Each array\n * is a CSS font-family stack in priority order (preferred face first, generic\n * fallback last); multi-word names are pre-quoted so they drop straight into a\n * `font-family` value.\n */\nexport interface EmailThemeFonts {\n\t/** Stack for display/heading text. */\n\tdisplay: string[];\n\t/** Stack for body/sans text. */\n\tsans: string[];\n\t/** Stack for monospace text (codes, metadata). */\n\tmono: string[];\n}\n\n/**\n * Organization identity rendered into email chrome (header, signature, footer).\n *\n * All `*Url` fields are absolute URLs. {@link EmailOrgIdentity.registeredAddress}\n * leads with the legal entity name, so it stands alone as a complete CAN-SPAM\n * postal line without a separate `legalName` line in the footer.\n */\nexport interface EmailOrgIdentity {\n\t/** Short brand name used in sign-offs, e.g. \"— The {brandName} team\". */\n\tbrandName: string;\n\t/** Product name shown in the header lockup beside the logo. */\n\tproductName: string;\n\t/** Full legal entity name. */\n\tlegalName: string;\n\t/** Registered postal address, prefixed with the legal name; a complete CAN-SPAM line. */\n\tregisteredAddress: string;\n\t/** Support inbox address, rendered as a `mailto:` link. */\n\tsupportEmail: string;\n\t/** Marketing/website URL (absolute). Never used as an unsubscribe target. */\n\twebsiteUrl: string;\n\t/** Absolute URL of the Terms page. */\n\ttermsUrl: string;\n\t/** Absolute URL of the Privacy page. */\n\tprivacyUrl: string;\n\t/** Absolute URL of the header logo image. */\n\tlogoUrl: string;\n}\n\n/** The full, resolved theme every template renders against. */\nexport interface EmailTheme {\n\t/** Color tokens → Tailwind `theme.extend.colors` (email-safe hex). */\n\tcolors: Record<string, string>;\n\t/** Font stacks → Tailwind `theme.extend.fontFamily` (pre-quoted multi-word names). */\n\tfonts: EmailThemeFonts;\n\t/** Organization identity for header lockup, signatures, and legal footer. */\n\torg: EmailOrgIdentity;\n\t/** Optional stylesheet `<link>` injected in `<Head>` for brand webfonts. */\n\tfontsHref?: string;\n}\n\n/**\n * A partial theme a consumer supplies to rebrand; unset keys fall back to the\n * base. All object fields are **shallow**-merged over the base one level deep (see\n * {@link resolveEmailTheme}), so supplying `colors` replaces only the named color\n * tokens, not the whole palette.\n */\nexport interface EmailThemeOverride {\n\t/** Color tokens to override (email-safe hex); merged over the base palette. */\n\tcolors?: Record<string, string>;\n\t/** Font stacks to override; unspecified stacks keep the base. */\n\tfonts?: Partial<EmailThemeFonts>;\n\t/** Override organization identity fields (shallow-merged over the base). */\n\torg?: Partial<EmailOrgIdentity>;\n\t/** Replace the webfont `<link>` href, or pass `null` to drop it entirely. */\n\tfontsHref?: string | null;\n}\n\n//#endregion\n\n//#region Public API\n\n/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */\nexport const defaultEmailTheme: EmailTheme = {\n\tcolors: { ...emailColors },\n\tfonts: {\n\t\tdisplay: [...emailFonts.stacks.display],\n\t\tsans: [...emailFonts.stacks.body],\n\t\tmono: [...emailFonts.stacks.mono],\n\t},\n\torg: { ...emailOrg },\n\tfontsHref: emailFonts.googleFontsHref,\n};\n\n/**\n * Merge an override onto a base theme, producing a new resolved theme.\n *\n * Pure — never mutates `base`. `colors`, `fonts`, and `org` are **shallow**-merged\n * (override keys replace base keys one level deep), so a partial `fonts` override\n * keeps the base's other stacks. `fontsHref` follows a three-way rule: `null`\n * drops the webfont link entirely, absent/`undefined` keeps the base href, and any\n * string replaces it.\n *\n * @param base - The theme to start from.\n * @param override - Fields to overlay; when omitted, `base` is returned by reference.\n * @returns The merged theme, or `base` itself when there is no override.\n */\nexport function resolveEmailTheme(base: EmailTheme, override?: EmailThemeOverride): EmailTheme {\n\tif (!override) return base;\n\treturn {\n\t\tcolors: { ...base.colors, ...override.colors },\n\t\tfonts: { ...base.fonts, ...override.fonts },\n\t\torg: { ...base.org, ...override.org },\n\t\tfontsHref: override.fontsHref === null ? undefined : (override.fontsHref ?? base.fontsHref),\n\t};\n}\n\n/**\n * Merge an override onto the default ResQ Systems theme.\n *\n * Pure convenience wrapper over {@link resolveEmailTheme} with\n * {@link defaultEmailTheme} as the base.\n *\n * @param override - Fields to overlay on the default theme.\n * @returns The resolved theme.\n */\nexport function mergeEmailTheme(override?: EmailThemeOverride): EmailTheme {\n\treturn resolveEmailTheme(defaultEmailTheme, override);\n}\n\n/**\n * Build the `<Tailwind config>` object from a resolved theme.\n *\n * Pure — projects the theme's colors and font stacks into a Tailwind\n * `theme.extend` config atop the pixel-based preset (email clients need px units,\n * not rem).\n *\n * @param theme - The resolved theme to project.\n * @returns The config object to pass to react-email's `<Tailwind>`.\n */\nexport function buildTailwindConfig(theme: EmailTheme) {\n\treturn {\n\t\tpresets: [pixelBasedPreset],\n\t\ttheme: {\n\t\t\textend: {\n\t\t\t\tcolors: { ...theme.colors },\n\t\t\t\tfontFamily: {\n\t\t\t\t\tdisplay: [...theme.fonts.display],\n\t\t\t\t\tsans: [...theme.fonts.sans],\n\t\t\t\t\tmono: [...theme.fonts.mono],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n}\n\n/** Context carrying the active theme; defaults to the ResQ Systems brand. */\nexport const EmailThemeContext = createContext<EmailTheme>(defaultEmailTheme);\n\n/**\n * Wrap an element so it renders against a theme override (used by `renderEmail`).\n * Returns the element unchanged when there is no override, so the default theme\n * flows through context.\n *\n * Pure — builds a new provider element and does not mutate `element`.\n *\n * @param element - The email element tree to wrap.\n * @param override - Theme fields to overlay; when omitted, `element` is returned unchanged.\n * @returns `element`, wrapped in an {@link EmailThemeContext} provider when an override is given.\n */\nexport function withEmailTheme(element: ReactElement, override?: EmailThemeOverride): ReactElement {\n\tif (!override) return element;\n\treturn createElement(EmailThemeContext.Provider, { value: mergeEmailTheme(override) }, element);\n}\n\n/**\n * Per-send message policy carried through context to the legal footer.\n *\n * The unsubscribe affordance renders only when {@link EmailMessage.category} is\n * `\"marketing\"` **and** {@link EmailMessage.unsubscribeUrl} is set; a marketing\n * send with no `unsubscribeUrl` simply omits it (there is no homepage fallback).\n */\nexport interface EmailMessage {\n\t/** Compliance class; defaults to `transactional`. */\n\tcategory: EmailCategory;\n\t/** Absolute unsubscribe/preferences URL; only consulted for `marketing` sends. */\n\tunsubscribeUrl?: string;\n}\n\n/** Context carrying the active message policy; defaults to a transactional send. */\nexport const EmailMessageContext = createContext<EmailMessage>({ category: \"transactional\" });\n\n/**\n * Wrap an element so it renders against a message policy (used by `renderEmail`).\n * Returns the element unchanged when no message is given, so the default\n * transactional policy flows through context.\n *\n * Pure — builds a new provider element and does not mutate `element`.\n *\n * @param element - The email element tree to wrap.\n * @param message - The per-send policy; when omitted, `element` is returned unchanged.\n * @returns `element`, wrapped in an {@link EmailMessageContext} provider when a message is given.\n */\nexport function withEmailMessage(element: ReactElement, message?: EmailMessage): ReactElement {\n\tif (!message) return element;\n\treturn createElement(EmailMessageContext.Provider, { value: message }, element);\n}\n\n//#endregion\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4GA,MAAa,oBAAgC;CAC5C,QAAQ,EAAE,GAAG,YAAY;CACzB,OAAO;EACN,SAAS,CAAC,GAAG,WAAW,OAAO,OAAO;EACtC,MAAM,CAAC,GAAG,WAAW,OAAO,IAAI;EAChC,MAAM,CAAC,GAAG,WAAW,OAAO,IAAI;CACjC;CACA,KAAK,EAAE,GAAG,SAAS;CACnB,WAAW,WAAW;AACvB;;;;;;;;;;;;;;AAeA,SAAgB,kBAAkB,MAAkB,UAA2C;CAC9F,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO;EACN,QAAQ;GAAE,GAAG,KAAK;GAAQ,GAAG,SAAS;EAAO;EAC7C,OAAO;GAAE,GAAG,KAAK;GAAO,GAAG,SAAS;EAAM;EAC1C,KAAK;GAAE,GAAG,KAAK;GAAK,GAAG,SAAS;EAAI;EACpC,WAAW,SAAS,cAAc,OAAO,KAAA,IAAa,SAAS,aAAa,KAAK;CAClF;AACD;;;;;;;;;;AAWA,SAAgB,gBAAgB,UAA2C;CAC1E,OAAO,kBAAkB,mBAAmB,QAAQ;AACrD;;;;;;;;;;;AAYA,SAAgB,oBAAoB,OAAmB;CACtD,OAAO;EACN,SAAS,CAAC,gBAAgB;EAC1B,OAAO,EACN,QAAQ;GACP,QAAQ,EAAE,GAAG,MAAM,OAAO;GAC1B,YAAY;IACX,SAAS,CAAC,GAAG,MAAM,MAAM,OAAO;IAChC,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;IAC1B,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;GAC3B;EACD,EACD;CACD;AACD;;AAGA,MAAa,oBAAoB,cAA0B,iBAAiB;;;;;;;;;;;;AAa5E,SAAgB,eAAe,SAAuB,UAA6C;CAClG,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO,cAAc,kBAAkB,UAAU,EAAE,OAAO,gBAAgB,QAAQ,EAAE,GAAG,OAAO;AAC/F;;AAiBA,MAAa,sBAAsB,cAA4B,EAAE,UAAU,gBAAgB,CAAC;;;;;;;;;;;;AAa5F,SAAgB,iBAAiB,SAAuB,SAAsC;CAC7F,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,cAAc,oBAAoB,UAAU,EAAE,OAAO,QAAQ,GAAG,OAAO;AAC/E"}
|
package/lib/emails/tokens.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ declare const emailFonts: {
|
|
|
43
43
|
};
|
|
44
44
|
readonly googleFontsHref: "https://fonts.googleapis.com/css2?family=Syne:wght@700;800&family=DM+Sans:wght@400;500&family=DM+Mono:wght@500&display=swap";
|
|
45
45
|
};
|
|
46
|
+
/** Union of the available email-safe color token names. */
|
|
46
47
|
type EmailColorToken = keyof typeof emailColors;
|
|
47
48
|
/**
|
|
48
49
|
* Organization identity for email chrome (header lockup, signatures, legal
|
|
@@ -54,7 +55,7 @@ declare const emailOrg: {
|
|
|
54
55
|
readonly productName: "ResQ Tactical OS";
|
|
55
56
|
readonly legalName: "ResQ Systems, Inc.";
|
|
56
57
|
readonly registeredAddress: "ResQ Systems, Inc., 131 Continental Dr, Suite 305, Newark, DE 19713, USA";
|
|
57
|
-
readonly supportEmail: "
|
|
58
|
+
readonly supportEmail: "contact@resq.software";
|
|
58
59
|
readonly websiteUrl: "https://resq.software";
|
|
59
60
|
readonly termsUrl: "https://resq.software/legal/terms";
|
|
60
61
|
readonly privacyUrl: "https://resq.software/legal/privacy";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","names":[],"sources":["../../src/emails/tokens.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","names":[],"sources":["../../src/emails/tokens.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;cAgCa;;;;;;;;;;;;;cAGA;;;;;;;;;;;;KAGD,+BAA+B;;;;;;cAO9B;WACZ;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA"}
|
package/lib/emails/tokens.js
CHANGED
|
@@ -17,6 +17,13 @@ import { colors, fonts } from "@resq-systems/constants/tokens";
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
/**
|
|
20
|
+
* @fileoverview Email-safe brand tokens — the hex color palette, font stacks, and
|
|
21
|
+
* organization identity, sourced from `@resq-systems/constants` so branding stays
|
|
22
|
+
* centralized across apps.
|
|
23
|
+
*
|
|
24
|
+
* @module @resq-systems/email-templates/emails/tokens
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
20
27
|
* Email-safe hex color tokens, sourced from the shared `@resq-systems/constants`
|
|
21
28
|
* design tokens so the brand palette lives in one place across apps. Email
|
|
22
29
|
* clients don't support `oklch()`, so the hex snapshot is used here.
|
package/lib/emails/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","names":[],"sources":["../../src/emails/tokens.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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\nimport { brand } from \"@resq-systems/constants/brand\";\nimport { colors, fonts } from \"@resq-systems/constants/tokens\";\n\n/**\n * Email-safe hex color tokens, sourced from the shared `@resq-systems/constants`\n * design tokens so the brand palette lives in one place across apps. Email\n * clients don't support `oklch()`, so the hex snapshot is used here.\n */\nexport const emailColors = colors.hex;\n\n/** Brand font stacks + webfont stylesheet href, from the shared design tokens. */\nexport const emailFonts = fonts;\n\nexport type EmailColorToken = keyof typeof emailColors;\n\n/**\n * Organization identity for email chrome (header lockup, signatures, legal\n * footer), derived from the shared `@resq-systems/constants` brand so names,\n * addresses, and legal URLs live in one place across apps.\n */\nexport const emailOrg = {\n\tbrandName: brand.name,\n\tproductName: brand.productName,\n\tlegalName: brand.legalName,\n\tregisteredAddress: brand.postalAddress,\n\tsupportEmail: brand.email.support,\n\twebsiteUrl: brand.domains.marketing,\n\ttermsUrl: brand.legal.termsUrl,\n\tprivacyUrl: brand.legal.privacyUrl,\n\tlogoUrl: brand.logo,\n} as const;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tokens.js","names":[],"sources":["../../src/emails/tokens.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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 * @fileoverview Email-safe brand tokens — the hex color palette, font stacks, and\n * organization identity, sourced from `@resq-systems/constants` so branding stays\n * centralized across apps.\n *\n * @module @resq-systems/email-templates/emails/tokens\n */\n\nimport { brand } from \"@resq-systems/constants/brand\";\nimport { colors, fonts } from \"@resq-systems/constants/tokens\";\n\n/**\n * Email-safe hex color tokens, sourced from the shared `@resq-systems/constants`\n * design tokens so the brand palette lives in one place across apps. Email\n * clients don't support `oklch()`, so the hex snapshot is used here.\n */\nexport const emailColors = colors.hex;\n\n/** Brand font stacks + webfont stylesheet href, from the shared design tokens. */\nexport const emailFonts = fonts;\n\n/** Union of the available email-safe color token names. */\nexport type EmailColorToken = keyof typeof emailColors;\n\n/**\n * Organization identity for email chrome (header lockup, signatures, legal\n * footer), derived from the shared `@resq-systems/constants` brand so names,\n * addresses, and legal URLs live in one place across apps.\n */\nexport const emailOrg = {\n\tbrandName: brand.name,\n\tproductName: brand.productName,\n\tlegalName: brand.legalName,\n\tregisteredAddress: brand.postalAddress,\n\tsupportEmail: brand.email.support,\n\twebsiteUrl: brand.domains.marketing,\n\ttermsUrl: brand.legal.termsUrl,\n\tprivacyUrl: brand.legal.privacyUrl,\n\tlogoUrl: brand.logo,\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,cAAc,OAAO;;AAGlC,MAAa,aAAa;;;;;;AAU1B,MAAa,WAAW;CACvB,WAAW,MAAM;CACjB,aAAa,MAAM;CACnB,WAAW,MAAM;CACjB,mBAAmB,MAAM;CACzB,cAAc,MAAM,MAAM;CAC1B,YAAY,MAAM,QAAQ;CAC1B,UAAU,MAAM,MAAM;CACtB,YAAY,MAAM,MAAM;CACxB,SAAS,MAAM;AAChB"}
|
package/lib/emails/welcome.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WelcomeData } from "../schemas.js";
|
|
2
2
|
//#region src/emails/welcome.d.ts
|
|
3
|
+
/** Props for {@link WelcomeEmail} — the welcome template's validated `data`. */
|
|
3
4
|
type WelcomeEmailProps = WelcomeData;
|
|
4
5
|
/** Account welcome / onboarding email. */
|
|
5
6
|
declare function WelcomeEmail({ firstName, verifyUrl }: WelcomeEmailProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome.d.ts","names":[],"sources":["../../src/emails/welcome.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"welcome.d.ts","names":[],"sources":["../../src/emails/welcome.tsx"],"mappings":";;;KA0BY,oBAAoB;;iBAGhB,eAAe,WAAqB,aAAa,oCAAiB,IAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome.js","names":[],"sources":["../../src/emails/welcome.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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\nimport type { WelcomeData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type WelcomeEmailProps = WelcomeData;\n\n/** Account welcome / onboarding email. */\nexport function WelcomeEmail({ firstName = \"there\", verifyUrl }: WelcomeEmailProps) {\n\treturn (\n\t\t<Email.Shell preview={`Welcome to ResQ Systems, ${firstName}`}>\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>Welcome to ResQ Systems</Email.Title>\n\t\t\t<Email.Paragraph>Hi {firstName},</Email.Paragraph>\n\t\t\t<Email.Paragraph>\n\t\t\t\tThanks for creating an account. Everything is set up and ready when you are.\n\t\t\t</Email.Paragraph>\n\t\t\t{verifyUrl ? (\n\t\t\t\t<>\n\t\t\t\t\t<Email.Paragraph>\n\t\t\t\t\t\tConfirm your email address to finish setting up your account.\n\t\t\t\t\t</Email.Paragraph>\n\t\t\t\t\t<Email.CTA href={verifyUrl}>Verify email</Email.CTA>\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t\t<Email.Signature />\n\t\t\t<Email.LegalFooter\n\t\t\t\tcategory=\"transactional\"\n\t\t\t\treason=\"You are receiving this email because you created a ResQ Systems account.\"\n\t\t\t/>\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"welcome.js","names":[],"sources":["../../src/emails/welcome.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\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 * @fileoverview Account welcome / onboarding email component.\n *\n * @module @resq-systems/email-templates/emails/welcome\n */\n\nimport type { WelcomeData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\n/** Props for {@link WelcomeEmail} — the welcome template's validated `data`. */\nexport type WelcomeEmailProps = WelcomeData;\n\n/** Account welcome / onboarding email. */\nexport function WelcomeEmail({ firstName = \"there\", verifyUrl }: WelcomeEmailProps) {\n\treturn (\n\t\t<Email.Shell preview={`Welcome to ResQ Systems, ${firstName}`}>\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>Welcome to ResQ Systems</Email.Title>\n\t\t\t<Email.Paragraph>Hi {firstName},</Email.Paragraph>\n\t\t\t<Email.Paragraph>\n\t\t\t\tThanks for creating an account. Everything is set up and ready when you are.\n\t\t\t</Email.Paragraph>\n\t\t\t{verifyUrl ? (\n\t\t\t\t<>\n\t\t\t\t\t<Email.Paragraph>\n\t\t\t\t\t\tConfirm your email address to finish setting up your account.\n\t\t\t\t\t</Email.Paragraph>\n\t\t\t\t\t<Email.CTA href={verifyUrl}>Verify email</Email.CTA>\n\t\t\t\t</>\n\t\t\t) : null}\n\t\t\t<Email.Signature />\n\t\t\t<Email.LegalFooter\n\t\t\t\tcategory=\"transactional\"\n\t\t\t\treason=\"You are receiving this email because you created a ResQ Systems account.\"\n\t\t\t/>\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;AA6BA,SAAgB,aAAa,EAAE,YAAY,SAAS,aAAgC;CACnF,OACC,qBAAC,MAAM,OAAP;EAAa,SAAS,4BAA4B;EAAlD,UAAA;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,oBAAC,MAAM,OAAP,EAAA,UAAa,0BAAoC,CAAA;GACjD,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAI;IAAU;GAAkB,EAAA,CAAA;GACjD,oBAAC,MAAM,WAAP,EAAA,UAAiB,+EAEA,CAAA;GAChB,YACA,qBAAA,UAAA,EAAA,UAAA,CACC,oBAAC,MAAM,WAAP,EAAA,UAAiB,gEAEA,CAAA,GACjB,oBAAC,MAAM,KAAP;IAAW,MAAM;IAAW,UAAA;GAAuB,CAAA,CAClD,EAAA,CAAA,IACC;GACJ,oBAAC,MAAM,WAAP,CAAkB,CAAA;GAClB,oBAAC,MAAM,aAAP;IACC,UAAS;IACT,QAAO;GACP,CAAA;EACW;;AAEf"}
|
package/lib/index.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ import { EmailName, EmailPayload, EmailTemplateData, decodeEmailPayload } from "
|
|
|
5
5
|
import { registry } from "./registry.js";
|
|
6
6
|
import { renderEmail } from "./render.js";
|
|
7
7
|
import { incidentAlertTemplate, missionApprovalTemplate, newDeviceLoginTemplate, notificationTemplate, orgInvitationTemplate, otpTemplate, passwordChangedTemplate, passwordResetTemplate, resqEmailTemplates, welcomeTemplate } from "./templates.js";
|
|
8
|
-
export { EmailAddress, EmailCategory, EmailMessage, EmailMessageContext, EmailName, EmailOrgIdentity, EmailPayload, type EmailRegistryEntry, EmailTemplateData, type EmailTemplateDef, EmailTheme, EmailThemeContext, EmailThemeFonts, EmailThemeOverride, EmailValidationError, HttpUrl, IncidentAlertData, type Mailer, type MailerPayload, type MailerTemplateData, MissionApprovalData, NewDeviceLoginData, NotificationData, OrgInvitationData, OtpData, PasswordChangedData, PasswordResetData, type RenderEmailOptions, type RenderedEmail, WelcomeData, buildTailwindConfig, createMailer, decodeEmailPayload, defaultEmailTheme, defineEmailTemplate, emailCategory, incidentAlertData, incidentAlertTemplate, mergeEmailTheme, missionApprovalData, missionApprovalTemplate, newDeviceLoginData, newDeviceLoginTemplate, notificationData, notificationTemplate, orgInvitationData, orgInvitationTemplate, otpData, otpTemplate, passwordChangedData, passwordChangedTemplate, passwordResetData, passwordResetTemplate, registry, renderEmail, resolveEmailTheme, resqEmailTemplates, welcomeData, welcomeTemplate, withEmailMessage, withEmailTheme };
|
|
8
|
+
export { EmailAddress, type EmailCategory, type EmailMessage, EmailMessageContext, type EmailName, type EmailOrgIdentity, EmailPayload, type EmailRegistryEntry, type EmailTemplateData, type EmailTemplateDef, type EmailTheme, EmailThemeContext, type EmailThemeFonts, type EmailThemeOverride, EmailValidationError, HttpUrl, type IncidentAlertData, type Mailer, type MailerPayload, type MailerTemplateData, type MissionApprovalData, type NewDeviceLoginData, type NotificationData, type OrgInvitationData, type OtpData, type PasswordChangedData, type PasswordResetData, type RenderEmailOptions, type RenderedEmail, type WelcomeData, buildTailwindConfig, createMailer, decodeEmailPayload, defaultEmailTheme, defineEmailTemplate, emailCategory, incidentAlertData, incidentAlertTemplate, mergeEmailTheme, missionApprovalData, missionApprovalTemplate, newDeviceLoginData, newDeviceLoginTemplate, notificationData, notificationTemplate, orgInvitationData, orgInvitationTemplate, otpData, otpTemplate, passwordChangedData, passwordChangedTemplate, passwordResetData, passwordResetTemplate, registry, renderEmail, resolveEmailTheme, resqEmailTemplates, welcomeData, welcomeTemplate, withEmailMessage, withEmailTheme };
|
package/lib/mailer.d.ts
CHANGED
|
@@ -3,14 +3,42 @@ import { EmailThemeOverride } from "./emails/theme.js";
|
|
|
3
3
|
import { Schema } from "effect";
|
|
4
4
|
import { ReactElement } from "react";
|
|
5
5
|
//#region src/mailer.d.ts
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* A template definition: its discriminant {@link EmailTemplateDef.name}, `data`
|
|
8
|
+
* schema, subject builder, and React component.
|
|
9
|
+
*
|
|
10
|
+
* `name` must be unique across the defs handed to {@link createMailer} — it is the
|
|
11
|
+
* payload union's discriminant, and a later def with a duplicate name silently
|
|
12
|
+
* overwrites the earlier one in the registry (last write wins in
|
|
13
|
+
* `Object.fromEntries`). `subject` and `Component` are only ever invoked with data
|
|
14
|
+
* that has already cleared `data`'s schema at the decode boundary, so they may
|
|
15
|
+
* treat every field as valid and should stay pure.
|
|
16
|
+
*
|
|
17
|
+
* @template Name - The literal template name (e.g. `"otp"`); the payload discriminant.
|
|
18
|
+
* @template DataSchema - The Effect Schema whose decoded `Type` is this template's `data`.
|
|
19
|
+
*/
|
|
7
20
|
interface EmailTemplateDef<Name extends string, DataSchema extends Schema.Top> {
|
|
21
|
+
/** Unique template name; the payload union's discriminant. */
|
|
8
22
|
readonly name: Name;
|
|
23
|
+
/** Effect Schema that validates this template's `data` at the decode boundary. */
|
|
9
24
|
readonly data: DataSchema;
|
|
25
|
+
/** Builds the subject line from already-validated `data`. Should be pure. */
|
|
10
26
|
readonly subject: (data: DataSchema["Type"]) => string;
|
|
27
|
+
/** Renders the email body from already-validated `data`. */
|
|
11
28
|
readonly Component: (data: DataSchema["Type"]) => ReactElement;
|
|
12
29
|
}
|
|
13
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Identity helper that infers and preserves a template def's literal types.
|
|
32
|
+
*
|
|
33
|
+
* Pure — returns `def` by reference, unchanged. It exists only so the `const` type
|
|
34
|
+
* parameters capture the literal `name` and the schema's `Type` at the call site;
|
|
35
|
+
* a bare object literal would widen `name` to `string` and lose the discriminant.
|
|
36
|
+
*
|
|
37
|
+
* @template Name - The literal template name; preserved via the `const` modifier.
|
|
38
|
+
* @template DataSchema - The template's `data` schema.
|
|
39
|
+
* @param def - The template definition to brand with its inferred literal types.
|
|
40
|
+
* @returns The same `def` object, typed with its narrowed literals.
|
|
41
|
+
*/
|
|
14
42
|
declare function defineEmailTemplate<const Name extends string, DataSchema extends Schema.Top>(def: EmailTemplateDef<Name, DataSchema>): EmailTemplateDef<Name, DataSchema>;
|
|
15
43
|
/**
|
|
16
44
|
* The common supertype for a heterogeneous list of template defs. The `never`
|
|
@@ -34,18 +62,38 @@ type PayloadFor<Def> = Def extends EmailTemplateDef<infer Name, infer DataSchema
|
|
|
34
62
|
/** Unsubscribe/preferences URL, surfaced in the legal footer for `marketing`. */
|
|
35
63
|
readonly unsubscribeUrl?: string;
|
|
36
64
|
} : never;
|
|
37
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* The discriminated payload union for a tuple of template defs — one
|
|
67
|
+
* `{ name, to, data, category?, unsubscribeUrl? }` variant per def, discriminated
|
|
68
|
+
* by the literal `name` field. Narrow a value with `payload.name` to recover the
|
|
69
|
+
* matching `data` type.
|
|
70
|
+
*
|
|
71
|
+
* @template Defs - The `as const` tuple of template defs the union is built over.
|
|
72
|
+
*/
|
|
38
73
|
type MailerPayload<Defs extends readonly AnyTemplateDef[]> = PayloadFor<Defs[number]>;
|
|
39
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* The `data` type for a given template name within a set of defs — the `data`
|
|
76
|
+
* field of the {@link MailerPayload} variant whose discriminant equals `Name`.
|
|
77
|
+
*
|
|
78
|
+
* @template Defs - The tuple of template defs the payload union is built over.
|
|
79
|
+
* @template Name - The literal `name` selecting a single variant's `data` shape.
|
|
80
|
+
*/
|
|
40
81
|
type MailerTemplateData<Defs extends readonly AnyTemplateDef[], Name extends MailerPayload<Defs>["name"]> = Extract<MailerPayload<Defs>, {
|
|
41
82
|
name: Name;
|
|
42
83
|
}>["data"];
|
|
43
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* The rendered, provider-ready email — the resolved output of
|
|
86
|
+
* {@link Mailer.renderEmail}. `html` and `text` are two renderings of the *same*
|
|
87
|
+
* message, so a provider may attach both as a multipart alternative.
|
|
88
|
+
*/
|
|
44
89
|
interface RenderedEmail {
|
|
45
|
-
/** Validated recipient (branded {@link EmailAddress}), carried from decode. */
|
|
90
|
+
/** Validated recipient (branded {@link EmailAddress}), carried through from decode. */
|
|
46
91
|
to: EmailAddress;
|
|
92
|
+
/** The subject line produced by the template's `subject` builder. */
|
|
47
93
|
subject: string;
|
|
94
|
+
/** The complete standalone HTML document for the email body. */
|
|
48
95
|
html: string;
|
|
96
|
+
/** The plain-text alternative rendering of the same body, for text-only clients. */
|
|
49
97
|
text: string;
|
|
50
98
|
}
|
|
51
99
|
/** Options for a mailer's `renderEmail`. */
|
|
@@ -53,13 +101,30 @@ interface RenderEmailOptions {
|
|
|
53
101
|
/** Rebrand this render by overriding theme colors/fonts (see `EmailThemeOverride`). */
|
|
54
102
|
theme?: EmailThemeOverride;
|
|
55
103
|
}
|
|
56
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Thrown when an untrusted payload fails schema validation at the decode boundary
|
|
106
|
+
* ({@link Mailer.decode}, and transitively {@link Mailer.renderEmail}).
|
|
107
|
+
*
|
|
108
|
+
* The `message` is the squashed Effect `Cause` from the failed decode; `name` is
|
|
109
|
+
* the stable literal `"EmailValidationError"`, so a caller can tell a bad payload
|
|
110
|
+
* apart from other failures by `name` without relying on `instanceof` across
|
|
111
|
+
* module/realm boundaries.
|
|
112
|
+
*/
|
|
57
113
|
declare class EmailValidationError extends Error {
|
|
58
114
|
readonly name = "EmailValidationError";
|
|
59
115
|
}
|
|
60
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* A registry entry: the subject builder and component renderer for one template.
|
|
118
|
+
*
|
|
119
|
+
* Both functions take `unknown` because the registry is keyed by name and has
|
|
120
|
+
* erased each def's `data` type. They must only be called with data that has
|
|
121
|
+
* already passed that template's schema (as {@link Mailer.renderEmail} does after
|
|
122
|
+
* {@link Mailer.decode}); calling them with unvalidated data is unsound.
|
|
123
|
+
*/
|
|
61
124
|
interface EmailRegistryEntry {
|
|
125
|
+
/** Builds the subject from validated `data` (typed `unknown` after name-erasure). */
|
|
62
126
|
subject: (data: unknown) => string;
|
|
127
|
+
/** Renders the body element from validated `data` (typed `unknown` after name-erasure). */
|
|
63
128
|
render: (data: unknown) => ReactElement;
|
|
64
129
|
}
|
|
65
130
|
/** A composed set of templates: contract schema, decoder, registry, and renderer. */
|
|
@@ -72,11 +137,33 @@ interface Mailer<Payload extends {
|
|
|
72
137
|
readonly schema: Schema.Top;
|
|
73
138
|
/** name → { subject, render } for every template. */
|
|
74
139
|
readonly registry: Record<Payload["name"], EmailRegistryEntry>;
|
|
75
|
-
/** Every registered template name. */
|
|
140
|
+
/** Every registered template name, in def order. */
|
|
76
141
|
readonly names: readonly Payload["name"][];
|
|
77
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* Validate an untrusted payload against the contract union and return the
|
|
144
|
+
* narrowed {@link Payload}.
|
|
145
|
+
*
|
|
146
|
+
* @param input - Untrusted `{ name, to, data }` value from the boundary.
|
|
147
|
+
* @returns The validated, branded payload.
|
|
148
|
+
* @throws {EmailValidationError} If `input` matches no template variant — bad
|
|
149
|
+
* `name`, a malformed/header-injecting `to`, or `data` failing its schema.
|
|
150
|
+
*/
|
|
78
151
|
decode(input: unknown): Payload;
|
|
79
|
-
/**
|
|
152
|
+
/**
|
|
153
|
+
* Validate then render a payload to `{ to, subject, html, text }`.
|
|
154
|
+
*
|
|
155
|
+
* Validates via {@link decode} first, then renders headlessly through
|
|
156
|
+
* `@react-email/render` — no browser, DOM, network, or clock — so it is safe in
|
|
157
|
+
* queue workers and cron jobs. Pure and stateless: concurrent calls against one
|
|
158
|
+
* mailer do not interfere, and there is no ordering guarantee between them. Does
|
|
159
|
+
* not honour an `AbortSignal`.
|
|
160
|
+
*
|
|
161
|
+
* @param input - Untrusted payload to validate and render.
|
|
162
|
+
* @param options - Optional per-render theme override.
|
|
163
|
+
* @returns A promise resolving to the rendered email.
|
|
164
|
+
* @throws {EmailValidationError} As a rejected promise, when `input` fails
|
|
165
|
+
* validation (surfaced from {@link decode}).
|
|
166
|
+
*/
|
|
80
167
|
renderEmail(input: unknown, options?: RenderEmailOptions): Promise<RenderedEmail>;
|
|
81
168
|
}
|
|
82
169
|
/**
|
|
@@ -84,6 +171,26 @@ interface Mailer<Payload extends {
|
|
|
84
171
|
* `{ name, to, data }` contract, a boundary decoder, a registry, and a headless
|
|
85
172
|
* renderer. Spread the built-in `resqEmailTemplates` and add your own — each
|
|
86
173
|
* template's `data` is validated by its Effect Schema.
|
|
174
|
+
*
|
|
175
|
+
* Pure: builds the schema union and registry eagerly and holds no mutable state;
|
|
176
|
+
* the returned `decode`/`renderEmail` are the only fallible surfaces. `defs`
|
|
177
|
+
* should have unique `name`s — a duplicate makes the later def win in the registry
|
|
178
|
+
* while both remain in the schema union (see {@link EmailTemplateDef}).
|
|
179
|
+
*
|
|
180
|
+
* @template Defs - The `as const` tuple of template defs to compose.
|
|
181
|
+
* @param defs - The template definitions; pass `[...resqEmailTemplates, myDef]` to extend the built-ins.
|
|
182
|
+
* @returns A {@link Mailer} whose `decode` throws (and `renderEmail` rejects with)
|
|
183
|
+
* {@link EmailValidationError} on invalid input.
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* const mailer = createMailer(resqEmailTemplates);
|
|
187
|
+
* const { subject } = await mailer.renderEmail({
|
|
188
|
+
* name: "otp",
|
|
189
|
+
* to: "user@example.com",
|
|
190
|
+
* data: { code: "123456" },
|
|
191
|
+
* });
|
|
192
|
+
* subject; // → "Your ResQ Systems verification code: 123456"
|
|
193
|
+
* ```
|
|
87
194
|
*/
|
|
88
195
|
declare function createMailer<const Defs extends readonly AnyTemplateDef[]>(defs: Defs): Mailer<MailerPayload<Defs>>;
|
|
89
196
|
//#endregion
|
package/lib/mailer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailer.d.ts","names":[],"sources":["../src/mailer.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"mailer.d.ts","names":[],"sources":["../src/mailer.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;UA+DiB,iBAAiB,qBAAqB,mBAAmB,OAAO;;WAEvE,MAAM;;WAEN,MAAM;;WAEN,UAAU,MAAM;;WAEhB,YAAY,MAAM,uBAAuB;;;;;;;;;;;;;;iBAenC,0BAA0B,qBAAqB,mBAAmB,OAAO,KACxF,KAAK,iBAAiB,MAAM,cAC1B,iBAAiB,MAAM;;;;;;;UAUhB;WACA;WACA,MAAM,OAAO;WACb,UAAU;WACV,YAAY,gBAAgB;;;KAIjC,WAAW,OACf,YAAY,uBAAuB,YAAY;WAEnC,MAAM;WACN,IAAI;WACJ,MAAM;;WAEN;;WAEA;;;;;;;;;;KAYD,cAAc,sBAAsB,oBAAoB,WAAW;;;;;;;;KASnE,mBACX,sBAAsB,kBACtB,aAAa,cAAc,iBACxB,QAAQ,cAAc;EAAS,MAAM;;;;;;;UAOxB;;EAEhB,IAAI;;EAEJ;;EAEA;;EAEA;;;UAIgB;;EAEhB,QAAQ;;;;;;;;;;;cAYI,6BAA6B;WACvB;;;;;;;;;;UAWF;;EAEhB,UAAU;;EAEV,SAAS,kBAAkB;;;UAIX,OAChB;WAA2B;WAAuB;WAAqB;;;WAG9D,QAAQ,OAAO;;WAEf,UAAU,OAAO,iBAAiB;;WAElC,gBAAgB;;;;;;;;;;EAUzB,OAAO,iBAAiB;;;;;;;;;;;;;;;;EAgBxB,YAAY,gBAAgB,UAAU,qBAAqB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCpD,mBAAmB,sBAAsB,kBACxD,MAAM,OACJ,OAAO,cAAc"}
|