@schemavaults/send-email 0.4.0 → 0.5.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 +28 -7
- package/dist/cli.js +96 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/send-email-request-body-schema.js +23 -2
- package/dist/send-email-request-body-schema.js.map +1 -1
- package/dist/validators/email-attachment-schema.d.ts +7 -4
- package/dist/validators/email-attachment-schema.js +19 -14
- package/dist/validators/email-attachment-schema.js.map +1 -1
- package/dist/validators/email-sender-schema.d.ts +12 -0
- package/dist/validators/email-sender-schema.js +62 -0
- package/dist/validators/email-sender-schema.js.map +1 -0
- package/dist/validators/unsafe-characters.d.ts +2 -0
- package/dist/validators/unsafe-characters.js +25 -0
- package/dist/validators/unsafe-characters.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,6 +81,23 @@ bunx schemavaults-send-email --transport smtp-primary send \
|
|
|
81
81
|
|
|
82
82
|
Transport names are defined by whoever configures the mail-server; this package only validates that the value looks like an identifier. An unknown transport name is rejected by the mail-server, not by the client.
|
|
83
83
|
|
|
84
|
+
### Set the sender
|
|
85
|
+
|
|
86
|
+
`from` is optional; when omitted, the mail-server sends from its configured default sender. Pass a bare address, or a display name followed by the address in angle brackets. Wrap a display name in double quotes when it contains any of `( ) [ ] : ; @ ,`:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
await sendEmail({
|
|
90
|
+
body: {
|
|
91
|
+
to: "user@example.com",
|
|
92
|
+
from: '"Example, Inc." <noreply@example.com>', // or "Example <noreply@example.com>", or "noreply@example.com"
|
|
93
|
+
subject: "Hello",
|
|
94
|
+
message: { text: "Hello.", html: "<p>Hello.</p>" },
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The address's domain must be one the mail-server's transport is set up to send from. On the CLI, pass the same value to `--from`.
|
|
100
|
+
|
|
84
101
|
### Attach files
|
|
85
102
|
|
|
86
103
|
Request bodies are JSON, so each attachment's bytes travel as a base64 string under `body.attachments`. You rarely need to encode anything yourself: the `attachments` option on `sendEmail()` (and `sendEmailToMailingList()`) accepts raw bytes, plain text, or already-encoded attachments and base64-encodes them for you before appending them to `body.attachments`.
|
|
@@ -121,9 +138,9 @@ const attachment = createEmailAttachment({
|
|
|
121
138
|
// => { filename: "logo.png", content: "iVBORw0KGgo...", contentType: "image/png", contentId: "logo" }
|
|
122
139
|
```
|
|
123
140
|
|
|
124
|
-
Setting `contentId` marks the attachment as inline so the HTML body can embed it via a `cid:` URL; pass the bare identifier without angle brackets. `contentType` is optional -- when omitted, the mail-server's transport derives it from the filename's extension.
|
|
141
|
+
Setting `contentId` marks the attachment as inline so the HTML body can embed it via a `cid:` URL; pass the bare identifier without angle brackets, in printable ASCII. `contentType` is optional -- when omitted, the mail-server's transport derives it from the filename's extension. Non-ASCII names belong in `filename`, not in a `contentType` parameter.
|
|
125
142
|
|
|
126
|
-
Limits enforced client-side (and exported as `MAX_ATTACHMENTS_PER_EMAIL` / `MAX_TOTAL_ATTACHMENT_BYTES`): at most 20 attachments per email, totalling at most 25 MiB once decoded. Filenames may not contain path separators or control characters. The mail-server, its hosting platform, and the receiving mail systems may enforce lower limits of their own.
|
|
143
|
+
Limits enforced client-side (and exported as `MAX_ATTACHMENTS_PER_EMAIL` / `MAX_TOTAL_ATTACHMENT_BYTES`): at most 20 attachments per email, totalling at most 25 MiB once decoded. Filenames may not contain path separators, control characters, or bidirectional formatting characters (which can disguise `invoice\u202Efdp.exe` as `invoiceexe.pdf`). `contentType` and `contentId` must be printable ASCII, and `subject` must not contain line breaks or other control characters, so no value can break out of its MIME header. The mail-server, its hosting platform, and the receiving mail systems may enforce lower limits of their own.
|
|
127
144
|
|
|
128
145
|
From the CLI, `--attach <path>` is repeatable on both `send` and `send-to-mailing-list`, and may be combined with `--body-file` (the files are appended to any `attachments` already in the JSON):
|
|
129
146
|
|
|
@@ -272,6 +289,10 @@ Zod schema for validating template IDs: lowercase alphanumeric with hyphens/unde
|
|
|
272
289
|
|
|
273
290
|
Zod schema for validating transport names: lowercase alphanumeric with hyphens/underscores, 1-64 characters, must start with a lowercase letter and end with a lowercase alphanumeric character. Whether a well-formed name corresponds to a transport the mail-server actually has configured is decided server-side.
|
|
274
291
|
|
|
292
|
+
### `emailSenderSchema`
|
|
293
|
+
|
|
294
|
+
Zod schema for the `from` field: a bare address (`noreply@example.com`) or a display name followed by the address in angle brackets (`Example <noreply@example.com>`). Display names may be Unicode; one containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes (`"Example, Inc." <noreply@example.com>`). Control characters, bidi formatting characters, and angle brackets, double quotes or backslashes inside the display name are rejected.
|
|
295
|
+
|
|
275
296
|
### `emailAttachmentSchema` / `emailAttachmentsSchema`
|
|
276
297
|
|
|
277
298
|
Zod schemas for a single attachment and for the `attachments` array respectively. The array schema enforces the count (`MAX_ATTACHMENTS_PER_EMAIL`, 20) and total decoded size (`MAX_TOTAL_ATTACHMENT_BYTES`, 25 MiB) limits; both constants are exported.
|
|
@@ -286,17 +307,17 @@ type Message =
|
|
|
286
307
|
| { text: string; html: string }; // both required
|
|
287
308
|
|
|
288
309
|
type EmailAttachment = {
|
|
289
|
-
filename: string; // 1-255 chars; no path separators or
|
|
310
|
+
filename: string; // 1-255 chars; no path separators, control or bidi formatting characters
|
|
290
311
|
content: string; // base64-encoded bytes (standard alphabet, padded)
|
|
291
|
-
contentType?: string; // MIME type; derived from the filename when omitted
|
|
292
|
-
contentId?: string; // marks the attachment inline; reference as cid:<contentId>
|
|
312
|
+
contentType?: string; // MIME type, printable ASCII; derived from the filename when omitted
|
|
313
|
+
contentId?: string; // printable ASCII; marks the attachment inline; reference as cid:<contentId>
|
|
293
314
|
};
|
|
294
315
|
|
|
295
316
|
type SendEmailRequestBody = {
|
|
296
317
|
to: string | string[]; // email address(es) or mailing list UUID
|
|
297
|
-
subject: string;
|
|
318
|
+
subject: string; // no line breaks or control characters (tabs allowed)
|
|
298
319
|
message: Message;
|
|
299
|
-
from?: string; // defaults to mail-server's configured sender
|
|
320
|
+
from?: string; // address or "Display Name <address>"; defaults to mail-server's configured sender
|
|
300
321
|
replyTo?: string;
|
|
301
322
|
cc?: string | string[];
|
|
302
323
|
bcc?: string | string[];
|
package/dist/cli.js
CHANGED
|
@@ -18008,6 +18008,35 @@ var transportIdSchema = external_exports.string().min(1, "Transport ID must be n
|
|
|
18008
18008
|
"Transport ID must start with a lowercase letter and end with a lowercase alphanumeric character, and may only contain lowercase alphanumeric characters, hyphens and underscores."
|
|
18009
18009
|
);
|
|
18010
18010
|
|
|
18011
|
+
// src/validators/unsafe-characters.ts
|
|
18012
|
+
function hasControlCharacters(value) {
|
|
18013
|
+
for (let i = 0; i < value.length; i++) {
|
|
18014
|
+
const code = value.charCodeAt(i);
|
|
18015
|
+
if (code < 32 || code >= 127 && code <= 159) return true;
|
|
18016
|
+
}
|
|
18017
|
+
return false;
|
|
18018
|
+
}
|
|
18019
|
+
var BIDI_FORMATTING = /* @__PURE__ */ new Set([
|
|
18020
|
+
1564,
|
|
18021
|
+
8206,
|
|
18022
|
+
8207,
|
|
18023
|
+
8234,
|
|
18024
|
+
8235,
|
|
18025
|
+
8236,
|
|
18026
|
+
8237,
|
|
18027
|
+
8238,
|
|
18028
|
+
8294,
|
|
18029
|
+
8295,
|
|
18030
|
+
8296,
|
|
18031
|
+
8297
|
|
18032
|
+
]);
|
|
18033
|
+
function hasBidiFormatting(value) {
|
|
18034
|
+
for (let i = 0; i < value.length; i++) {
|
|
18035
|
+
if (BIDI_FORMATTING.has(value.charCodeAt(i))) return true;
|
|
18036
|
+
}
|
|
18037
|
+
return false;
|
|
18038
|
+
}
|
|
18039
|
+
|
|
18011
18040
|
// src/validators/email-attachment-schema.ts
|
|
18012
18041
|
var MAX_ATTACHMENTS_PER_EMAIL = 20;
|
|
18013
18042
|
var MAX_TOTAL_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
@@ -18018,31 +18047,28 @@ function base64DecodedByteLength(base643) {
|
|
|
18018
18047
|
else if (base643.endsWith("=")) padding = 1;
|
|
18019
18048
|
return Math.floor(base643.length * 3 / 4) - padding;
|
|
18020
18049
|
}
|
|
18021
|
-
function hasControlCharacters(value) {
|
|
18022
|
-
for (let i = 0; i < value.length; i++) {
|
|
18023
|
-
const code = value.charCodeAt(i);
|
|
18024
|
-
if (code < 32 || code === 127) return true;
|
|
18025
|
-
}
|
|
18026
|
-
return false;
|
|
18027
|
-
}
|
|
18028
18050
|
var attachmentFilenameSchema = external_exports.string().min(1, "Attachment filename must be non-empty!").max(255, "Attachment filename must be at most 255 characters!").refine((name) => name !== "." && name !== "..", {
|
|
18029
18051
|
message: "Attachment filename must not be '.' or '..'!"
|
|
18030
18052
|
}).refine((name) => !name.includes("/") && !name.includes("\\"), {
|
|
18031
18053
|
message: "Attachment filename must not contain path separators!"
|
|
18032
18054
|
}).refine((name) => !hasControlCharacters(name), {
|
|
18033
18055
|
message: "Attachment filename must not contain control characters!"
|
|
18056
|
+
}).refine((name) => !hasBidiFormatting(name), {
|
|
18057
|
+
message: "Attachment filename must not contain bidirectional formatting characters!"
|
|
18034
18058
|
});
|
|
18035
18059
|
var attachmentContentSchema = external_exports.base64("Attachment content must be base64-encoded!").min(1, "Attachment content must not be empty!");
|
|
18036
18060
|
var MIME_TOKEN = "[A-Za-z0-9!#$&^_.+-]+";
|
|
18061
|
+
var MIME_PARAM_VALUE = '(?:"[\\x20\\x21\\x23-\\x7E]*"|[\\x21\\x23-\\x3A\\x3C-\\x7E]+)';
|
|
18037
18062
|
var attachmentContentTypeSchema = external_exports.string().min(1, "Attachment content type must be non-empty!").max(255, "Attachment content type must be at most 255 characters!").regex(
|
|
18063
|
+
// `[ \t]*`, not `\s*`: `\s` matches CR/LF.
|
|
18038
18064
|
new RegExp(
|
|
18039
|
-
`^${MIME_TOKEN}\\/${MIME_TOKEN}(
|
|
18065
|
+
`^${MIME_TOKEN}\\/${MIME_TOKEN}(?:[ \\t]*;[ \\t]*${MIME_TOKEN}=${MIME_PARAM_VALUE})*$`
|
|
18040
18066
|
),
|
|
18041
18067
|
"Attachment content type must be a MIME type such as 'application/pdf'!"
|
|
18042
18068
|
);
|
|
18043
18069
|
var attachmentContentIdSchema = external_exports.string().min(1, "Attachment content ID must be non-empty!").max(255, "Attachment content ID must be at most 255 characters!").regex(
|
|
18044
|
-
/^[
|
|
18045
|
-
"Attachment content ID must
|
|
18070
|
+
/^[\x21-\x3B\x3D\x3F-\x7E]+$/,
|
|
18071
|
+
"Attachment content ID must be printable ASCII without spaces or angle brackets!"
|
|
18046
18072
|
);
|
|
18047
18073
|
var emailAttachmentSchema = external_exports.object({
|
|
18048
18074
|
filename: attachmentFilenameSchema,
|
|
@@ -18069,6 +18095,46 @@ var emailAttachmentsSchema = external_exports.array(emailAttachmentSchema).min(1
|
|
|
18069
18095
|
}
|
|
18070
18096
|
});
|
|
18071
18097
|
|
|
18098
|
+
// src/validators/email-sender-schema.ts
|
|
18099
|
+
var emailAddressSchema = external_exports.string().email();
|
|
18100
|
+
var DISPLAY_NAME_SPECIALS = /[()[\]:;@,]/;
|
|
18101
|
+
function describeEmailSenderProblem(value) {
|
|
18102
|
+
if (hasControlCharacters(value)) {
|
|
18103
|
+
return "Sender must not contain line breaks or control characters!";
|
|
18104
|
+
}
|
|
18105
|
+
if (hasBidiFormatting(value)) {
|
|
18106
|
+
return "Sender must not contain bidirectional formatting characters!";
|
|
18107
|
+
}
|
|
18108
|
+
if (emailAddressSchema.safeParse(value).success) return null;
|
|
18109
|
+
const open = value.lastIndexOf("<");
|
|
18110
|
+
if (open < 0 || !value.endsWith(">") || value.trim() !== value) {
|
|
18111
|
+
return "Sender must be an email address (noreply@example.com) or a display name followed by an address in angle brackets (Example <noreply@example.com>)!";
|
|
18112
|
+
}
|
|
18113
|
+
const address = value.slice(open + 1, -1);
|
|
18114
|
+
const name = value.slice(0, open).trimEnd();
|
|
18115
|
+
if (!emailAddressSchema.safeParse(address).success) {
|
|
18116
|
+
return "Sender address in angle brackets must be a valid email address!";
|
|
18117
|
+
}
|
|
18118
|
+
const quoted = name.length >= 2 && name.startsWith('"') && name.endsWith('"');
|
|
18119
|
+
const text = quoted ? name.slice(1, -1) : name;
|
|
18120
|
+
if (text.trim().length === 0) {
|
|
18121
|
+
return "Sender display name must not be empty!";
|
|
18122
|
+
}
|
|
18123
|
+
if (/[<>"\\]/.test(text)) {
|
|
18124
|
+
return "Sender display name must not contain angle brackets, double quotes or backslashes!";
|
|
18125
|
+
}
|
|
18126
|
+
if (!quoted && DISPLAY_NAME_SPECIALS.test(text)) {
|
|
18127
|
+
return 'Sender display names containing ( ) [ ] : ; @ or , must be wrapped in double quotes (e.g. "Example, Inc." <noreply@example.com>)!';
|
|
18128
|
+
}
|
|
18129
|
+
return null;
|
|
18130
|
+
}
|
|
18131
|
+
var emailSenderSchema = external_exports.string().superRefine((value, ctx) => {
|
|
18132
|
+
const problem = describeEmailSenderProblem(value);
|
|
18133
|
+
if (problem !== null) {
|
|
18134
|
+
ctx.addIssue({ code: "custom", message: problem });
|
|
18135
|
+
}
|
|
18136
|
+
});
|
|
18137
|
+
|
|
18072
18138
|
// src/send-email-request-body-schema.ts
|
|
18073
18139
|
var sendEmailTemplateOptions = external_exports.object({
|
|
18074
18140
|
template_id: emailTemplateIdSchema,
|
|
@@ -18084,6 +18150,13 @@ var sendRawEmailOptions = external_exports.object({
|
|
|
18084
18150
|
html: true
|
|
18085
18151
|
}).strict();
|
|
18086
18152
|
var MAX_RECIPIENTS = 50;
|
|
18153
|
+
function hasHeaderUnsafeCharacters(value) {
|
|
18154
|
+
for (let i = 0; i < value.length; i++) {
|
|
18155
|
+
const code = value.charCodeAt(i);
|
|
18156
|
+
if (code < 32 && code !== 9 || code === 127) return true;
|
|
18157
|
+
}
|
|
18158
|
+
return false;
|
|
18159
|
+
}
|
|
18087
18160
|
function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
|
|
18088
18161
|
if (allow_mailing_list_ids_as_recipients) {
|
|
18089
18162
|
return external_exports.union([
|
|
@@ -18106,8 +18179,15 @@ function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
|
|
|
18106
18179
|
function createSendEmailRequestBodySchema(allow_mailing_list_ids_as_recipients = false) {
|
|
18107
18180
|
return external_exports.object({
|
|
18108
18181
|
to: createRecipientSchema(allow_mailing_list_ids_as_recipients),
|
|
18109
|
-
|
|
18110
|
-
|
|
18182
|
+
/**
|
|
18183
|
+
* Who the email is from: a bare address, or a display name followed by
|
|
18184
|
+
* the address in angle brackets ("Example <noreply@example.com>").
|
|
18185
|
+
* When omitted, the mail-server uses its configured default sender.
|
|
18186
|
+
*/
|
|
18187
|
+
from: emailSenderSchema.optional(),
|
|
18188
|
+
subject: external_exports.string().nonempty().refine((subject) => !hasHeaderUnsafeCharacters(subject), {
|
|
18189
|
+
message: "Subject must not contain line breaks or control characters!"
|
|
18190
|
+
}),
|
|
18111
18191
|
message: external_exports.union([sendEmailTemplateOptions, sendRawEmailOptions]),
|
|
18112
18192
|
replyTo: external_exports.string().email().optional(),
|
|
18113
18193
|
cc: external_exports.union([
|
|
@@ -18447,7 +18527,10 @@ async function withErrorHandling(fn) {
|
|
|
18447
18527
|
}
|
|
18448
18528
|
}
|
|
18449
18529
|
function attachBodyOptions(cmd) {
|
|
18450
|
-
return cmd.option(
|
|
18530
|
+
return cmd.option(
|
|
18531
|
+
"--from <sender>",
|
|
18532
|
+
'Sender email address, optionally with a display name ("Example <noreply@example.com>")'
|
|
18533
|
+
).option("--subject <subject>", "Email subject").option("--reply-to <email>", "Reply-To email address").option(
|
|
18451
18534
|
"--template-id <id>",
|
|
18452
18535
|
"Email template ID (mutually exclusive with --text/--html)"
|
|
18453
18536
|
).option(
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { sendEmailRequestBodySchema, createSendEmailRequestBodySchema, } from ".
|
|
|
2
2
|
export type { SendEmailRequestBody } from "./send-email-request-body-schema.js";
|
|
3
3
|
export { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
|
|
4
4
|
export { transportIdSchema } from "./validators/transport-id-schema.js";
|
|
5
|
+
export { emailSenderSchema } from "./validators/email-sender-schema.js";
|
|
5
6
|
export { emailAttachmentSchema, emailAttachmentsSchema, MAX_ATTACHMENTS_PER_EMAIL, MAX_TOTAL_ATTACHMENT_BYTES, } from "./validators/email-attachment-schema.js";
|
|
6
7
|
export type { EmailAttachment } from "./validators/email-attachment-schema.js";
|
|
7
8
|
export { createEmailAttachment } from "./create-email-attachment.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { sendEmailRequestBodySchema, createSendEmailRequestBodySchema, } from "./send-email-request-body-schema.js";
|
|
2
2
|
export { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
|
|
3
3
|
export { transportIdSchema } from "./validators/transport-id-schema.js";
|
|
4
|
+
export { emailSenderSchema } from "./validators/email-sender-schema.js";
|
|
4
5
|
export { emailAttachmentSchema, emailAttachmentsSchema, MAX_ATTACHMENTS_PER_EMAIL, MAX_TOTAL_ATTACHMENT_BYTES, } from "./validators/email-attachment-schema.js";
|
|
5
6
|
export { createEmailAttachment } from "./create-email-attachment.js";
|
|
6
7
|
export { sendEmail, sendEmail as default, } from "./send-email.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EACL,SAAS,EACT,SAAS,IAAI,OAAO,GACrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EACL,SAAS,EACT,SAAS,IAAI,OAAO,GACrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,gBAAgB,EACjB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { emailTemplateIdSchema } from "./validators/email-template-id-schema.js";
|
|
3
3
|
import { transportIdSchema } from "./validators/transport-id-schema.js";
|
|
4
4
|
import { emailAttachmentsSchema } from "./validators/email-attachment-schema.js";
|
|
5
|
+
import { emailSenderSchema } from "./validators/email-sender-schema.js";
|
|
5
6
|
const sendEmailTemplateOptions = z
|
|
6
7
|
.object({
|
|
7
8
|
template_id: emailTemplateIdSchema,
|
|
@@ -22,6 +23,16 @@ const sendRawEmailOptions = z
|
|
|
22
23
|
})
|
|
23
24
|
.strict();
|
|
24
25
|
const MAX_RECIPIENTS = 50;
|
|
26
|
+
// C0 controls except HTAB, plus DEL: a line break in a header value can
|
|
27
|
+
// start a new header (e.g. `Bcc:`).
|
|
28
|
+
function hasHeaderUnsafeCharacters(value) {
|
|
29
|
+
for (let i = 0; i < value.length; i++) {
|
|
30
|
+
const code = value.charCodeAt(i);
|
|
31
|
+
if ((code < 0x20 && code !== 0x09) || code === 0x7f)
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
25
36
|
export function createRecipientSchema(allow_mailing_list_ids_as_recipients = false) {
|
|
26
37
|
if (allow_mailing_list_ids_as_recipients) {
|
|
27
38
|
return z.union([
|
|
@@ -46,8 +57,18 @@ export function createSendEmailRequestBodySchema(allow_mailing_list_ids_as_recip
|
|
|
46
57
|
return z
|
|
47
58
|
.object({
|
|
48
59
|
to: createRecipientSchema(allow_mailing_list_ids_as_recipients),
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Who the email is from: a bare address, or a display name followed by
|
|
62
|
+
* the address in angle brackets ("Example <noreply@example.com>").
|
|
63
|
+
* When omitted, the mail-server uses its configured default sender.
|
|
64
|
+
*/
|
|
65
|
+
from: emailSenderSchema.optional(),
|
|
66
|
+
subject: z
|
|
67
|
+
.string()
|
|
68
|
+
.nonempty()
|
|
69
|
+
.refine((subject) => !hasHeaderUnsafeCharacters(subject), {
|
|
70
|
+
message: "Subject must not contain line breaks or control characters!",
|
|
71
|
+
}),
|
|
51
72
|
message: z.union([sendEmailTemplateOptions, sendRawEmailOptions]),
|
|
52
73
|
replyTo: z.string().email().optional(),
|
|
53
74
|
cc: z
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-email-request-body-schema.js","sourceRoot":"","sources":["../src/send-email-request-body-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"send-email-request-body-schema.js","sourceRoot":"","sources":["../src/send-email-request-body-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,8 @@ export declare const MAX_TOTAL_ATTACHMENT_BYTES: number;
|
|
|
18
18
|
export declare function base64DecodedByteLength(base64: string): number;
|
|
19
19
|
/**
|
|
20
20
|
* Name the recipient's mail client shows for the attached file. Unicode is
|
|
21
|
-
* allowed; path separators
|
|
21
|
+
* allowed; path separators, control characters and bidirectional formatting
|
|
22
|
+
* characters are not.
|
|
22
23
|
*/
|
|
23
24
|
export declare const attachmentFilenameSchema: z.ZodString;
|
|
24
25
|
/**
|
|
@@ -29,14 +30,16 @@ export declare const attachmentFilenameSchema: z.ZodString;
|
|
|
29
30
|
export declare const attachmentContentSchema: z.ZodBase64;
|
|
30
31
|
/**
|
|
31
32
|
* MIME type of the attachment, e.g. "application/pdf" or
|
|
32
|
-
* "text/csv; charset=utf-8". When omitted, the
|
|
33
|
-
* derives it from the filename's extension.
|
|
33
|
+
* "text/csv; charset=utf-8". Printable ASCII only. When omitted, the
|
|
34
|
+
* mail-server's transport derives it from the filename's extension.
|
|
34
35
|
*/
|
|
35
36
|
export declare const attachmentContentTypeSchema: z.ZodString;
|
|
36
37
|
/**
|
|
37
38
|
* Content-ID for inline attachments. Setting it marks the attachment as
|
|
38
39
|
* inline so the HTML body can reference it as `<img src="cid:<contentId>">`.
|
|
39
|
-
* Pass the bare identifier -- without the angle brackets.
|
|
40
|
+
* Pass the bare identifier -- without the angle brackets. Content-ID is an
|
|
41
|
+
* ASCII header; anything else is emitted as an encoded-word that no longer
|
|
42
|
+
* matches the HTML's `cid:` reference.
|
|
40
43
|
*/
|
|
41
44
|
export declare const attachmentContentIdSchema: z.ZodString;
|
|
42
45
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { hasBidiFormatting, hasControlCharacters, } from "../validators/unsafe-characters.js";
|
|
2
3
|
/**
|
|
3
4
|
* Maximum number of attachments accepted on a single email.
|
|
4
5
|
*/
|
|
@@ -25,17 +26,10 @@ export function base64DecodedByteLength(base64) {
|
|
|
25
26
|
padding = 1;
|
|
26
27
|
return Math.floor((base64.length * 3) / 4) - padding;
|
|
27
28
|
}
|
|
28
|
-
function hasControlCharacters(value) {
|
|
29
|
-
for (let i = 0; i < value.length; i++) {
|
|
30
|
-
const code = value.charCodeAt(i);
|
|
31
|
-
if (code < 0x20 || code === 0x7f)
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
29
|
/**
|
|
37
30
|
* Name the recipient's mail client shows for the attached file. Unicode is
|
|
38
|
-
* allowed; path separators
|
|
31
|
+
* allowed; path separators, control characters and bidirectional formatting
|
|
32
|
+
* characters are not.
|
|
39
33
|
*/
|
|
40
34
|
export const attachmentFilenameSchema = z
|
|
41
35
|
.string()
|
|
@@ -49,6 +43,9 @@ export const attachmentFilenameSchema = z
|
|
|
49
43
|
})
|
|
50
44
|
.refine((name) => !hasControlCharacters(name), {
|
|
51
45
|
message: "Attachment filename must not contain control characters!",
|
|
46
|
+
})
|
|
47
|
+
.refine((name) => !hasBidiFormatting(name), {
|
|
48
|
+
message: "Attachment filename must not contain bidirectional formatting characters!",
|
|
52
49
|
});
|
|
53
50
|
/**
|
|
54
51
|
* The attached file's bytes, base64-encoded (standard alphabet, padded, no
|
|
@@ -59,26 +56,34 @@ export const attachmentContentSchema = z
|
|
|
59
56
|
.base64("Attachment content must be base64-encoded!")
|
|
60
57
|
.min(1, "Attachment content must not be empty!");
|
|
61
58
|
const MIME_TOKEN = "[A-Za-z0-9!#$&^_.+-]+";
|
|
59
|
+
// Printable ASCII only, so no value can carry CR/LF or other controls out of
|
|
60
|
+
// its header. Quoted: anything printable but `"`. Unquoted: printable minus
|
|
61
|
+
// space, `"` and `;`.
|
|
62
|
+
const MIME_PARAM_VALUE = '(?:"[\\x20\\x21\\x23-\\x7E]*"|[\\x21\\x23-\\x3A\\x3C-\\x7E]+)';
|
|
62
63
|
/**
|
|
63
64
|
* MIME type of the attachment, e.g. "application/pdf" or
|
|
64
|
-
* "text/csv; charset=utf-8". When omitted, the
|
|
65
|
-
* derives it from the filename's extension.
|
|
65
|
+
* "text/csv; charset=utf-8". Printable ASCII only. When omitted, the
|
|
66
|
+
* mail-server's transport derives it from the filename's extension.
|
|
66
67
|
*/
|
|
67
68
|
export const attachmentContentTypeSchema = z
|
|
68
69
|
.string()
|
|
69
70
|
.min(1, "Attachment content type must be non-empty!")
|
|
70
71
|
.max(255, "Attachment content type must be at most 255 characters!")
|
|
71
|
-
.regex(
|
|
72
|
+
.regex(
|
|
73
|
+
// `[ \t]*`, not `\s*`: `\s` matches CR/LF.
|
|
74
|
+
new RegExp(`^${MIME_TOKEN}\\/${MIME_TOKEN}(?:[ \\t]*;[ \\t]*${MIME_TOKEN}=${MIME_PARAM_VALUE})*$`), "Attachment content type must be a MIME type such as 'application/pdf'!");
|
|
72
75
|
/**
|
|
73
76
|
* Content-ID for inline attachments. Setting it marks the attachment as
|
|
74
77
|
* inline so the HTML body can reference it as `<img src="cid:<contentId>">`.
|
|
75
|
-
* Pass the bare identifier -- without the angle brackets.
|
|
78
|
+
* Pass the bare identifier -- without the angle brackets. Content-ID is an
|
|
79
|
+
* ASCII header; anything else is emitted as an encoded-word that no longer
|
|
80
|
+
* matches the HTML's `cid:` reference.
|
|
76
81
|
*/
|
|
77
82
|
export const attachmentContentIdSchema = z
|
|
78
83
|
.string()
|
|
79
84
|
.min(1, "Attachment content ID must be non-empty!")
|
|
80
85
|
.max(255, "Attachment content ID must be at most 255 characters!")
|
|
81
|
-
.regex(/^[
|
|
86
|
+
.regex(/^[\x21-\x3B\x3D\x3F-\x7E]+$/, "Attachment content ID must be printable ASCII without spaces or angle brackets!");
|
|
82
87
|
/**
|
|
83
88
|
* A single file attached to an email, in the shape accepted by the
|
|
84
89
|
* `@schemavaults/mail-server` `/api/send` route.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-attachment-schema.js","sourceRoot":"","sources":["../../src/validators/email-attachment-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"email-attachment-schema.js","sourceRoot":"","sources":["../../src/validators/email-attachment-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Who an email is from: a bare address ("noreply@example.com"), or a display
|
|
4
|
+
* name followed by the address in angle brackets
|
|
5
|
+
* ("Example <noreply@example.com>"). Unicode display names are allowed; one
|
|
6
|
+
* containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes
|
|
7
|
+
* ('"Example, Inc." <noreply@example.com>'). Control characters, bidi
|
|
8
|
+
* formatting characters, and angle brackets, double quotes or backslashes
|
|
9
|
+
* within the display name are rejected.
|
|
10
|
+
*/
|
|
11
|
+
export declare const emailSenderSchema: z.ZodString;
|
|
12
|
+
export default emailSenderSchema;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { hasBidiFormatting, hasControlCharacters, } from "../validators/unsafe-characters.js";
|
|
3
|
+
const emailAddressSchema = z.string().email();
|
|
4
|
+
// RFC 5322 specials a display name may only carry inside double quotes.
|
|
5
|
+
// "." is a special too, but every mail client accepts it unquoted (as in
|
|
6
|
+
// "Example Inc. <noreply@example.com>"), so it is allowed.
|
|
7
|
+
const DISPLAY_NAME_SPECIALS = /[()[\]:;@,]/;
|
|
8
|
+
/**
|
|
9
|
+
* Why `value` is not an acceptable sender, or null when it is. Accepts a bare
|
|
10
|
+
* address, or a display name followed by the address in angle brackets.
|
|
11
|
+
*/
|
|
12
|
+
function describeEmailSenderProblem(value) {
|
|
13
|
+
if (hasControlCharacters(value)) {
|
|
14
|
+
return "Sender must not contain line breaks or control characters!";
|
|
15
|
+
}
|
|
16
|
+
if (hasBidiFormatting(value)) {
|
|
17
|
+
return "Sender must not contain bidirectional formatting characters!";
|
|
18
|
+
}
|
|
19
|
+
if (emailAddressSchema.safeParse(value).success)
|
|
20
|
+
return null;
|
|
21
|
+
// Split on the last "<" rather than with a regex: one with optional spaces
|
|
22
|
+
// around the split backtracks quadratically on long input. Any other angle
|
|
23
|
+
// bracket is rejected below, so the bracketed address is the only one.
|
|
24
|
+
const open = value.lastIndexOf("<");
|
|
25
|
+
if (open < 0 || !value.endsWith(">") || value.trim() !== value) {
|
|
26
|
+
return "Sender must be an email address (noreply@example.com) or a display name followed by an address in angle brackets (Example <noreply@example.com>)!";
|
|
27
|
+
}
|
|
28
|
+
const address = value.slice(open + 1, -1);
|
|
29
|
+
const name = value.slice(0, open).trimEnd();
|
|
30
|
+
if (!emailAddressSchema.safeParse(address).success) {
|
|
31
|
+
return "Sender address in angle brackets must be a valid email address!";
|
|
32
|
+
}
|
|
33
|
+
const quoted = name.length >= 2 && name.startsWith('"') && name.endsWith('"');
|
|
34
|
+
const text = quoted ? name.slice(1, -1) : name;
|
|
35
|
+
if (text.trim().length === 0) {
|
|
36
|
+
return "Sender display name must not be empty!";
|
|
37
|
+
}
|
|
38
|
+
if (/[<>"\\]/.test(text)) {
|
|
39
|
+
return "Sender display name must not contain angle brackets, double quotes or backslashes!";
|
|
40
|
+
}
|
|
41
|
+
if (!quoted && DISPLAY_NAME_SPECIALS.test(text)) {
|
|
42
|
+
return 'Sender display names containing ( ) [ ] : ; @ or , must be wrapped in double quotes (e.g. "Example, Inc." <noreply@example.com>)!';
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Who an email is from: a bare address ("noreply@example.com"), or a display
|
|
48
|
+
* name followed by the address in angle brackets
|
|
49
|
+
* ("Example <noreply@example.com>"). Unicode display names are allowed; one
|
|
50
|
+
* containing any of `( ) [ ] : ; @ ,` must be wrapped in double quotes
|
|
51
|
+
* ('"Example, Inc." <noreply@example.com>'). Control characters, bidi
|
|
52
|
+
* formatting characters, and angle brackets, double quotes or backslashes
|
|
53
|
+
* within the display name are rejected.
|
|
54
|
+
*/
|
|
55
|
+
export const emailSenderSchema = z.string().superRefine((value, ctx) => {
|
|
56
|
+
const problem = describeEmailSenderProblem(value);
|
|
57
|
+
if (problem !== null) {
|
|
58
|
+
ctx.addIssue({ code: "custom", message: problem });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
export default emailSenderSchema;
|
|
62
|
+
//# sourceMappingURL=email-sender-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-sender-schema.js","sourceRoot":"","sources":["../../src/validators/email-sender-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AAExC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;AAE9C,wEAAwE;AACxE,yEAAyE;AACzE,2DAA2D;AAC3D,MAAM,qBAAqB,GAAG,aAAa,CAAC;AAE5C;;;GAGG;AACH,SAAS,0BAA0B,CAAC,KAAa;IAC/C,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,4DAA4D,CAAC;IACtE,CAAC;IACD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,8DAA8D,CAAC;IACxE,CAAC;IACD,IAAI,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE7D,2EAA2E;IAC3E,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;QAC/D,OAAO,mJAAmJ,CAAC;IAC7J,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5C,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;QACnD,OAAO,iEAAiE,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,wCAAwC,CAAC;IAClD,CAAC;IACD,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,oFAAoF,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,mIAAmI,CAAC;IAC7I,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACrE,MAAM,OAAO,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// C0, DEL and C1 controls.
|
|
2
|
+
export function hasControlCharacters(value) {
|
|
3
|
+
for (let i = 0; i < value.length; i++) {
|
|
4
|
+
const code = value.charCodeAt(i);
|
|
5
|
+
if (code < 0x20 || (code >= 0x7f && code <= 0x9f))
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
// Bidirectional formatting characters (ALM, LRM, RLM, LRE through RLO, LRI
|
|
11
|
+
// through PDI) let a filename like "invoice<U+202E>fdp.exe" display as
|
|
12
|
+
// "invoiceexe.pdf". Listed as code points because the characters are
|
|
13
|
+
// invisible in source.
|
|
14
|
+
const BIDI_FORMATTING = new Set([
|
|
15
|
+
0x061c, 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x2066,
|
|
16
|
+
0x2067, 0x2068, 0x2069,
|
|
17
|
+
]);
|
|
18
|
+
export function hasBidiFormatting(value) {
|
|
19
|
+
for (let i = 0; i < value.length; i++) {
|
|
20
|
+
if (BIDI_FORMATTING.has(value.charCodeAt(i)))
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=unsafe-characters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsafe-characters.js","sourceRoot":"","sources":["../../src/validators/unsafe-characters.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,2EAA2E;AAC3E,uEAAuE;AACvE,qEAAqE;AACrE,uBAAuB;AACvB,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACtE,MAAM,EAAE,MAAM,EAAE,MAAM;CACvB,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED