@resq-systems/email-templates 0.3.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/README.md +236 -0
- package/lib/contract.d.ts +125 -0
- package/lib/contract.d.ts.map +1 -0
- package/lib/contract.js +29 -0
- package/lib/contract.js.map +1 -0
- package/lib/emails/incident-alert.d.ts +8 -0
- package/lib/emails/incident-alert.d.ts.map +1 -0
- package/lib/emails/incident-alert.js +44 -0
- package/lib/emails/incident-alert.js.map +1 -0
- package/lib/emails/index.d.ts +13 -0
- package/lib/emails/index.js +13 -0
- package/lib/emails/mission-approval.d.ts +8 -0
- package/lib/emails/mission-approval.d.ts.map +1 -0
- package/lib/emails/mission-approval.js +46 -0
- package/lib/emails/mission-approval.js.map +1 -0
- package/lib/emails/new-device-login.d.ts +8 -0
- package/lib/emails/new-device-login.d.ts.map +1 -0
- package/lib/emails/new-device-login.js +47 -0
- package/lib/emails/new-device-login.js.map +1 -0
- package/lib/emails/notification.d.ts +8 -0
- package/lib/emails/notification.d.ts.map +1 -0
- package/lib/emails/notification.js +33 -0
- package/lib/emails/notification.js.map +1 -0
- package/lib/emails/org-invitation.d.ts +8 -0
- package/lib/emails/org-invitation.d.ts.map +1 -0
- package/lib/emails/org-invitation.js +41 -0
- package/lib/emails/org-invitation.js.map +1 -0
- package/lib/emails/otp.d.ts +11 -0
- package/lib/emails/otp.d.ts.map +1 -0
- package/lib/emails/otp.js +37 -0
- package/lib/emails/otp.js.map +1 -0
- package/lib/emails/password-changed.d.ts +8 -0
- package/lib/emails/password-changed.d.ts.map +1 -0
- package/lib/emails/password-changed.js +36 -0
- package/lib/emails/password-changed.js.map +1 -0
- package/lib/emails/password-reset.d.ts +8 -0
- package/lib/emails/password-reset.d.ts.map +1 -0
- package/lib/emails/password-reset.js +37 -0
- package/lib/emails/password-reset.js.map +1 -0
- package/lib/emails/primitives.d.ts +94 -0
- package/lib/emails/primitives.d.ts.map +1 -0
- package/lib/emails/primitives.js +233 -0
- package/lib/emails/primitives.js.map +1 -0
- package/lib/emails/theme.d.ts +89 -0
- package/lib/emails/theme.d.ts.map +1 -0
- package/lib/emails/theme.js +93 -0
- package/lib/emails/theme.js.map +1 -0
- package/lib/emails/tokens.d.ts +65 -0
- package/lib/emails/tokens.d.ts.map +1 -0
- package/lib/emails/tokens.js +46 -0
- package/lib/emails/tokens.js.map +1 -0
- package/lib/emails/welcome.d.ts +8 -0
- package/lib/emails/welcome.d.ts.map +1 -0
- package/lib/emails/welcome.js +32 -0
- package/lib/emails/welcome.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +8 -0
- package/lib/mailer.d.ts +89 -0
- package/lib/mailer.d.ts.map +1 -0
- package/lib/mailer.js +85 -0
- package/lib/mailer.js.map +1 -0
- package/lib/node_modules/@react-email/tailwind/dist/index.d.ts +9 -0
- package/lib/node_modules/@react-email/tailwind/dist/index.d.ts.map +1 -0
- package/lib/node_modules/tailwindcss/dist/colors.d.ts +349 -0
- package/lib/node_modules/tailwindcss/dist/colors.d.ts.map +1 -0
- package/lib/node_modules/tailwindcss/dist/lib.d.ts +6 -0
- package/lib/node_modules/tailwindcss/dist/lib.d.ts.map +1 -0
- package/lib/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts +29 -0
- package/lib/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts.map +1 -0
- package/lib/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts +126 -0
- package/lib/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts.map +1 -0
- package/lib/registry.d.ts +25 -0
- package/lib/registry.d.ts.map +1 -0
- package/lib/registry.js +26 -0
- package/lib/registry.js.map +1 -0
- package/lib/render.d.ts +13 -0
- package/lib/render.d.ts.map +1 -0
- package/lib/render.js +29 -0
- package/lib/render.js.map +1 -0
- package/lib/schemas.d.ts +86 -0
- package/lib/schemas.d.ts.map +1 -0
- package/lib/schemas.js +104 -0
- package/lib/schemas.js.map +1 -0
- package/lib/send/index.d.ts +4 -0
- package/lib/send/index.js +3 -0
- package/lib/send/resend-sender.d.ts +14 -0
- package/lib/send/resend-sender.d.ts.map +1 -0
- package/lib/send/resend-sender.js +76 -0
- package/lib/send/resend-sender.js.map +1 -0
- package/lib/send/send-email.d.ts +19 -0
- package/lib/send/send-email.d.ts.map +1 -0
- package/lib/send/send-email.js +67 -0
- package/lib/send/send-email.js.map +1 -0
- package/lib/send/sender.d.ts +58 -0
- package/lib/send/sender.d.ts.map +1 -0
- package/lib/send/sender.js +0 -0
- package/lib/suite.d.ts +130 -0
- package/lib/suite.d.ts.map +1 -0
- package/lib/suite.js +28 -0
- package/lib/suite.js.map +1 -0
- package/lib/templates.d.ts +131 -0
- package/lib/templates.d.ts.map +1 -0
- package/lib/templates.js +98 -0
- package/lib/templates.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { TailwindConfig } from "../node_modules/@react-email/tailwind/dist/index.js";
|
|
2
|
+
import { EmailCategory } from "../schemas.js";
|
|
3
|
+
import { ReactElement } from "react";
|
|
4
|
+
//#region src/emails/theme.d.ts
|
|
5
|
+
interface EmailThemeFonts {
|
|
6
|
+
display: string[];
|
|
7
|
+
sans: string[];
|
|
8
|
+
mono: string[];
|
|
9
|
+
}
|
|
10
|
+
/** Organization identity rendered into email chrome (header, signature, footer). */
|
|
11
|
+
interface EmailOrgIdentity {
|
|
12
|
+
brandName: string;
|
|
13
|
+
productName: string;
|
|
14
|
+
legalName: string;
|
|
15
|
+
registeredAddress: string;
|
|
16
|
+
supportEmail: string;
|
|
17
|
+
websiteUrl: string;
|
|
18
|
+
termsUrl: string;
|
|
19
|
+
privacyUrl: string;
|
|
20
|
+
logoUrl: string;
|
|
21
|
+
}
|
|
22
|
+
/** The full, resolved theme every template renders against. */
|
|
23
|
+
interface EmailTheme {
|
|
24
|
+
/** Color tokens → Tailwind `theme.extend.colors` (email-safe hex). */
|
|
25
|
+
colors: Record<string, string>;
|
|
26
|
+
/** Font stacks → Tailwind `theme.extend.fontFamily` (pre-quoted multi-word names). */
|
|
27
|
+
fonts: EmailThemeFonts;
|
|
28
|
+
/** Organization identity for header lockup, signatures, and legal footer. */
|
|
29
|
+
org: EmailOrgIdentity;
|
|
30
|
+
/** Optional stylesheet `<link>` injected in `<Head>` for brand webfonts. */
|
|
31
|
+
fontsHref?: string;
|
|
32
|
+
}
|
|
33
|
+
/** A partial theme a consumer supplies to rebrand; unset keys fall back to the base. */
|
|
34
|
+
interface EmailThemeOverride {
|
|
35
|
+
colors?: Record<string, string>;
|
|
36
|
+
fonts?: Partial<EmailThemeFonts>;
|
|
37
|
+
/** Override organization identity fields (shallow-merged over the base). */
|
|
38
|
+
org?: Partial<EmailOrgIdentity>;
|
|
39
|
+
/** Pass `null` to drop the webfont link entirely. */
|
|
40
|
+
fontsHref?: string | null;
|
|
41
|
+
}
|
|
42
|
+
/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */
|
|
43
|
+
declare const defaultEmailTheme: EmailTheme;
|
|
44
|
+
/** Merge an override onto a base theme (colors/fonts shallow-merge; `fontsHref: null` removes it). */
|
|
45
|
+
declare function resolveEmailTheme(base: EmailTheme, override?: EmailThemeOverride): EmailTheme;
|
|
46
|
+
/** Merge an override onto the default ResQ Systems theme. */
|
|
47
|
+
declare function mergeEmailTheme(override?: EmailThemeOverride): EmailTheme;
|
|
48
|
+
/** Build the `<Tailwind config>` object from a resolved theme. */
|
|
49
|
+
declare function buildTailwindConfig(theme: EmailTheme): {
|
|
50
|
+
presets: TailwindConfig[];
|
|
51
|
+
theme: {
|
|
52
|
+
extend: {
|
|
53
|
+
colors: {
|
|
54
|
+
[x: string]: string;
|
|
55
|
+
};
|
|
56
|
+
fontFamily: {
|
|
57
|
+
display: string[];
|
|
58
|
+
sans: string[];
|
|
59
|
+
mono: string[];
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
/** Context carrying the active theme; defaults to the ResQ Systems brand. */
|
|
65
|
+
declare const EmailThemeContext: import("react").Context<EmailTheme>;
|
|
66
|
+
/**
|
|
67
|
+
* Wrap an element so it renders against a theme override (used by `renderEmail`).
|
|
68
|
+
* Returns the element unchanged when there is no override, so the default theme
|
|
69
|
+
* flows through context.
|
|
70
|
+
*/
|
|
71
|
+
declare function withEmailTheme(element: ReactElement, override?: EmailThemeOverride): ReactElement;
|
|
72
|
+
/** Per-send message policy carried through context to the legal footer. */
|
|
73
|
+
interface EmailMessage {
|
|
74
|
+
/** Compliance class; defaults to `transactional`. */
|
|
75
|
+
category: EmailCategory;
|
|
76
|
+
/** Where the unsubscribe/preferences link points (used for `marketing`). */
|
|
77
|
+
unsubscribeUrl?: string;
|
|
78
|
+
}
|
|
79
|
+
/** Context carrying the active message policy; defaults to a transactional send. */
|
|
80
|
+
declare const EmailMessageContext: import("react").Context<EmailMessage>;
|
|
81
|
+
/**
|
|
82
|
+
* Wrap an element so it renders against a message policy (used by `renderEmail`).
|
|
83
|
+
* Returns the element unchanged when no message is given, so the default
|
|
84
|
+
* transactional policy flows through context.
|
|
85
|
+
*/
|
|
86
|
+
declare function withEmailMessage(element: ReactElement, message?: EmailMessage): ReactElement;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { EmailMessage, EmailMessageContext, EmailOrgIdentity, EmailTheme, EmailThemeContext, EmailThemeFonts, EmailThemeOverride, buildTailwindConfig, defaultEmailTheme, mergeEmailTheme, resolveEmailTheme, withEmailMessage, withEmailTheme };
|
|
89
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","names":[],"sources":["../../src/emails/theme.tsx"],"mappings":";;;;UAqBiB;EAChB;EACA;EACA;;;UAIgB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIgB;;EAEhB,QAAQ;;EAER,OAAO;;EAEP,KAAK;;EAEL;;;UAIgB;EAChB,SAAS;EACT,QAAQ,QAAQ;;EAEhB,MAAM,QAAQ;;EAEd;;;cAIY,mBAAmB;;iBAYhB,kBAAkB,MAAM,YAAY,WAAW,qBAAqB;;iBAWpE,gBAAgB,WAAW,qBAAqB;;iBAKhD,oBAAoB,OAAO;WAAA;;;;;;;QAOtC;QACA;QACA;;;;;;cAQQ,mCAAiB,QAAA;;;;;;iBAOd,eAAe,SAAS,cAAc,WAAW,qBAAqB;;UAMrE;;EAEhB,UAAU;;EAEV;;;cAIY,qCAAmB,QAAA;;;;;;iBAOhB,iBAAiB,SAAS,cAAc,UAAU,eAAe"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { emailColors, emailFonts, emailOrg } from "./tokens.js";
|
|
2
|
+
import { pixelBasedPreset } from "@react-email/components";
|
|
3
|
+
import { createContext, createElement } from "react";
|
|
4
|
+
//#region src/emails/theme.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
* you may not use this file except in compliance with the License.
|
|
10
|
+
* You may obtain a copy of the License at
|
|
11
|
+
*
|
|
12
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/
|
|
20
|
+
/** The default ResQ Systems brand theme (dark-first, red primary, Syne/DM Sans/DM Mono). */
|
|
21
|
+
const defaultEmailTheme = {
|
|
22
|
+
colors: { ...emailColors },
|
|
23
|
+
fonts: {
|
|
24
|
+
display: [...emailFonts.stacks.display],
|
|
25
|
+
sans: [...emailFonts.stacks.body],
|
|
26
|
+
mono: [...emailFonts.stacks.mono]
|
|
27
|
+
},
|
|
28
|
+
org: { ...emailOrg },
|
|
29
|
+
fontsHref: emailFonts.googleFontsHref
|
|
30
|
+
};
|
|
31
|
+
/** Merge an override onto a base theme (colors/fonts shallow-merge; `fontsHref: null` removes it). */
|
|
32
|
+
function resolveEmailTheme(base, override) {
|
|
33
|
+
if (!override) return base;
|
|
34
|
+
return {
|
|
35
|
+
colors: {
|
|
36
|
+
...base.colors,
|
|
37
|
+
...override.colors
|
|
38
|
+
},
|
|
39
|
+
fonts: {
|
|
40
|
+
...base.fonts,
|
|
41
|
+
...override.fonts
|
|
42
|
+
},
|
|
43
|
+
org: {
|
|
44
|
+
...base.org,
|
|
45
|
+
...override.org
|
|
46
|
+
},
|
|
47
|
+
fontsHref: override.fontsHref === null ? void 0 : override.fontsHref ?? base.fontsHref
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Merge an override onto the default ResQ Systems theme. */
|
|
51
|
+
function mergeEmailTheme(override) {
|
|
52
|
+
return resolveEmailTheme(defaultEmailTheme, override);
|
|
53
|
+
}
|
|
54
|
+
/** Build the `<Tailwind config>` object from a resolved theme. */
|
|
55
|
+
function buildTailwindConfig(theme) {
|
|
56
|
+
return {
|
|
57
|
+
presets: [pixelBasedPreset],
|
|
58
|
+
theme: { extend: {
|
|
59
|
+
colors: { ...theme.colors },
|
|
60
|
+
fontFamily: {
|
|
61
|
+
display: [...theme.fonts.display],
|
|
62
|
+
sans: [...theme.fonts.sans],
|
|
63
|
+
mono: [...theme.fonts.mono]
|
|
64
|
+
}
|
|
65
|
+
} }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Context carrying the active theme; defaults to the ResQ Systems brand. */
|
|
69
|
+
const EmailThemeContext = createContext(defaultEmailTheme);
|
|
70
|
+
/**
|
|
71
|
+
* Wrap an element so it renders against a theme override (used by `renderEmail`).
|
|
72
|
+
* Returns the element unchanged when there is no override, so the default theme
|
|
73
|
+
* flows through context.
|
|
74
|
+
*/
|
|
75
|
+
function withEmailTheme(element, override) {
|
|
76
|
+
if (!override) return element;
|
|
77
|
+
return createElement(EmailThemeContext.Provider, { value: mergeEmailTheme(override) }, element);
|
|
78
|
+
}
|
|
79
|
+
/** Context carrying the active message policy; defaults to a transactional send. */
|
|
80
|
+
const EmailMessageContext = createContext({ category: "transactional" });
|
|
81
|
+
/**
|
|
82
|
+
* Wrap an element so it renders against a message policy (used by `renderEmail`).
|
|
83
|
+
* Returns the element unchanged when no message is given, so the default
|
|
84
|
+
* transactional policy flows through context.
|
|
85
|
+
*/
|
|
86
|
+
function withEmailMessage(element, message) {
|
|
87
|
+
if (!message) return element;
|
|
88
|
+
return createElement(EmailMessageContext.Provider, { value: message }, element);
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { EmailMessageContext, EmailThemeContext, buildTailwindConfig, defaultEmailTheme, mergeEmailTheme, resolveEmailTheme, withEmailMessage, withEmailTheme };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/emails/tokens.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Email-safe hex color tokens, sourced from the shared `@resq-systems/constants`
|
|
19
|
+
* design tokens so the brand palette lives in one place across apps. Email
|
|
20
|
+
* clients don't support `oklch()`, so the hex snapshot is used here.
|
|
21
|
+
*/
|
|
22
|
+
declare const emailColors: {
|
|
23
|
+
readonly background: "#0A0E1A";
|
|
24
|
+
readonly surface: "#171C2B";
|
|
25
|
+
readonly border: "#1E2438";
|
|
26
|
+
readonly foreground: "#F0F2FA";
|
|
27
|
+
readonly muted: "#7D8CAE";
|
|
28
|
+
readonly primary: "#D43E3F";
|
|
29
|
+
readonly info: "#7D8CAE";
|
|
30
|
+
readonly success: "#3FB984";
|
|
31
|
+
readonly warning: "#E0A100";
|
|
32
|
+
readonly danger: "#D43E3F";
|
|
33
|
+
};
|
|
34
|
+
/** Brand font stacks + webfont stylesheet href, from the shared design tokens. */
|
|
35
|
+
declare const emailFonts: {
|
|
36
|
+
readonly display: "Syne";
|
|
37
|
+
readonly body: "DM Sans";
|
|
38
|
+
readonly mono: "DM Mono";
|
|
39
|
+
readonly stacks: {
|
|
40
|
+
readonly display: readonly ["Syne", "'Helvetica Neue'", "Arial", "sans-serif"];
|
|
41
|
+
readonly body: readonly ["'DM Sans'", "-apple-system", "BlinkMacSystemFont", "'Segoe UI'", "Roboto", "Helvetica", "Arial", "sans-serif"];
|
|
42
|
+
readonly mono: readonly ["'DM Mono'", "ui-monospace", "'SF Mono'", "Menlo", "Consolas", "monospace"];
|
|
43
|
+
};
|
|
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
|
+
};
|
|
46
|
+
type EmailColorToken = keyof typeof emailColors;
|
|
47
|
+
/**
|
|
48
|
+
* Organization identity for email chrome (header lockup, signatures, legal
|
|
49
|
+
* footer), derived from the shared `@resq-systems/constants` brand so names,
|
|
50
|
+
* addresses, and legal URLs live in one place across apps.
|
|
51
|
+
*/
|
|
52
|
+
declare const emailOrg: {
|
|
53
|
+
readonly brandName: "ResQ Systems";
|
|
54
|
+
readonly productName: "ResQ Tactical OS";
|
|
55
|
+
readonly legalName: "ResQ Systems, Inc.";
|
|
56
|
+
readonly registeredAddress: "ResQ Systems, Inc., 131 Continental Dr, Suite 305, Newark, DE 19713, USA";
|
|
57
|
+
readonly supportEmail: "support@resq.software";
|
|
58
|
+
readonly websiteUrl: "https://resq.software";
|
|
59
|
+
readonly termsUrl: "https://resq.software/legal/terms";
|
|
60
|
+
readonly privacyUrl: "https://resq.software/legal/privacy";
|
|
61
|
+
readonly logoUrl: "https://resq.software/logo.png";
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { EmailColorToken, emailColors, emailFonts, emailOrg };
|
|
65
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","names":[],"sources":["../../src/emails/tokens.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;cAwBa;;;;;;;;;;;;;cAGA;;;;;;;;;;;KAED,+BAA+B;;;;;;cAO9B;WACZ;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { brand } from "@resq-systems/constants/brand";
|
|
2
|
+
import { colors, fonts } from "@resq-systems/constants/tokens";
|
|
3
|
+
//#region src/emails/tokens.ts
|
|
4
|
+
/**
|
|
5
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Email-safe hex color tokens, sourced from the shared `@resq-systems/constants`
|
|
21
|
+
* design tokens so the brand palette lives in one place across apps. Email
|
|
22
|
+
* clients don't support `oklch()`, so the hex snapshot is used here.
|
|
23
|
+
*/
|
|
24
|
+
const emailColors = colors.hex;
|
|
25
|
+
/** Brand font stacks + webfont stylesheet href, from the shared design tokens. */
|
|
26
|
+
const emailFonts = fonts;
|
|
27
|
+
/**
|
|
28
|
+
* Organization identity for email chrome (header lockup, signatures, legal
|
|
29
|
+
* footer), derived from the shared `@resq-systems/constants` brand so names,
|
|
30
|
+
* addresses, and legal URLs live in one place across apps.
|
|
31
|
+
*/
|
|
32
|
+
const emailOrg = {
|
|
33
|
+
brandName: brand.name,
|
|
34
|
+
productName: brand.productName,
|
|
35
|
+
legalName: brand.legalName,
|
|
36
|
+
registeredAddress: brand.postalAddress,
|
|
37
|
+
supportEmail: brand.email.support,
|
|
38
|
+
websiteUrl: brand.domains.marketing,
|
|
39
|
+
termsUrl: brand.legal.termsUrl,
|
|
40
|
+
privacyUrl: brand.legal.privacyUrl,
|
|
41
|
+
logoUrl: brand.logo
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { emailColors, emailFonts, emailOrg };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,cAAc,OAAO;;AAGlC,MAAa,aAAa;;;;;;AAS1B,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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WelcomeData } from "../schemas.js";
|
|
2
|
+
//#region src/emails/welcome.d.ts
|
|
3
|
+
type WelcomeEmailProps = WelcomeData;
|
|
4
|
+
/** Account welcome / onboarding email. */
|
|
5
|
+
declare function WelcomeEmail({ firstName, verifyUrl }: WelcomeEmailProps): import("react").JSX.Element;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { WelcomeEmail, WelcomeEmailProps };
|
|
8
|
+
//# sourceMappingURL=welcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"welcome.d.ts","names":[],"sources":["../../src/emails/welcome.tsx"],"mappings":";;KAmBY,oBAAoB;;iBAGhB,eAAe,WAAqB,aAAa,oCAAiB,IAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Email } from "./primitives.js";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/emails/welcome.tsx
|
|
4
|
+
/** Account welcome / onboarding email. */
|
|
5
|
+
function WelcomeEmail({ firstName = "there", verifyUrl }) {
|
|
6
|
+
return /* @__PURE__ */ jsxs(Email.Shell, {
|
|
7
|
+
preview: `Welcome to ResQ Systems, ${firstName}`,
|
|
8
|
+
children: [
|
|
9
|
+
/* @__PURE__ */ jsx(Email.Header, {}),
|
|
10
|
+
/* @__PURE__ */ jsx(Email.Title, { children: "Welcome to ResQ Systems" }),
|
|
11
|
+
/* @__PURE__ */ jsxs(Email.Paragraph, { children: [
|
|
12
|
+
"Hi ",
|
|
13
|
+
firstName,
|
|
14
|
+
","
|
|
15
|
+
] }),
|
|
16
|
+
/* @__PURE__ */ jsx(Email.Paragraph, { children: "Thanks for creating an account. Everything is set up and ready when you are." }),
|
|
17
|
+
verifyUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Email.Paragraph, { children: "Confirm your email address to finish setting up your account." }), /* @__PURE__ */ jsx(Email.CTA, {
|
|
18
|
+
href: verifyUrl,
|
|
19
|
+
children: "Verify email"
|
|
20
|
+
})] }) : null,
|
|
21
|
+
/* @__PURE__ */ jsx(Email.Signature, {}),
|
|
22
|
+
/* @__PURE__ */ jsx(Email.LegalFooter, {
|
|
23
|
+
category: "transactional",
|
|
24
|
+
reason: "You are receiving this email because you created a ResQ Systems account."
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { WelcomeEmail };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=welcome.js.map
|
|
@@ -0,0 +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":";;;;AAsBA,SAAgB,aAAa,EAAE,YAAY,SAAS,aAAgC;CACnF,OACC,qBAAC,MAAM,OAAP;EAAa,SAAS,4BAA4B;YAAlD;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;cAAW;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
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EmailCategory, HttpUrl, IncidentAlertData, MissionApprovalData, NewDeviceLoginData, NotificationData, OrgInvitationData, OtpData, PasswordChangedData, PasswordResetData, WelcomeData, emailCategory, incidentAlertData, missionApprovalData, newDeviceLoginData, notificationData, orgInvitationData, otpData, passwordChangedData, passwordResetData, welcomeData } from "./schemas.js";
|
|
2
|
+
import { EmailMessage, EmailMessageContext, EmailOrgIdentity, EmailTheme, EmailThemeContext, EmailThemeFonts, EmailThemeOverride, buildTailwindConfig, defaultEmailTheme, mergeEmailTheme, resolveEmailTheme, withEmailMessage, withEmailTheme } from "./emails/theme.js";
|
|
3
|
+
import { EmailRegistryEntry, EmailTemplateDef, EmailValidationError, Mailer, MailerPayload, MailerTemplateData, RenderEmailOptions, RenderedEmail, createMailer, defineEmailTemplate } from "./mailer.js";
|
|
4
|
+
import { EmailName, EmailPayload, EmailTemplateData, decodeEmailPayload } from "./contract.js";
|
|
5
|
+
import { registry } from "./registry.js";
|
|
6
|
+
import { renderEmail } from "./render.js";
|
|
7
|
+
import { incidentAlertTemplate, missionApprovalTemplate, newDeviceLoginTemplate, notificationTemplate, orgInvitationTemplate, otpTemplate, passwordChangedTemplate, passwordResetTemplate, resqEmailTemplates, welcomeTemplate } from "./templates.js";
|
|
8
|
+
export { 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 };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EmailMessageContext, EmailThemeContext, buildTailwindConfig, defaultEmailTheme, mergeEmailTheme, resolveEmailTheme, withEmailMessage, withEmailTheme } from "./emails/theme.js";
|
|
2
|
+
import { HttpUrl, emailCategory, incidentAlertData, missionApprovalData, newDeviceLoginData, notificationData, orgInvitationData, otpData, passwordChangedData, passwordResetData, welcomeData } from "./schemas.js";
|
|
3
|
+
import { EmailValidationError, createMailer, defineEmailTemplate } from "./mailer.js";
|
|
4
|
+
import { incidentAlertTemplate, missionApprovalTemplate, newDeviceLoginTemplate, notificationTemplate, orgInvitationTemplate, otpTemplate, passwordChangedTemplate, passwordResetTemplate, resqEmailTemplates, welcomeTemplate } from "./templates.js";
|
|
5
|
+
import { EmailPayload, decodeEmailPayload } from "./contract.js";
|
|
6
|
+
import { registry } from "./registry.js";
|
|
7
|
+
import { renderEmail } from "./render.js";
|
|
8
|
+
export { EmailMessageContext, EmailPayload, EmailThemeContext, EmailValidationError, HttpUrl, 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
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { EmailThemeOverride } from "./emails/theme.js";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import { ReactElement } from "react";
|
|
4
|
+
//#region src/mailer.d.ts
|
|
5
|
+
/** A template definition: its name, `data` schema, subject line, and component. */
|
|
6
|
+
interface EmailTemplateDef<Name extends string, DataSchema extends Schema.Top> {
|
|
7
|
+
readonly name: Name;
|
|
8
|
+
readonly data: DataSchema;
|
|
9
|
+
readonly subject: (data: DataSchema["Type"]) => string;
|
|
10
|
+
readonly Component: (data: DataSchema["Type"]) => ReactElement;
|
|
11
|
+
}
|
|
12
|
+
/** Identity helper that infers and preserves a template def's literal types. */
|
|
13
|
+
declare function defineEmailTemplate<const Name extends string, DataSchema extends Schema.Top>(def: EmailTemplateDef<Name, DataSchema>): EmailTemplateDef<Name, DataSchema>;
|
|
14
|
+
/**
|
|
15
|
+
* The common supertype for a heterogeneous list of template defs. The `never`
|
|
16
|
+
* parameters make every concrete `EmailTemplateDef<Name, DataSchema>` assignable
|
|
17
|
+
* here (function parameters are contravariant), so defs with different `data`
|
|
18
|
+
* types can live in one array.
|
|
19
|
+
*/
|
|
20
|
+
interface AnyTemplateDef {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly data: Schema.Top;
|
|
23
|
+
readonly subject: (data: never) => string;
|
|
24
|
+
readonly Component: (data: never) => ReactElement;
|
|
25
|
+
}
|
|
26
|
+
/** The `{ name, to, data, category?, unsubscribeUrl? }` payload for a single template def. */
|
|
27
|
+
type PayloadFor<Def> = Def extends EmailTemplateDef<infer Name, infer DataSchema> ? {
|
|
28
|
+
readonly name: Name;
|
|
29
|
+
readonly to: string;
|
|
30
|
+
readonly data: DataSchema["Type"];
|
|
31
|
+
/** Compliance class for this send; defaults to `transactional`. */
|
|
32
|
+
readonly category?: "transactional" | "marketing";
|
|
33
|
+
/** Unsubscribe/preferences URL, surfaced in the legal footer for `marketing`. */
|
|
34
|
+
readonly unsubscribeUrl?: string;
|
|
35
|
+
} : never;
|
|
36
|
+
/** The discriminated payload union for a tuple of template defs. */
|
|
37
|
+
type MailerPayload<Defs extends readonly AnyTemplateDef[]> = PayloadFor<Defs[number]>;
|
|
38
|
+
/** The `data` type for a given template name within a set of defs. */
|
|
39
|
+
type MailerTemplateData<Defs extends readonly AnyTemplateDef[], Name extends MailerPayload<Defs>["name"]> = Extract<MailerPayload<Defs>, {
|
|
40
|
+
name: Name;
|
|
41
|
+
}>["data"];
|
|
42
|
+
/** The rendered, provider-ready email. */
|
|
43
|
+
interface RenderedEmail {
|
|
44
|
+
to: string;
|
|
45
|
+
subject: string;
|
|
46
|
+
html: string;
|
|
47
|
+
text: string;
|
|
48
|
+
}
|
|
49
|
+
/** Options for a mailer's `renderEmail`. */
|
|
50
|
+
interface RenderEmailOptions {
|
|
51
|
+
/** Rebrand this render by overriding theme colors/fonts (see `EmailThemeOverride`). */
|
|
52
|
+
theme?: EmailThemeOverride;
|
|
53
|
+
}
|
|
54
|
+
/** Thrown when an untrusted payload fails schema validation at the boundary. */
|
|
55
|
+
declare class EmailValidationError extends Error {
|
|
56
|
+
readonly name = "EmailValidationError";
|
|
57
|
+
}
|
|
58
|
+
/** A registry entry: the subject builder and component renderer for one template. */
|
|
59
|
+
interface EmailRegistryEntry {
|
|
60
|
+
subject: (data: unknown) => string;
|
|
61
|
+
render: (data: unknown) => ReactElement;
|
|
62
|
+
}
|
|
63
|
+
/** A composed set of templates: contract schema, decoder, registry, and renderer. */
|
|
64
|
+
interface Mailer<Payload extends {
|
|
65
|
+
readonly name: string;
|
|
66
|
+
readonly to: string;
|
|
67
|
+
readonly data: unknown;
|
|
68
|
+
}> {
|
|
69
|
+
/** The Effect Schema union describing every `{ name, to, data }` payload. */
|
|
70
|
+
readonly schema: Schema.Top;
|
|
71
|
+
/** name → { subject, render } for every template. */
|
|
72
|
+
readonly registry: Record<Payload["name"], EmailRegistryEntry>;
|
|
73
|
+
/** Every registered template name. */
|
|
74
|
+
readonly names: readonly Payload["name"][];
|
|
75
|
+
/** Validate an untrusted payload (throws {@link EmailValidationError}). */
|
|
76
|
+
decode(input: unknown): Payload;
|
|
77
|
+
/** Validate then render to `{ to, subject, html, text }` (headless, pipeline-safe). */
|
|
78
|
+
renderEmail(input: unknown, options?: RenderEmailOptions): Promise<RenderedEmail>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Compose template definitions into a typed mailer: a discriminated
|
|
82
|
+
* `{ name, to, data }` contract, a boundary decoder, a registry, and a headless
|
|
83
|
+
* renderer. Spread the built-in `resqEmailTemplates` and add your own — each
|
|
84
|
+
* template's `data` is validated by its Effect Schema.
|
|
85
|
+
*/
|
|
86
|
+
declare function createMailer<const Defs extends readonly AnyTemplateDef[]>(defs: Defs): Mailer<MailerPayload<Defs>>;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { EmailRegistryEntry, EmailTemplateDef, EmailValidationError, Mailer, MailerPayload, MailerTemplateData, RenderEmailOptions, RenderedEmail, createMailer, defineEmailTemplate };
|
|
89
|
+
//# sourceMappingURL=mailer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.d.ts","names":[],"sources":["../src/mailer.tsx"],"mappings":";;;;;UA8BiB,iBAAiB,qBAAqB,mBAAmB,OAAO;WACvE,MAAM;WACN,MAAM;WACN,UAAU,MAAM;WAChB,YAAY,MAAM,uBAAuB;;;iBAInC,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;WACA,MAAM;;WAEN;;WAEA;;;KAKD,cAAc,sBAAsB,oBAAoB,WAAW;;KAGnE,mBACX,sBAAsB,kBACtB,aAAa,cAAc,iBACxB,QAAQ,cAAc;EAAS,MAAM;;;UAGxB;EAChB;EACA;EACA;EACA;;;UAIgB;;EAEhB,QAAQ;;;cAII,6BAA6B;WACvB;;;UAIF;EAChB,UAAU;EACV,SAAS,kBAAkB;;;UAIX,OAChB;WAA2B;WAAuB;WAAqB;;;WAG9D,QAAQ,OAAO;;WAEf,UAAU,OAAO,iBAAiB;;WAElC,gBAAgB;;EAEzB,OAAO,iBAAiB;;EAExB,YAAY,gBAAgB,UAAU,qBAAqB,QAAQ;;;;;;;;iBASpD,mBAAmB,sBAAsB,kBACxD,MAAM,OACJ,OAAO,cAAc"}
|
package/lib/mailer.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { withEmailMessage, withEmailTheme } from "./emails/theme.js";
|
|
2
|
+
import { HttpUrl, emailCategory } from "./schemas.js";
|
|
3
|
+
import { render } from "@react-email/render";
|
|
4
|
+
import { Cause, Exit, Schema } from "effect";
|
|
5
|
+
//#region src/mailer.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
const Recipient = Schema.String;
|
|
22
|
+
/** Identity helper that infers and preserves a template def's literal types. */
|
|
23
|
+
function defineEmailTemplate(def) {
|
|
24
|
+
return def;
|
|
25
|
+
}
|
|
26
|
+
/** Thrown when an untrusted payload fails schema validation at the boundary. */
|
|
27
|
+
var EmailValidationError = class extends Error {
|
|
28
|
+
name = "EmailValidationError";
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Compose template definitions into a typed mailer: a discriminated
|
|
32
|
+
* `{ name, to, data }` contract, a boundary decoder, a registry, and a headless
|
|
33
|
+
* renderer. Spread the built-in `resqEmailTemplates` and add your own — each
|
|
34
|
+
* template's `data` is validated by its Effect Schema.
|
|
35
|
+
*/
|
|
36
|
+
function createMailer(defs) {
|
|
37
|
+
const schema = Schema.Union(defs.map((def) => Schema.Struct({
|
|
38
|
+
name: Schema.Literal(def.name),
|
|
39
|
+
to: Recipient,
|
|
40
|
+
data: def.data,
|
|
41
|
+
category: Schema.optional(emailCategory),
|
|
42
|
+
unsubscribeUrl: Schema.optional(HttpUrl)
|
|
43
|
+
})));
|
|
44
|
+
const registry = Object.fromEntries(defs.map((def) => [def.name, {
|
|
45
|
+
subject: def.subject,
|
|
46
|
+
render: def.Component
|
|
47
|
+
}]));
|
|
48
|
+
const names = defs.map((def) => def.name);
|
|
49
|
+
const decodeExit = Schema.decodeUnknownExit(schema);
|
|
50
|
+
function decode(input) {
|
|
51
|
+
const result = decodeExit(input);
|
|
52
|
+
if (Exit.isFailure(result)) {
|
|
53
|
+
const squashed = Cause.squash(result.cause);
|
|
54
|
+
throw new EmailValidationError(squashed instanceof Error ? squashed.message : String(squashed));
|
|
55
|
+
}
|
|
56
|
+
return result.value;
|
|
57
|
+
}
|
|
58
|
+
async function renderEmail(input, options) {
|
|
59
|
+
const payload = decode(input);
|
|
60
|
+
const entry = registry[payload.name];
|
|
61
|
+
const message = {
|
|
62
|
+
category: payload.category ?? "transactional",
|
|
63
|
+
unsubscribeUrl: payload.unsubscribeUrl
|
|
64
|
+
};
|
|
65
|
+
const element = withEmailMessage(withEmailTheme(entry.render(payload.data), options?.theme), message);
|
|
66
|
+
const [html, text] = await Promise.all([render(element), render(element, { plainText: true })]);
|
|
67
|
+
return {
|
|
68
|
+
to: payload.to,
|
|
69
|
+
subject: entry.subject(payload.data),
|
|
70
|
+
html,
|
|
71
|
+
text
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
schema,
|
|
76
|
+
registry,
|
|
77
|
+
names,
|
|
78
|
+
decode,
|
|
79
|
+
renderEmail
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { EmailValidationError, createMailer, defineEmailTemplate };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=mailer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailer.js","names":[],"sources":["../src/mailer.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 { render } from \"@react-email/render\";\nimport { Cause, Exit, Schema } from \"effect\";\nimport type { ReactElement } from \"react\";\nimport {\n\ttype EmailMessage,\n\ttype EmailThemeOverride,\n\twithEmailMessage,\n\twithEmailTheme,\n} from \"./emails/theme.js\";\nimport { HttpUrl, emailCategory } from \"./schemas.js\";\n\nconst Recipient = Schema.String;\n\n/** A template definition: its name, `data` schema, subject line, and component. */\nexport interface EmailTemplateDef<Name extends string, DataSchema extends Schema.Top> {\n\treadonly name: Name;\n\treadonly data: DataSchema;\n\treadonly subject: (data: DataSchema[\"Type\"]) => string;\n\treadonly Component: (data: DataSchema[\"Type\"]) => ReactElement;\n}\n\n/** Identity helper that infers and preserves a template def's literal types. */\nexport function defineEmailTemplate<const Name extends string, DataSchema extends Schema.Top>(\n\tdef: EmailTemplateDef<Name, DataSchema>,\n): EmailTemplateDef<Name, DataSchema> {\n\treturn def;\n}\n\n/**\n * The common supertype for a heterogeneous list of template defs. The `never`\n * parameters make every concrete `EmailTemplateDef<Name, DataSchema>` assignable\n * here (function parameters are contravariant), so defs with different `data`\n * types can live in one array.\n */\ninterface AnyTemplateDef {\n\treadonly name: string;\n\treadonly data: Schema.Top;\n\treadonly subject: (data: never) => string;\n\treadonly Component: (data: never) => ReactElement;\n}\n\n/** The `{ name, to, data, category?, unsubscribeUrl? }` payload for a single template def. */\ntype PayloadFor<Def> =\n\tDef extends EmailTemplateDef<infer Name, infer DataSchema>\n\t\t? {\n\t\t\t\treadonly name: Name;\n\t\t\t\treadonly to: string;\n\t\t\t\treadonly data: DataSchema[\"Type\"];\n\t\t\t\t/** Compliance class for this send; defaults to `transactional`. */\n\t\t\t\treadonly category?: \"transactional\" | \"marketing\";\n\t\t\t\t/** Unsubscribe/preferences URL, surfaced in the legal footer for `marketing`. */\n\t\t\t\treadonly unsubscribeUrl?: string;\n\t\t\t}\n\t\t: never;\n\n/** The discriminated payload union for a tuple of template defs. */\nexport type MailerPayload<Defs extends readonly AnyTemplateDef[]> = PayloadFor<Defs[number]>;\n\n/** The `data` type for a given template name within a set of defs. */\nexport type MailerTemplateData<\n\tDefs extends readonly AnyTemplateDef[],\n\tName extends MailerPayload<Defs>[\"name\"],\n> = Extract<MailerPayload<Defs>, { name: Name }>[\"data\"];\n\n/** The rendered, provider-ready email. */\nexport interface RenderedEmail {\n\tto: string;\n\tsubject: string;\n\thtml: string;\n\ttext: string;\n}\n\n/** Options for a mailer's `renderEmail`. */\nexport interface RenderEmailOptions {\n\t/** Rebrand this render by overriding theme colors/fonts (see `EmailThemeOverride`). */\n\ttheme?: EmailThemeOverride;\n}\n\n/** Thrown when an untrusted payload fails schema validation at the boundary. */\nexport class EmailValidationError extends Error {\n\toverride readonly name = \"EmailValidationError\";\n}\n\n/** A registry entry: the subject builder and component renderer for one template. */\nexport interface EmailRegistryEntry {\n\tsubject: (data: unknown) => string;\n\trender: (data: unknown) => ReactElement;\n}\n\n/** A composed set of templates: contract schema, decoder, registry, and renderer. */\nexport interface Mailer<\n\tPayload extends { readonly name: string; readonly to: string; readonly data: unknown },\n> {\n\t/** The Effect Schema union describing every `{ name, to, data }` payload. */\n\treadonly schema: Schema.Top;\n\t/** name → { subject, render } for every template. */\n\treadonly registry: Record<Payload[\"name\"], EmailRegistryEntry>;\n\t/** Every registered template name. */\n\treadonly names: readonly Payload[\"name\"][];\n\t/** Validate an untrusted payload (throws {@link EmailValidationError}). */\n\tdecode(input: unknown): Payload;\n\t/** Validate then render to `{ to, subject, html, text }` (headless, pipeline-safe). */\n\trenderEmail(input: unknown, options?: RenderEmailOptions): Promise<RenderedEmail>;\n}\n\n/**\n * Compose template definitions into a typed mailer: a discriminated\n * `{ name, to, data }` contract, a boundary decoder, a registry, and a headless\n * renderer. Spread the built-in `resqEmailTemplates` and add your own — each\n * template's `data` is validated by its Effect Schema.\n */\nexport function createMailer<const Defs extends readonly AnyTemplateDef[]>(\n\tdefs: Defs,\n): Mailer<MailerPayload<Defs>> {\n\ttype Payload = MailerPayload<Defs>;\n\n\tconst schema = Schema.Union(\n\t\tdefs.map((def) =>\n\t\t\tSchema.Struct({\n\t\t\t\tname: Schema.Literal(def.name),\n\t\t\t\tto: Recipient,\n\t\t\t\tdata: def.data,\n\t\t\t\tcategory: Schema.optional(emailCategory),\n\t\t\t\tunsubscribeUrl: Schema.optional(HttpUrl),\n\t\t\t}),\n\t\t),\n\t);\n\n\t// Entries are stored with `unknown` params; the def's data type is enforced at\n\t// the call boundary by `decode`, so these casts are safe.\n\tconst registry: Record<string, EmailRegistryEntry> = Object.fromEntries(\n\t\tdefs.map((def) => [\n\t\t\tdef.name,\n\t\t\t{\n\t\t\t\tsubject: def.subject as EmailRegistryEntry[\"subject\"],\n\t\t\t\trender: def.Component as EmailRegistryEntry[\"render\"],\n\t\t\t},\n\t\t]),\n\t);\n\n\tconst names = defs.map((def) => def.name);\n\n\t// Cast past the `Decoder` services constraint: the union's fields are concrete\n\t// schemas with no decoding services at runtime.\n\tconst decodeExit = Schema.decodeUnknownExit(\n\t\tschema as unknown as Parameters<typeof Schema.decodeUnknownExit>[0],\n\t);\n\n\tfunction decode(input: unknown): Payload {\n\t\tconst result = decodeExit(input);\n\t\tif (Exit.isFailure(result)) {\n\t\t\tconst squashed = Cause.squash(result.cause);\n\t\t\tthrow new EmailValidationError(\n\t\t\t\tsquashed instanceof Error ? squashed.message : String(squashed),\n\t\t\t);\n\t\t}\n\t\treturn result.value as Payload;\n\t}\n\n\tasync function renderEmail(input: unknown, options?: RenderEmailOptions): Promise<RenderedEmail> {\n\t\tconst payload = decode(input);\n\t\tconst entry = registry[payload.name as string];\n\t\tconst message: EmailMessage = {\n\t\t\tcategory: payload.category ?? \"transactional\",\n\t\t\tunsubscribeUrl: payload.unsubscribeUrl,\n\t\t};\n\t\tconst element = withEmailMessage(\n\t\t\twithEmailTheme(entry.render(payload.data), options?.theme),\n\t\t\tmessage,\n\t\t);\n\t\tconst [html, text] = await Promise.all([render(element), render(element, { plainText: true })]);\n\t\treturn { to: payload.to, subject: entry.subject(payload.data), html, text };\n\t}\n\n\treturn {\n\t\tschema,\n\t\tregistry: registry as Record<Payload[\"name\"], EmailRegistryEntry>,\n\t\tnames: names as readonly Payload[\"name\"][],\n\t\tdecode,\n\t\trenderEmail,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,YAAY,OAAO;;AAWzB,SAAgB,oBACf,KACqC;CACrC,OAAO;AACR;;AAqDA,IAAa,uBAAb,cAA0C,MAAM;CAC/C,OAAyB;AAC1B;;;;;;;AA8BA,SAAgB,aACf,MAC8B;CAG9B,MAAM,SAAS,OAAO,MACrB,KAAK,KAAK,QACT,OAAO,OAAO;EACb,MAAM,OAAO,QAAQ,IAAI,IAAI;EAC7B,IAAI;EACJ,MAAM,IAAI;EACV,UAAU,OAAO,SAAS,aAAa;EACvC,gBAAgB,OAAO,SAAS,OAAO;CACxC,CAAC,CACF,CACD;CAIA,MAAM,WAA+C,OAAO,YAC3D,KAAK,KAAK,QAAQ,CACjB,IAAI,MACJ;EACC,SAAS,IAAI;EACb,QAAQ,IAAI;CACb,CACD,CAAC,CACF;CAEA,MAAM,QAAQ,KAAK,KAAK,QAAQ,IAAI,IAAI;CAIxC,MAAM,aAAa,OAAO,kBACzB,MACD;CAEA,SAAS,OAAO,OAAyB;EACxC,MAAM,SAAS,WAAW,KAAK;EAC/B,IAAI,KAAK,UAAU,MAAM,GAAG;GAC3B,MAAM,WAAW,MAAM,OAAO,OAAO,KAAK;GAC1C,MAAM,IAAI,qBACT,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ,CAC/D;EACD;EACA,OAAO,OAAO;CACf;CAEA,eAAe,YAAY,OAAgB,SAAsD;EAChG,MAAM,UAAU,OAAO,KAAK;EAC5B,MAAM,QAAQ,SAAS,QAAQ;EAC/B,MAAM,UAAwB;GAC7B,UAAU,QAAQ,YAAY;GAC9B,gBAAgB,QAAQ;EACzB;EACA,MAAM,UAAU,iBACf,eAAe,MAAM,OAAO,QAAQ,IAAI,GAAG,SAAS,KAAK,GACzD,OACD;EACA,MAAM,CAAC,MAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,OAAO,OAAO,GAAG,OAAO,SAAS,EAAE,WAAW,KAAK,CAAC,CAAC,CAAC;EAC9F,OAAO;GAAE,IAAI,QAAQ;GAAI,SAAS,MAAM,QAAQ,QAAQ,IAAI;GAAG;GAAM;EAAK;CAC3E;CAEA,OAAO;EACN;EACU;EACH;EACP;EACA;CACD;AACD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Config } from "../../../tailwindcss/dist/lib.js";
|
|
2
|
+
import "react";
|
|
3
|
+
//#region ../../node_modules/@react-email/tailwind/dist/index.d.mts
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/tailwind.d.ts
|
|
6
|
+
type TailwindConfig = Omit<Config, 'content'>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { TailwindConfig };
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../../../../../node_modules/@react-email/tailwind/dist/index.d.mts"],"x_google_ignoreList":[0],"mappings":";;;;;KAWK,iBAAiB,KAAK"}
|