@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
package/lib/schemas.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region src/schemas.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A non-empty, absolute http(s) URL. Validated with a pattern check (blocks
|
|
5
|
+
* `javascript:`/relative hrefs) but decoded as a plain `string`, so template
|
|
6
|
+
* props stay ergonomic. Exported for consumers building their own templates.
|
|
7
|
+
*/
|
|
8
|
+
declare const HttpUrl: Schema.String;
|
|
9
|
+
/**
|
|
10
|
+
* Compliance class of an email send. `transactional` skips unsubscribe UI;
|
|
11
|
+
* `marketing` requires an unsubscribe affordance in the legal footer.
|
|
12
|
+
*/
|
|
13
|
+
declare const emailCategory: Schema.Literals<readonly ["transactional", "marketing"]>;
|
|
14
|
+
type EmailCategory = typeof emailCategory.Type;
|
|
15
|
+
declare const otpData: Schema.Struct<{
|
|
16
|
+
readonly code: Schema.NonEmptyString;
|
|
17
|
+
readonly firstName: Schema.optional<Schema.String>;
|
|
18
|
+
readonly expiresInMinutes: Schema.optional<Schema.Number>;
|
|
19
|
+
}>;
|
|
20
|
+
declare const welcomeData: Schema.Struct<{
|
|
21
|
+
readonly firstName: Schema.NonEmptyString;
|
|
22
|
+
readonly verifyUrl: Schema.optional<Schema.String>;
|
|
23
|
+
}>;
|
|
24
|
+
declare const passwordResetData: Schema.Struct<{
|
|
25
|
+
readonly firstName: Schema.optional<Schema.String>;
|
|
26
|
+
readonly resetUrl: Schema.String;
|
|
27
|
+
readonly expiresInMinutes: Schema.optional<Schema.Number>;
|
|
28
|
+
}>;
|
|
29
|
+
declare const notificationData: Schema.Struct<{
|
|
30
|
+
readonly title: Schema.NonEmptyString;
|
|
31
|
+
readonly body: Schema.NonEmptyString;
|
|
32
|
+
readonly severity: Schema.optional<Schema.Literals<readonly ["info", "success", "warning", "error"]>>;
|
|
33
|
+
readonly actionUrl: Schema.optional<Schema.String>;
|
|
34
|
+
readonly actionLabel: Schema.optional<Schema.String>;
|
|
35
|
+
}>;
|
|
36
|
+
declare const incidentAlertData: Schema.Struct<{
|
|
37
|
+
readonly incidentId: Schema.NonEmptyString;
|
|
38
|
+
readonly title: Schema.NonEmptyString;
|
|
39
|
+
readonly severity: Schema.Literals<readonly ["info", "warning", "critical"]>;
|
|
40
|
+
readonly summary: Schema.NonEmptyString;
|
|
41
|
+
readonly location: Schema.optional<Schema.String>;
|
|
42
|
+
readonly detectedAt: Schema.optional<Schema.String>;
|
|
43
|
+
readonly dashboardUrl: Schema.String;
|
|
44
|
+
}>;
|
|
45
|
+
declare const passwordChangedData: Schema.Struct<{
|
|
46
|
+
readonly firstName: Schema.optional<Schema.String>;
|
|
47
|
+
readonly changedAt: Schema.optional<Schema.String>;
|
|
48
|
+
readonly secureAccountUrl: Schema.optional<Schema.String>;
|
|
49
|
+
}>;
|
|
50
|
+
declare const newDeviceLoginData: Schema.Struct<{
|
|
51
|
+
readonly firstName: Schema.optional<Schema.String>;
|
|
52
|
+
readonly device: Schema.optional<Schema.String>;
|
|
53
|
+
readonly location: Schema.optional<Schema.String>;
|
|
54
|
+
readonly ipAddress: Schema.optional<Schema.String>;
|
|
55
|
+
readonly at: Schema.optional<Schema.String>;
|
|
56
|
+
readonly secureAccountUrl: Schema.optional<Schema.String>;
|
|
57
|
+
}>;
|
|
58
|
+
declare const missionApprovalData: Schema.Struct<{
|
|
59
|
+
readonly missionId: Schema.NonEmptyString;
|
|
60
|
+
readonly title: Schema.NonEmptyString;
|
|
61
|
+
readonly summary: Schema.optional<Schema.String>;
|
|
62
|
+
readonly requestedBy: Schema.optional<Schema.String>;
|
|
63
|
+
readonly severity: Schema.optional<Schema.Literals<readonly ["info", "warning", "critical"]>>;
|
|
64
|
+
readonly approveUrl: Schema.String;
|
|
65
|
+
readonly expiresInMinutes: Schema.optional<Schema.Number>;
|
|
66
|
+
}>;
|
|
67
|
+
declare const orgInvitationData: Schema.Struct<{
|
|
68
|
+
readonly orgName: Schema.NonEmptyString;
|
|
69
|
+
readonly inviterName: Schema.optional<Schema.String>;
|
|
70
|
+
readonly orgRole: Schema.optional<Schema.String>;
|
|
71
|
+
readonly acceptUrl: Schema.String;
|
|
72
|
+
readonly expiresInDays: Schema.optional<Schema.Number>;
|
|
73
|
+
}>;
|
|
74
|
+
/** Inferred `data` types for the built-in templates (used for component props). */
|
|
75
|
+
type OtpData = typeof otpData.Type;
|
|
76
|
+
type WelcomeData = typeof welcomeData.Type;
|
|
77
|
+
type PasswordResetData = typeof passwordResetData.Type;
|
|
78
|
+
type NotificationData = typeof notificationData.Type;
|
|
79
|
+
type IncidentAlertData = typeof incidentAlertData.Type;
|
|
80
|
+
type PasswordChangedData = typeof passwordChangedData.Type;
|
|
81
|
+
type NewDeviceLoginData = typeof newDeviceLoginData.Type;
|
|
82
|
+
type MissionApprovalData = typeof missionApprovalData.Type;
|
|
83
|
+
type OrgInvitationData = typeof orgInvitationData.Type;
|
|
84
|
+
//#endregion
|
|
85
|
+
export { EmailCategory, HttpUrl, IncidentAlertData, MissionApprovalData, NewDeviceLoginData, NotificationData, OrgInvitationData, OtpData, PasswordChangedData, PasswordResetData, WelcomeData, emailCategory, incidentAlertData, missionApprovalData, newDeviceLoginData, notificationData, orgInvitationData, otpData, passwordChangedData, passwordResetData, welcomeData };
|
|
86
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","names":[],"sources":["../src/schemas.ts"],"mappings":";;;;;;;cAuBa,SAAO,OAAA;;;;;cAMP,eAAa,OAAA;KACd,uBAAuB,cAAc;cAEpC,SAAO,OAAA;;;;;cAMP,aAAW,OAAA;;;;cAKX,mBAAiB,OAAA;;;;;cAMjB,kBAAgB,OAAA;;;;;;;cAQhB,mBAAiB,OAAA;;;;;;;;;cAYjB,qBAAmB,OAAA;;;;;cAQnB,oBAAkB,OAAA;;;;;;;;cAalB,qBAAmB,OAAA;;;;;;;;;cAWnB,mBAAiB,OAAA;;;;;;;;KASlB,iBAAiB,QAAQ;KACzB,qBAAqB,YAAY;KACjC,2BAA2B,kBAAkB;KAC7C,0BAA0B,iBAAiB;KAC3C,2BAA2B,kBAAkB;KAC7C,6BAA6B,oBAAoB;KACjD,4BAA4B,mBAAmB;KAC/C,6BAA6B,oBAAoB;KACjD,2BAA2B,kBAAkB"}
|
package/lib/schemas.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region src/schemas.ts
|
|
3
|
+
/**
|
|
4
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* A non-empty, absolute http(s) URL. Validated with a pattern check (blocks
|
|
20
|
+
* `javascript:`/relative hrefs) but decoded as a plain `string`, so template
|
|
21
|
+
* props stay ergonomic. Exported for consumers building their own templates.
|
|
22
|
+
*/
|
|
23
|
+
const HttpUrl = Schema.String.check(Schema.isPattern(/^https?:\/\/\S+$/i));
|
|
24
|
+
/**
|
|
25
|
+
* Compliance class of an email send. `transactional` skips unsubscribe UI;
|
|
26
|
+
* `marketing` requires an unsubscribe affordance in the legal footer.
|
|
27
|
+
*/
|
|
28
|
+
const emailCategory = Schema.Literals(["transactional", "marketing"]);
|
|
29
|
+
const otpData = Schema.Struct({
|
|
30
|
+
code: Schema.NonEmptyString,
|
|
31
|
+
firstName: Schema.optional(Schema.String),
|
|
32
|
+
expiresInMinutes: Schema.optional(Schema.Number)
|
|
33
|
+
});
|
|
34
|
+
const welcomeData = Schema.Struct({
|
|
35
|
+
firstName: Schema.NonEmptyString,
|
|
36
|
+
verifyUrl: Schema.optional(HttpUrl)
|
|
37
|
+
});
|
|
38
|
+
const passwordResetData = Schema.Struct({
|
|
39
|
+
firstName: Schema.optional(Schema.String),
|
|
40
|
+
resetUrl: HttpUrl,
|
|
41
|
+
expiresInMinutes: Schema.optional(Schema.Number)
|
|
42
|
+
});
|
|
43
|
+
const notificationData = Schema.Struct({
|
|
44
|
+
title: Schema.NonEmptyString,
|
|
45
|
+
body: Schema.NonEmptyString,
|
|
46
|
+
severity: Schema.optional(Schema.Literals([
|
|
47
|
+
"info",
|
|
48
|
+
"success",
|
|
49
|
+
"warning",
|
|
50
|
+
"error"
|
|
51
|
+
])),
|
|
52
|
+
actionUrl: Schema.optional(HttpUrl),
|
|
53
|
+
actionLabel: Schema.optional(Schema.String)
|
|
54
|
+
});
|
|
55
|
+
const incidentAlertData = Schema.Struct({
|
|
56
|
+
incidentId: Schema.NonEmptyString,
|
|
57
|
+
title: Schema.NonEmptyString,
|
|
58
|
+
severity: Schema.Literals([
|
|
59
|
+
"info",
|
|
60
|
+
"warning",
|
|
61
|
+
"critical"
|
|
62
|
+
]),
|
|
63
|
+
summary: Schema.NonEmptyString,
|
|
64
|
+
location: Schema.optional(Schema.String),
|
|
65
|
+
detectedAt: Schema.optional(Schema.String),
|
|
66
|
+
dashboardUrl: HttpUrl
|
|
67
|
+
});
|
|
68
|
+
const passwordChangedData = Schema.Struct({
|
|
69
|
+
firstName: Schema.optional(Schema.String),
|
|
70
|
+
changedAt: Schema.optional(Schema.String),
|
|
71
|
+
secureAccountUrl: Schema.optional(HttpUrl)
|
|
72
|
+
});
|
|
73
|
+
const newDeviceLoginData = Schema.Struct({
|
|
74
|
+
firstName: Schema.optional(Schema.String),
|
|
75
|
+
device: Schema.optional(Schema.String),
|
|
76
|
+
location: Schema.optional(Schema.String),
|
|
77
|
+
ipAddress: Schema.optional(Schema.String),
|
|
78
|
+
at: Schema.optional(Schema.String),
|
|
79
|
+
secureAccountUrl: Schema.optional(HttpUrl)
|
|
80
|
+
});
|
|
81
|
+
const missionApprovalData = Schema.Struct({
|
|
82
|
+
missionId: Schema.NonEmptyString,
|
|
83
|
+
title: Schema.NonEmptyString,
|
|
84
|
+
summary: Schema.optional(Schema.String),
|
|
85
|
+
requestedBy: Schema.optional(Schema.String),
|
|
86
|
+
severity: Schema.optional(Schema.Literals([
|
|
87
|
+
"info",
|
|
88
|
+
"warning",
|
|
89
|
+
"critical"
|
|
90
|
+
])),
|
|
91
|
+
approveUrl: HttpUrl,
|
|
92
|
+
expiresInMinutes: Schema.optional(Schema.Number)
|
|
93
|
+
});
|
|
94
|
+
const orgInvitationData = Schema.Struct({
|
|
95
|
+
orgName: Schema.NonEmptyString,
|
|
96
|
+
inviterName: Schema.optional(Schema.String),
|
|
97
|
+
orgRole: Schema.optional(Schema.String),
|
|
98
|
+
acceptUrl: HttpUrl,
|
|
99
|
+
expiresInDays: Schema.optional(Schema.Number)
|
|
100
|
+
});
|
|
101
|
+
//#endregion
|
|
102
|
+
export { HttpUrl, emailCategory, incidentAlertData, missionApprovalData, newDeviceLoginData, notificationData, orgInvitationData, otpData, passwordChangedData, passwordResetData, welcomeData };
|
|
103
|
+
|
|
104
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","names":["S"],"sources":["../src/schemas.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 { Schema as S } from \"effect\";\n\n/**\n * A non-empty, absolute http(s) URL. Validated with a pattern check (blocks\n * `javascript:`/relative hrefs) but decoded as a plain `string`, so template\n * props stay ergonomic. Exported for consumers building their own templates.\n */\nexport const HttpUrl = S.String.check(S.isPattern(/^https?:\\/\\/\\S+$/i));\n\n/**\n * Compliance class of an email send. `transactional` skips unsubscribe UI;\n * `marketing` requires an unsubscribe affordance in the legal footer.\n */\nexport const emailCategory = S.Literals([\"transactional\", \"marketing\"]);\nexport type EmailCategory = typeof emailCategory.Type;\n\nexport const otpData = S.Struct({\n\tcode: S.NonEmptyString,\n\tfirstName: S.optional(S.String),\n\texpiresInMinutes: S.optional(S.Number),\n});\n\nexport const welcomeData = S.Struct({\n\tfirstName: S.NonEmptyString,\n\tverifyUrl: S.optional(HttpUrl),\n});\n\nexport const passwordResetData = S.Struct({\n\tfirstName: S.optional(S.String),\n\tresetUrl: HttpUrl,\n\texpiresInMinutes: S.optional(S.Number),\n});\n\nexport const notificationData = S.Struct({\n\ttitle: S.NonEmptyString,\n\tbody: S.NonEmptyString,\n\tseverity: S.optional(S.Literals([\"info\", \"success\", \"warning\", \"error\"])),\n\tactionUrl: S.optional(HttpUrl),\n\tactionLabel: S.optional(S.String),\n});\n\nexport const incidentAlertData = S.Struct({\n\tincidentId: S.NonEmptyString,\n\ttitle: S.NonEmptyString,\n\tseverity: S.Literals([\"info\", \"warning\", \"critical\"]),\n\tsummary: S.NonEmptyString,\n\tlocation: S.optional(S.String),\n\t// Preformatted timestamp string (caller formats/localizes) to avoid\n\t// timezone/format ambiguity inside the email.\n\tdetectedAt: S.optional(S.String),\n\tdashboardUrl: HttpUrl,\n});\n\nexport const passwordChangedData = S.Struct({\n\tfirstName: S.optional(S.String),\n\t// Preformatted timestamp string (caller formats/localizes).\n\tchangedAt: S.optional(S.String),\n\t// Where to secure the account if the change was not authorized.\n\tsecureAccountUrl: S.optional(HttpUrl),\n});\n\nexport const newDeviceLoginData = S.Struct({\n\tfirstName: S.optional(S.String),\n\t// Human-readable client, e.g. \"Chrome on macOS\".\n\tdevice: S.optional(S.String),\n\t// Human-readable place, e.g. \"Newark, DE, USA\".\n\tlocation: S.optional(S.String),\n\tipAddress: S.optional(S.String),\n\t// Preformatted timestamp string (caller formats/localizes).\n\tat: S.optional(S.String),\n\t// Where to review activity / secure the account if the sign-in was not the recipient.\n\tsecureAccountUrl: S.optional(HttpUrl),\n});\n\nexport const missionApprovalData = S.Struct({\n\tmissionId: S.NonEmptyString,\n\ttitle: S.NonEmptyString,\n\tsummary: S.optional(S.String),\n\trequestedBy: S.optional(S.String),\n\tseverity: S.optional(S.Literals([\"info\", \"warning\", \"critical\"])),\n\t// Approver sign-off link (e.g. the HCE mission-approval route).\n\tapproveUrl: HttpUrl,\n\texpiresInMinutes: S.optional(S.Number),\n});\n\nexport const orgInvitationData = S.Struct({\n\torgName: S.NonEmptyString,\n\tinviterName: S.optional(S.String),\n\torgRole: S.optional(S.String),\n\tacceptUrl: HttpUrl,\n\texpiresInDays: S.optional(S.Number),\n});\n\n/** Inferred `data` types for the built-in templates (used for component props). */\nexport type OtpData = typeof otpData.Type;\nexport type WelcomeData = typeof welcomeData.Type;\nexport type PasswordResetData = typeof passwordResetData.Type;\nexport type NotificationData = typeof notificationData.Type;\nexport type IncidentAlertData = typeof incidentAlertData.Type;\nexport type PasswordChangedData = typeof passwordChangedData.Type;\nexport type NewDeviceLoginData = typeof newDeviceLoginData.Type;\nexport type MissionApprovalData = typeof missionApprovalData.Type;\nexport type OrgInvitationData = typeof orgInvitationData.Type;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,UAAUA,OAAE,OAAO,MAAMA,OAAE,UAAU,mBAAmB,CAAC;;;;;AAMtE,MAAa,gBAAgBA,OAAE,SAAS,CAAC,iBAAiB,WAAW,CAAC;AAGtE,MAAa,UAAUA,OAAE,OAAO;CAC/B,MAAMA,OAAE;CACR,WAAWA,OAAE,SAASA,OAAE,MAAM;CAC9B,kBAAkBA,OAAE,SAASA,OAAE,MAAM;AACtC,CAAC;AAED,MAAa,cAAcA,OAAE,OAAO;CACnC,WAAWA,OAAE;CACb,WAAWA,OAAE,SAAS,OAAO;AAC9B,CAAC;AAED,MAAa,oBAAoBA,OAAE,OAAO;CACzC,WAAWA,OAAE,SAASA,OAAE,MAAM;CAC9B,UAAU;CACV,kBAAkBA,OAAE,SAASA,OAAE,MAAM;AACtC,CAAC;AAED,MAAa,mBAAmBA,OAAE,OAAO;CACxC,OAAOA,OAAE;CACT,MAAMA,OAAE;CACR,UAAUA,OAAE,SAASA,OAAE,SAAS;EAAC;EAAQ;EAAW;EAAW;CAAO,CAAC,CAAC;CACxE,WAAWA,OAAE,SAAS,OAAO;CAC7B,aAAaA,OAAE,SAASA,OAAE,MAAM;AACjC,CAAC;AAED,MAAa,oBAAoBA,OAAE,OAAO;CACzC,YAAYA,OAAE;CACd,OAAOA,OAAE;CACT,UAAUA,OAAE,SAAS;EAAC;EAAQ;EAAW;CAAU,CAAC;CACpD,SAASA,OAAE;CACX,UAAUA,OAAE,SAASA,OAAE,MAAM;CAG7B,YAAYA,OAAE,SAASA,OAAE,MAAM;CAC/B,cAAc;AACf,CAAC;AAED,MAAa,sBAAsBA,OAAE,OAAO;CAC3C,WAAWA,OAAE,SAASA,OAAE,MAAM;CAE9B,WAAWA,OAAE,SAASA,OAAE,MAAM;CAE9B,kBAAkBA,OAAE,SAAS,OAAO;AACrC,CAAC;AAED,MAAa,qBAAqBA,OAAE,OAAO;CAC1C,WAAWA,OAAE,SAASA,OAAE,MAAM;CAE9B,QAAQA,OAAE,SAASA,OAAE,MAAM;CAE3B,UAAUA,OAAE,SAASA,OAAE,MAAM;CAC7B,WAAWA,OAAE,SAASA,OAAE,MAAM;CAE9B,IAAIA,OAAE,SAASA,OAAE,MAAM;CAEvB,kBAAkBA,OAAE,SAAS,OAAO;AACrC,CAAC;AAED,MAAa,sBAAsBA,OAAE,OAAO;CAC3C,WAAWA,OAAE;CACb,OAAOA,OAAE;CACT,SAASA,OAAE,SAASA,OAAE,MAAM;CAC5B,aAAaA,OAAE,SAASA,OAAE,MAAM;CAChC,UAAUA,OAAE,SAASA,OAAE,SAAS;EAAC;EAAQ;EAAW;CAAU,CAAC,CAAC;CAEhE,YAAY;CACZ,kBAAkBA,OAAE,SAASA,OAAE,MAAM;AACtC,CAAC;AAED,MAAa,oBAAoBA,OAAE,OAAO;CACzC,SAASA,OAAE;CACX,aAAaA,OAAE,SAASA,OAAE,MAAM;CAChC,SAASA,OAAE,SAASA,OAAE,MAAM;CAC5B,WAAW;CACX,eAAeA,OAAE,SAASA,OAAE,MAAM;AACnC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { EmailSender, SendEmailInput, SendResult } from "./sender.js";
|
|
2
|
+
import { createResendSender } from "./resend-sender.js";
|
|
3
|
+
import { SendEmailOptions, sendEmail } from "./send-email.js";
|
|
4
|
+
export { EmailSender, SendEmailInput, SendEmailOptions, SendResult, createResendSender, sendEmail };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EmailSender } from "./sender.js";
|
|
2
|
+
//#region src/send/resend-sender.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Create an {@link EmailSender} backed by Resend.
|
|
5
|
+
*
|
|
6
|
+
* Server-only — never import this into a browser bundle or the API key leaks.
|
|
7
|
+
* The key is read from the explicit argument or the `RESEND_API_KEY` env var and
|
|
8
|
+
* validated up front (fail fast). Resend returns `{ data, error }` for API-level
|
|
9
|
+
* failures rather than throwing, so we branch on `error` instead of try/catch.
|
|
10
|
+
*/
|
|
11
|
+
declare function createResendSender(apiKey?: string | undefined): EmailSender;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { createResendSender };
|
|
14
|
+
//# sourceMappingURL=resend-sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-sender.d.ts","names":[],"sources":["../../src/send/resend-sender.ts"],"mappings":";;;;;;;;;;iBA2BgB,mBACf,8BACE"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Resend } from "resend";
|
|
2
|
+
//#region src/send/resend-sender.ts
|
|
3
|
+
/**
|
|
4
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Create an {@link EmailSender} backed by Resend.
|
|
20
|
+
*
|
|
21
|
+
* Server-only — never import this into a browser bundle or the API key leaks.
|
|
22
|
+
* The key is read from the explicit argument or the `RESEND_API_KEY` env var and
|
|
23
|
+
* validated up front (fail fast). Resend returns `{ data, error }` for API-level
|
|
24
|
+
* failures rather than throwing, so we branch on `error` instead of try/catch.
|
|
25
|
+
*/
|
|
26
|
+
function createResendSender(apiKey = process.env.RESEND_API_KEY) {
|
|
27
|
+
if (!apiKey) throw new Error("RESEND_API_KEY is required to create a Resend sender");
|
|
28
|
+
const resend = new Resend(apiKey);
|
|
29
|
+
return { async send(input) {
|
|
30
|
+
const payload = {
|
|
31
|
+
from: input.from,
|
|
32
|
+
to: input.to,
|
|
33
|
+
subject: input.subject,
|
|
34
|
+
html: input.html,
|
|
35
|
+
text: input.text,
|
|
36
|
+
replyTo: input.replyTo,
|
|
37
|
+
cc: input.cc,
|
|
38
|
+
bcc: input.bcc,
|
|
39
|
+
headers: input.headers
|
|
40
|
+
};
|
|
41
|
+
const options = input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : void 0;
|
|
42
|
+
try {
|
|
43
|
+
const { data, error } = await resend.emails.send(payload, options);
|
|
44
|
+
if (error) return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: {
|
|
47
|
+
name: error.name,
|
|
48
|
+
message: error.message
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
if (!data) return {
|
|
52
|
+
ok: false,
|
|
53
|
+
error: {
|
|
54
|
+
name: "unknown_error",
|
|
55
|
+
message: "Resend returned no data and no error"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
ok: true,
|
|
60
|
+
id: data.id
|
|
61
|
+
};
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
error: {
|
|
66
|
+
name: "transport_error",
|
|
67
|
+
message: err instanceof Error ? err.message : String(err)
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
} };
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { createResendSender };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=resend-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-sender.js","names":[],"sources":["../../src/send/resend-sender.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 { Resend } from \"resend\";\nimport type { EmailSender, SendEmailInput, SendResult } from \"./sender.js\";\n\n/**\n * Create an {@link EmailSender} backed by Resend.\n *\n * Server-only — never import this into a browser bundle or the API key leaks.\n * The key is read from the explicit argument or the `RESEND_API_KEY` env var and\n * validated up front (fail fast). Resend returns `{ data, error }` for API-level\n * failures rather than throwing, so we branch on `error` instead of try/catch.\n */\nexport function createResendSender(\n\tapiKey: string | undefined = process.env.RESEND_API_KEY,\n): EmailSender {\n\tif (!apiKey) {\n\t\tthrow new Error(\"RESEND_API_KEY is required to create a Resend sender\");\n\t}\n\n\tconst resend = new Resend(apiKey);\n\n\treturn {\n\t\tasync send(input: SendEmailInput): Promise<SendResult> {\n\t\t\t// `to`/`html`/`text` are always populated on the pipeline path (see\n\t\t\t// renderEmail); the localized cast keeps Resend's html|text|react union\n\t\t\t// happy without leaking `any`.\n\t\t\tconst payload = {\n\t\t\t\tfrom: input.from,\n\t\t\t\tto: input.to,\n\t\t\t\tsubject: input.subject,\n\t\t\t\thtml: input.html,\n\t\t\t\ttext: input.text,\n\t\t\t\treplyTo: input.replyTo,\n\t\t\t\tcc: input.cc,\n\t\t\t\tbcc: input.bcc,\n\t\t\t\theaders: input.headers,\n\t\t\t} as Parameters<typeof resend.emails.send>[0];\n\n\t\t\tconst options = input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : undefined;\n\n\t\t\ttry {\n\t\t\t\tconst { data, error } = await resend.emails.send(payload, options);\n\n\t\t\t\tif (error) {\n\t\t\t\t\treturn { ok: false, error: { name: error.name, message: error.message } };\n\t\t\t\t}\n\n\t\t\t\tif (!data) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\terror: { name: \"unknown_error\", message: \"Resend returned no data and no error\" },\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn { ok: true, id: data.id };\n\t\t\t} catch (err) {\n\t\t\t\t// The SDK returns { data, error } for API errors, but can still THROW\n\t\t\t\t// on transport failures (fetch rejection, DNS, aborted request), so the\n\t\t\t\t// whole call is wrapped to honor the never-throws contract of send().\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tname: \"transport_error\",\n\t\t\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,mBACf,SAA6B,QAAQ,IAAI,gBAC3B;CACd,IAAI,CAAC,QACJ,MAAM,IAAI,MAAM,sDAAsD;CAGvE,MAAM,SAAS,IAAI,OAAO,MAAM;CAEhC,OAAO,EACN,MAAM,KAAK,OAA4C;EAItD,MAAM,UAAU;GACf,MAAM,MAAM;GACZ,IAAI,MAAM;GACV,SAAS,MAAM;GACf,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,IAAI,MAAM;GACV,KAAK,MAAM;GACX,SAAS,MAAM;EAChB;EAEA,MAAM,UAAU,MAAM,iBAAiB,EAAE,gBAAgB,MAAM,eAAe,IAAI,KAAA;EAElF,IAAI;GACH,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,OAAO,KAAK,SAAS,OAAO;GAEjE,IAAI,OACH,OAAO;IAAE,IAAI;IAAO,OAAO;KAAE,MAAM,MAAM;KAAM,SAAS,MAAM;IAAQ;GAAE;GAGzE,IAAI,CAAC,MACJ,OAAO;IACN,IAAI;IACJ,OAAO;KAAE,MAAM;KAAiB,SAAS;IAAuC;GACjF;GAGD,OAAO;IAAE,IAAI;IAAM,IAAI,KAAK;GAAG;EAChC,SAAS,KAAK;GAIb,OAAO;IACN,IAAI;IACJ,OAAO;KACN,MAAM;KACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IACzD;GACD;EACD;CACD,EACD;AACD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EmailSender, SendResult } from "./sender.js";
|
|
2
|
+
//#region src/send/send-email.d.ts
|
|
3
|
+
interface SendEmailOptions {
|
|
4
|
+
/** Verified sender address, e.g. "ResQ Systems <updates@send.resq.software>". */
|
|
5
|
+
from: string;
|
|
6
|
+
replyTo?: string | string[];
|
|
7
|
+
/** Stable key so Resend de-dupes identical sends for 24h. */
|
|
8
|
+
idempotencyKey?: string;
|
|
9
|
+
/** Extra headers passed through to the sender. */
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Render a validated payload and hand it to a sender in one call. Convenience
|
|
14
|
+
* wiring for the common pipeline case: `sendEmail(sender, payload, { from })`.
|
|
15
|
+
*/
|
|
16
|
+
declare function sendEmail(sender: EmailSender, payload: unknown, options: SendEmailOptions): Promise<SendResult>;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { SendEmailOptions, sendEmail };
|
|
19
|
+
//# sourceMappingURL=send-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-email.d.ts","names":[],"sources":["../../src/send/send-email.ts"],"mappings":";;UAoBiB;;EAEhB;EACA;;EAEA;;EAEA,UAAU;;;;;;iBAOW,UACrB,QAAQ,aACR,kBACA,SAAS,mBACP,QAAQ"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EmailValidationError } from "../mailer.js";
|
|
2
|
+
import { renderEmail } from "../render.js";
|
|
3
|
+
//#region src/send/send-email.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
|
+
* Render a validated payload and hand it to a sender in one call. Convenience
|
|
21
|
+
* wiring for the common pipeline case: `sendEmail(sender, payload, { from })`.
|
|
22
|
+
*/
|
|
23
|
+
async function sendEmail(sender, payload, options) {
|
|
24
|
+
let rendered;
|
|
25
|
+
try {
|
|
26
|
+
rendered = await renderEmail(payload);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err instanceof EmailValidationError) return {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: {
|
|
31
|
+
name: err.name,
|
|
32
|
+
message: err.message
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
error: {
|
|
38
|
+
name: "render_error",
|
|
39
|
+
message: err instanceof Error ? err.message : String(err)
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return await sender.send({
|
|
45
|
+
from: options.from,
|
|
46
|
+
to: rendered.to,
|
|
47
|
+
subject: rendered.subject,
|
|
48
|
+
html: rendered.html,
|
|
49
|
+
text: rendered.text,
|
|
50
|
+
replyTo: options.replyTo,
|
|
51
|
+
idempotencyKey: options.idempotencyKey,
|
|
52
|
+
headers: options.headers
|
|
53
|
+
});
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
error: {
|
|
58
|
+
name: "sender_error",
|
|
59
|
+
message: err instanceof Error ? err.message : String(err)
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { sendEmail };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=send-email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-email.js","names":[],"sources":["../../src/send/send-email.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 { EmailValidationError } from \"../mailer.js\";\nimport { renderEmail } from \"../render.js\";\nimport type { EmailSender, SendResult } from \"./sender.js\";\n\nexport interface SendEmailOptions {\n\t/** Verified sender address, e.g. \"ResQ Systems <updates@send.resq.software>\". */\n\tfrom: string;\n\treplyTo?: string | string[];\n\t/** Stable key so Resend de-dupes identical sends for 24h. */\n\tidempotencyKey?: string;\n\t/** Extra headers passed through to the sender. */\n\theaders?: Record<string, string>;\n}\n\n/**\n * Render a validated payload and hand it to a sender in one call. Convenience\n * wiring for the common pipeline case: `sendEmail(sender, payload, { from })`.\n */\nexport async function sendEmail(\n\tsender: EmailSender,\n\tpayload: unknown,\n\toptions: SendEmailOptions,\n): Promise<SendResult> {\n\tlet rendered: Awaited<ReturnType<typeof renderEmail>>;\n\ttry {\n\t\trendered = await renderEmail(payload);\n\t} catch (err) {\n\t\t// Preserve the never-throws SendResult contract (see the sender adapters):\n\t\t// an invalid payload — or any other render failure — becomes a failure\n\t\t// result instead of a rejected promise, so pipeline callers that only\n\t\t// branch on `SendResult` never hit an unhandled rejection.\n\t\t// EmailValidationError keeps its name so callers can tell a bad payload\n\t\t// apart from an unexpected render error.\n\t\tif (err instanceof EmailValidationError) {\n\t\t\treturn { ok: false, error: { name: err.name, message: err.message } };\n\t\t}\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: {\n\t\t\t\tname: \"render_error\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t},\n\t\t};\n\t}\n\n\ttry {\n\t\treturn await sender.send({\n\t\t\tfrom: options.from,\n\t\t\tto: rendered.to,\n\t\t\tsubject: rendered.subject,\n\t\t\thtml: rendered.html,\n\t\t\ttext: rendered.text,\n\t\t\treplyTo: options.replyTo,\n\t\t\tidempotencyKey: options.idempotencyKey,\n\t\t\theaders: options.headers,\n\t\t});\n\t} catch (err) {\n\t\t// EmailSender.send is expected to normalize failures into SendResult, but a\n\t\t// third-party sender might still throw; keep sendEmail's never-throws\n\t\t// contract regardless, tagged distinctly so it isn't confused with a\n\t\t// render_error.\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: {\n\t\t\t\tname: \"sender_error\",\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAkCA,eAAsB,UACrB,QACA,SACA,SACsB;CACtB,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,YAAY,OAAO;CACrC,SAAS,KAAK;EAOb,IAAI,eAAe,sBAClB,OAAO;GAAE,IAAI;GAAO,OAAO;IAAE,MAAM,IAAI;IAAM,SAAS,IAAI;GAAQ;EAAE;EAErE,OAAO;GACN,IAAI;GACJ,OAAO;IACN,MAAM;IACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GACzD;EACD;CACD;CAEA,IAAI;EACH,OAAO,MAAM,OAAO,KAAK;GACxB,MAAM,QAAQ;GACd,IAAI,SAAS;GACb,SAAS,SAAS;GAClB,MAAM,SAAS;GACf,MAAM,SAAS;GACf,SAAS,QAAQ;GACjB,gBAAgB,QAAQ;GACxB,SAAS,QAAQ;EAClB,CAAC;CACF,SAAS,KAAK;EAKb,OAAO;GACN,IAAI;GACJ,OAAO;IACN,MAAM;IACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GACzD;EACD;CACD;AACD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/send/sender.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
|
+
/** Provider-agnostic input for sending a single email. */
|
|
18
|
+
interface SendEmailInput {
|
|
19
|
+
from: string;
|
|
20
|
+
to: string | string[];
|
|
21
|
+
subject: string;
|
|
22
|
+
html?: string;
|
|
23
|
+
text?: string;
|
|
24
|
+
replyTo?: string | string[];
|
|
25
|
+
cc?: string | string[];
|
|
26
|
+
bcc?: string | string[];
|
|
27
|
+
/** Stable key so Resend de-dupes identical sends for 24h. */
|
|
28
|
+
idempotencyKey?: string;
|
|
29
|
+
/** Extra headers, e.g. RFC 8058 `List-Unsubscribe` for marketing mail. */
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
/** Normalized send result. Providers map their responses onto this shape. */
|
|
33
|
+
type SendResult = {
|
|
34
|
+
ok: true;
|
|
35
|
+
id: string;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
error: {
|
|
39
|
+
name: string;
|
|
40
|
+
message: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Port for an email transport. Implement this to plug in any provider (Resend,
|
|
45
|
+
* SES, Postmark, SMTP); the rest of the package depends only on this interface.
|
|
46
|
+
*/
|
|
47
|
+
interface EmailSender {
|
|
48
|
+
/**
|
|
49
|
+
* Send one email. Implementations SHOULD normalize transport/API failures into
|
|
50
|
+
* a `{ ok: false, error }` result rather than throwing (the bundled Resend
|
|
51
|
+
* adapter does). `sendEmail` still guards against a throwing sender, but
|
|
52
|
+
* honoring this contract keeps the failure `name`/`message` provider-accurate.
|
|
53
|
+
*/
|
|
54
|
+
send(input: SendEmailInput): Promise<SendResult>;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { EmailSender, SendEmailInput, SendResult };
|
|
58
|
+
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.d.ts","names":[],"sources":["../../src/send/sender.ts"],"mappings":";;;;;;;;;;;;;;;;;UAiBiB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA,UAAU;;;KAIC;EACP;EAAU;;EACV;EAAW;IAAS;IAAc;;;;;;;UAMtB;;;;;;;EAOhB,KAAK,OAAO,iBAAiB,QAAQ"}
|
|
File without changes
|
package/lib/suite.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Mailer } from "./mailer.js";
|
|
2
|
+
//#region src/suite.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Copyright 2026 ResQ Systems, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The default mailer over the built-in ResQ Systems templates — the single source of
|
|
20
|
+
* truth behind the package's `EmailPayload`, `decodeEmailPayload`, `registry`,
|
|
21
|
+
* and `renderEmail` exports.
|
|
22
|
+
*/
|
|
23
|
+
declare const resqMailer: Mailer<{
|
|
24
|
+
readonly name: "incident-alert";
|
|
25
|
+
readonly to: string;
|
|
26
|
+
readonly data: {
|
|
27
|
+
readonly incidentId: string;
|
|
28
|
+
readonly title: string;
|
|
29
|
+
readonly severity: "critical" | "info" | "warning";
|
|
30
|
+
readonly summary: string;
|
|
31
|
+
readonly location?: string | undefined;
|
|
32
|
+
readonly detectedAt?: string | undefined;
|
|
33
|
+
readonly dashboardUrl: string;
|
|
34
|
+
};
|
|
35
|
+
readonly category?: "transactional" | "marketing";
|
|
36
|
+
readonly unsubscribeUrl?: string;
|
|
37
|
+
} | {
|
|
38
|
+
readonly name: "mission-approval";
|
|
39
|
+
readonly to: string;
|
|
40
|
+
readonly data: {
|
|
41
|
+
readonly missionId: string;
|
|
42
|
+
readonly title: string;
|
|
43
|
+
readonly summary?: string | undefined;
|
|
44
|
+
readonly requestedBy?: string | undefined;
|
|
45
|
+
readonly severity?: "critical" | "info" | "warning" | undefined;
|
|
46
|
+
readonly approveUrl: string;
|
|
47
|
+
readonly expiresInMinutes?: number | undefined;
|
|
48
|
+
};
|
|
49
|
+
readonly category?: "transactional" | "marketing";
|
|
50
|
+
readonly unsubscribeUrl?: string;
|
|
51
|
+
} | {
|
|
52
|
+
readonly name: "new-device-login";
|
|
53
|
+
readonly to: string;
|
|
54
|
+
readonly data: {
|
|
55
|
+
readonly firstName?: string | undefined;
|
|
56
|
+
readonly device?: string | undefined;
|
|
57
|
+
readonly location?: string | undefined;
|
|
58
|
+
readonly ipAddress?: string | undefined;
|
|
59
|
+
readonly at?: string | undefined;
|
|
60
|
+
readonly secureAccountUrl?: string | undefined;
|
|
61
|
+
};
|
|
62
|
+
readonly category?: "transactional" | "marketing";
|
|
63
|
+
readonly unsubscribeUrl?: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly name: "notification";
|
|
66
|
+
readonly to: string;
|
|
67
|
+
readonly data: {
|
|
68
|
+
readonly title: string;
|
|
69
|
+
readonly body: string;
|
|
70
|
+
readonly severity?: "error" | "info" | "success" | "warning" | undefined;
|
|
71
|
+
readonly actionUrl?: string | undefined;
|
|
72
|
+
readonly actionLabel?: string | undefined;
|
|
73
|
+
};
|
|
74
|
+
readonly category?: "transactional" | "marketing";
|
|
75
|
+
readonly unsubscribeUrl?: string;
|
|
76
|
+
} | {
|
|
77
|
+
readonly name: "org-invitation";
|
|
78
|
+
readonly to: string;
|
|
79
|
+
readonly data: {
|
|
80
|
+
readonly orgName: string;
|
|
81
|
+
readonly inviterName?: string | undefined;
|
|
82
|
+
readonly orgRole?: string | undefined;
|
|
83
|
+
readonly acceptUrl: string;
|
|
84
|
+
readonly expiresInDays?: number | undefined;
|
|
85
|
+
};
|
|
86
|
+
readonly category?: "transactional" | "marketing";
|
|
87
|
+
readonly unsubscribeUrl?: string;
|
|
88
|
+
} | {
|
|
89
|
+
readonly name: "otp";
|
|
90
|
+
readonly to: string;
|
|
91
|
+
readonly data: {
|
|
92
|
+
readonly code: string;
|
|
93
|
+
readonly firstName?: string | undefined;
|
|
94
|
+
readonly expiresInMinutes?: number | undefined;
|
|
95
|
+
};
|
|
96
|
+
readonly category?: "transactional" | "marketing";
|
|
97
|
+
readonly unsubscribeUrl?: string;
|
|
98
|
+
} | {
|
|
99
|
+
readonly name: "password-changed";
|
|
100
|
+
readonly to: string;
|
|
101
|
+
readonly data: {
|
|
102
|
+
readonly firstName?: string | undefined;
|
|
103
|
+
readonly changedAt?: string | undefined;
|
|
104
|
+
readonly secureAccountUrl?: string | undefined;
|
|
105
|
+
};
|
|
106
|
+
readonly category?: "transactional" | "marketing";
|
|
107
|
+
readonly unsubscribeUrl?: string;
|
|
108
|
+
} | {
|
|
109
|
+
readonly name: "password-reset";
|
|
110
|
+
readonly to: string;
|
|
111
|
+
readonly data: {
|
|
112
|
+
readonly firstName?: string | undefined;
|
|
113
|
+
readonly resetUrl: string;
|
|
114
|
+
readonly expiresInMinutes?: number | undefined;
|
|
115
|
+
};
|
|
116
|
+
readonly category?: "transactional" | "marketing";
|
|
117
|
+
readonly unsubscribeUrl?: string;
|
|
118
|
+
} | {
|
|
119
|
+
readonly name: "welcome";
|
|
120
|
+
readonly to: string;
|
|
121
|
+
readonly data: {
|
|
122
|
+
readonly firstName: string;
|
|
123
|
+
readonly verifyUrl?: string | undefined;
|
|
124
|
+
};
|
|
125
|
+
readonly category?: "transactional" | "marketing";
|
|
126
|
+
readonly unsubscribeUrl?: string;
|
|
127
|
+
}>;
|
|
128
|
+
//#endregion
|
|
129
|
+
export { resqMailer };
|
|
130
|
+
//# sourceMappingURL=suite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.d.ts","names":[],"sources":["../src/suite.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;cAwBa,YAAA"}
|
package/lib/suite.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createMailer } from "./mailer.js";
|
|
2
|
+
import { resqEmailTemplates } from "./templates.js";
|
|
3
|
+
//#region src/suite.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
|
+
* The default mailer over the built-in ResQ Systems templates — the single source of
|
|
21
|
+
* truth behind the package's `EmailPayload`, `decodeEmailPayload`, `registry`,
|
|
22
|
+
* and `renderEmail` exports.
|
|
23
|
+
*/
|
|
24
|
+
const resqMailer = createMailer(resqEmailTemplates);
|
|
25
|
+
//#endregion
|
|
26
|
+
export { resqMailer };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=suite.js.map
|
package/lib/suite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite.js","names":[],"sources":["../src/suite.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 { createMailer } from \"./mailer.js\";\nimport { resqEmailTemplates } from \"./templates.js\";\n\n/**\n * The default mailer over the built-in ResQ Systems templates — the single source of\n * truth behind the package's `EmailPayload`, `decodeEmailPayload`, `registry`,\n * and `renderEmail` exports.\n */\nexport const resqMailer = createMailer(resqEmailTemplates);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,aAAa,aAAa,kBAAkB"}
|