@primitivedotdev/sdk 0.6.0 → 0.8.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 +114 -210
- package/dist/address-parser-CfPHs3mE.js +113 -0
- package/dist/api/generated/index.js +1 -1
- package/dist/api/generated/sdk.gen.js +17 -0
- package/dist/api/index.d.ts +4 -1877
- package/dist/api/index.js +255 -0
- package/dist/api-BH8PnmHs.js +1338 -0
- package/dist/contract/index.d.ts +3 -2
- package/dist/contract/index.js +3 -1
- package/dist/{index-DLmAI4UQ.d.ts → index-CuuP1JkG.d.ts} +9 -2
- package/dist/index-D9lanVFt.d.ts +2145 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +13 -2
- package/dist/openapi/openapi.generated.js +413 -1
- package/dist/openapi/operations.generated.js +16 -0
- package/dist/parser/address-parser.js +129 -0
- package/dist/parser/index.d.ts +105 -3
- package/dist/parser/index.js +2 -1
- package/dist/received-email-C67Z7Dha.d.ts +36 -0
- package/dist/received-email-Q6Cha3wc.js +71 -0
- package/dist/types.generated.js +7 -0
- package/dist/types.js +53 -0
- package/dist/webhook/index.d.ts +4 -3
- package/dist/webhook/index.js +4 -2
- package/dist/webhook/received-email.js +82 -0
- package/dist/{webhook-COe5N_Uj.js → webhook-2TALcBQz.js} +16 -1
- package/oclif.manifest.json +47 -1
- package/package.json +10 -3
- /package/dist/{types-CKFmgitP.d.ts → types-CIOzt1FY.d.ts} +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import addressparser from "nodemailer/lib/addressparser/index.js";
|
|
2
|
+
import isEmail from "validator/lib/isEmail.js";
|
|
3
|
+
// Per RFC 5322 §2.1.1, header lines are bounded at 998 octets. We measure
|
|
4
|
+
// in UTF-8 bytes, not JS code units, so SMTPUTF8 (RFC 6531) headers with
|
|
5
|
+
// multi-byte characters cannot bypass the cap by being short on chars but
|
|
6
|
+
// long on bytes. Reject anything beyond as malformed without parsing: a
|
|
7
|
+
// longer From field is either a header-injection probe or a corrupt feed.
|
|
8
|
+
const MAX_HEADER_LENGTH = 998;
|
|
9
|
+
// Options for validator's isEmail. The per-part length limits (64-octet
|
|
10
|
+
// local-part, 255-octet domain), dot-atom rules, hostname-label rules,
|
|
11
|
+
// and TLD requirement are all enforced inside isEmail. We choose:
|
|
12
|
+
// allow_ip_domain: true -- accept user@[192.168.1.1] address-literals
|
|
13
|
+
// require_tld: true -- reject user@localhost
|
|
14
|
+
// allow_display_name: false -- we already extracted the address with
|
|
15
|
+
// addressparser, so isEmail only sees the
|
|
16
|
+
// bare addr-spec
|
|
17
|
+
// allow_utf8_local_part: true -- accept SMTPUTF8 / EAI local-parts
|
|
18
|
+
const IS_EMAIL_OPTIONS = {
|
|
19
|
+
allow_ip_domain: true,
|
|
20
|
+
require_tld: true,
|
|
21
|
+
allow_display_name: false,
|
|
22
|
+
allow_utf8_local_part: true,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Strict parser for RFC 5322 From-style headers in security-bearing
|
|
26
|
+
* contexts (allowlist gates, permission grants).
|
|
27
|
+
*
|
|
28
|
+
* Rejects, without falling back to a "best guess":
|
|
29
|
+
* - empty / whitespace-only input
|
|
30
|
+
* - inputs longer than RFC 5322's 998-octet line limit
|
|
31
|
+
* - multi-address From (RFC 5322 allows it but it is vanishingly
|
|
32
|
+
* rare and ambiguous as an identity)
|
|
33
|
+
* - group syntax ("Friends: a@b.com, c@d.com;")
|
|
34
|
+
* - any address that fails validator's isEmail check with our chosen
|
|
35
|
+
* options. That covers per-part length limits, dot-atom rules,
|
|
36
|
+
* hostname-label rules, TLD requirement, and other RFC 5321/5322
|
|
37
|
+
* conformance checks.
|
|
38
|
+
*
|
|
39
|
+
* Returns ONLY the validated address, with no display name. Strict
|
|
40
|
+
* exists for gating decisions, where the address is the security-
|
|
41
|
+
* bearing field. Display names from addressparser are not trustworthy
|
|
42
|
+
* here: weird inputs like `Name <user@x.com> <attacker@y.com>` get
|
|
43
|
+
* parsed as a single entry whose `name` silently includes the second
|
|
44
|
+
* address. Surfacing that as a "parsed name" would invite downstream
|
|
45
|
+
* misuse, so we drop it. If you need the name, call
|
|
46
|
+
* {@link parseFromHeaderLoose} alongside (it returns null on failure
|
|
47
|
+
* anyway, so you can still gate on strict's Result).
|
|
48
|
+
*
|
|
49
|
+
* Returns a typed Result so callers can map the failure reason to
|
|
50
|
+
* stable error codes without inspecting message text.
|
|
51
|
+
*/
|
|
52
|
+
export function parseFromHeader(header) {
|
|
53
|
+
if (header === null || header === undefined) {
|
|
54
|
+
return { ok: false, reason: "empty" };
|
|
55
|
+
}
|
|
56
|
+
const trimmed = header.trim();
|
|
57
|
+
if (trimmed.length === 0) {
|
|
58
|
+
return { ok: false, reason: "empty" };
|
|
59
|
+
}
|
|
60
|
+
if (Buffer.byteLength(trimmed, "utf8") > MAX_HEADER_LENGTH) {
|
|
61
|
+
return { ok: false, reason: "too_long" };
|
|
62
|
+
}
|
|
63
|
+
// Default (no flatten) so group entries surface as { name, group: [] }
|
|
64
|
+
// rather than being silently merged into the address list.
|
|
65
|
+
const parsed = addressparser(trimmed);
|
|
66
|
+
if (parsed.length > 1) {
|
|
67
|
+
return { ok: false, reason: "multiple_addresses" };
|
|
68
|
+
}
|
|
69
|
+
const entry = parsed[0];
|
|
70
|
+
// addressparser returns a single entry with empty `address` for raw
|
|
71
|
+
// garbage rather than an empty array, so an empty result is only
|
|
72
|
+
// possible for inputs that already failed our trim/empty check above.
|
|
73
|
+
// The defensive fall-through maps any future regression to
|
|
74
|
+
// invalid_address rather than crashing on parsed[0].
|
|
75
|
+
if (entry === undefined) {
|
|
76
|
+
return { ok: false, reason: "invalid_address" };
|
|
77
|
+
}
|
|
78
|
+
if ("group" in entry) {
|
|
79
|
+
return { ok: false, reason: "group_syntax" };
|
|
80
|
+
}
|
|
81
|
+
const address = entry.address;
|
|
82
|
+
if (address === undefined || !isEmail(address, IS_EMAIL_OPTIONS)) {
|
|
83
|
+
return { ok: false, reason: "invalid_address" };
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
ok: true,
|
|
87
|
+
value: { address: address.toLowerCase() },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Lenient parser for display-only call sites (inbox card "from",
|
|
92
|
+
* log lines, debugging). Returns the first parseable address with its
|
|
93
|
+
* display name, or null.
|
|
94
|
+
*
|
|
95
|
+
* Differences from {@link parseFromHeader}:
|
|
96
|
+
* - Multi-address From returns the first address instead of rejecting
|
|
97
|
+
* - Group syntax is flattened into its member addresses
|
|
98
|
+
* - Returns null instead of a typed reason on failure
|
|
99
|
+
* - Includes the parsed display name in the result
|
|
100
|
+
*
|
|
101
|
+
* Do not use for permission gates or any decision that grants access.
|
|
102
|
+
* That is what {@link parseFromHeader} is for. Names returned here can
|
|
103
|
+
* include addressparser's recovery output (trailing tokens, garbage
|
|
104
|
+
* before the address); treat as opaque text for display.
|
|
105
|
+
*/
|
|
106
|
+
export function parseFromHeaderLoose(header) {
|
|
107
|
+
if (header === null || header === undefined) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const trimmed = header.trim();
|
|
111
|
+
if (trimmed.length === 0 ||
|
|
112
|
+
Buffer.byteLength(trimmed, "utf8") > MAX_HEADER_LENGTH) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const parsed = addressparser(trimmed);
|
|
116
|
+
for (const entry of parsed) {
|
|
117
|
+
const candidates = "group" in entry && Array.isArray(entry.group) ? entry.group : [entry];
|
|
118
|
+
for (const candidate of candidates) {
|
|
119
|
+
const address = candidate.address;
|
|
120
|
+
if (address !== undefined && isEmail(address, IS_EMAIL_OPTIONS)) {
|
|
121
|
+
return {
|
|
122
|
+
address: address.toLowerCase(),
|
|
123
|
+
name: candidate.name && candidate.name.length > 0 ? candidate.name : null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
package/dist/parser/index.d.ts
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
|
-
import { EmailAddress, ParsedDataComplete, WebhookAttachment } from "../types-
|
|
1
|
+
import { EmailAddress, ParsedDataComplete, WebhookAttachment } from "../types-CIOzt1FY.js";
|
|
2
2
|
|
|
3
|
+
//#region src/parser/address-parser.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A validated RFC 5322 address. Returned by the strict parser, which
|
|
6
|
+
* deliberately does not expose a display name.
|
|
7
|
+
*
|
|
8
|
+
* `address` is normalized to lowercase. Both the local-part and the
|
|
9
|
+
* domain are lowercased: RFC 5321 §2.4 permits case-sensitive local-
|
|
10
|
+
* parts, but every consumer mailbox in practice treats them as
|
|
11
|
+
* case-insensitive, and a case-sensitive grant key would split
|
|
12
|
+
* `Bob@x.com` from `bob@x.com` into separate rows and defeat the
|
|
13
|
+
* primary-key index on lookup.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A validated RFC 5322 address. Returned by the strict parser, which
|
|
17
|
+
* deliberately does not expose a display name.
|
|
18
|
+
*
|
|
19
|
+
* `address` is normalized to lowercase. Both the local-part and the
|
|
20
|
+
* domain are lowercased: RFC 5321 §2.4 permits case-sensitive local-
|
|
21
|
+
* parts, but every consumer mailbox in practice treats them as
|
|
22
|
+
* case-insensitive, and a case-sensitive grant key would split
|
|
23
|
+
* `Bob@x.com` from `bob@x.com` into separate rows and defeat the
|
|
24
|
+
* primary-key index on lookup.
|
|
25
|
+
*/
|
|
26
|
+
interface ValidatedAddress {
|
|
27
|
+
address: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A parsed RFC 5322 address with its display name. Returned by the
|
|
31
|
+
* loose parser for display-only call sites.
|
|
32
|
+
*
|
|
33
|
+
* `address` is lowercased on the same rationale as
|
|
34
|
+
* {@link ValidatedAddress}. The display name is preserved as provided
|
|
35
|
+
* (after addressparser's quote / encoded-word handling), or null if the
|
|
36
|
+
* header had no display name. Names from the loose parser are NOT
|
|
37
|
+
* trustworthy for downstream mail building: addressparser's recovery
|
|
38
|
+
* mode can fold trailing tokens or a second bracketed address into the
|
|
39
|
+
* name field. Treat as opaque text, sanitize before re-emitting.
|
|
40
|
+
*/
|
|
41
|
+
interface ParsedAddress {
|
|
42
|
+
address: string;
|
|
43
|
+
name: string | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Reason a strict From-header parse rejected the input. Stable enum so
|
|
47
|
+
* callers can branch on the reason without parsing message text.
|
|
48
|
+
*/
|
|
49
|
+
type ParseFromHeaderFailureReason = "empty" | "too_long" | "multiple_addresses" | "group_syntax" | "invalid_address";
|
|
50
|
+
type ParseFromHeaderResult = {
|
|
51
|
+
ok: true;
|
|
52
|
+
value: ValidatedAddress;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
reason: ParseFromHeaderFailureReason;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Strict parser for RFC 5322 From-style headers in security-bearing
|
|
59
|
+
* contexts (allowlist gates, permission grants).
|
|
60
|
+
*
|
|
61
|
+
* Rejects, without falling back to a "best guess":
|
|
62
|
+
* - empty / whitespace-only input
|
|
63
|
+
* - inputs longer than RFC 5322's 998-octet line limit
|
|
64
|
+
* - multi-address From (RFC 5322 allows it but it is vanishingly
|
|
65
|
+
* rare and ambiguous as an identity)
|
|
66
|
+
* - group syntax ("Friends: a@b.com, c@d.com;")
|
|
67
|
+
* - any address that fails validator's isEmail check with our chosen
|
|
68
|
+
* options. That covers per-part length limits, dot-atom rules,
|
|
69
|
+
* hostname-label rules, TLD requirement, and other RFC 5321/5322
|
|
70
|
+
* conformance checks.
|
|
71
|
+
*
|
|
72
|
+
* Returns ONLY the validated address, with no display name. Strict
|
|
73
|
+
* exists for gating decisions, where the address is the security-
|
|
74
|
+
* bearing field. Display names from addressparser are not trustworthy
|
|
75
|
+
* here: weird inputs like `Name <user@x.com> <attacker@y.com>` get
|
|
76
|
+
* parsed as a single entry whose `name` silently includes the second
|
|
77
|
+
* address. Surfacing that as a "parsed name" would invite downstream
|
|
78
|
+
* misuse, so we drop it. If you need the name, call
|
|
79
|
+
* {@link parseFromHeaderLoose} alongside (it returns null on failure
|
|
80
|
+
* anyway, so you can still gate on strict's Result).
|
|
81
|
+
*
|
|
82
|
+
* Returns a typed Result so callers can map the failure reason to
|
|
83
|
+
* stable error codes without inspecting message text.
|
|
84
|
+
*/
|
|
85
|
+
declare function parseFromHeader(header: string | null | undefined): ParseFromHeaderResult;
|
|
86
|
+
/**
|
|
87
|
+
* Lenient parser for display-only call sites (inbox card "from",
|
|
88
|
+
* log lines, debugging). Returns the first parseable address with its
|
|
89
|
+
* display name, or null.
|
|
90
|
+
*
|
|
91
|
+
* Differences from {@link parseFromHeader}:
|
|
92
|
+
* - Multi-address From returns the first address instead of rejecting
|
|
93
|
+
* - Group syntax is flattened into its member addresses
|
|
94
|
+
* - Returns null instead of a typed reason on failure
|
|
95
|
+
* - Includes the parsed display name in the result
|
|
96
|
+
*
|
|
97
|
+
* Do not use for permission gates or any decision that grants access.
|
|
98
|
+
* That is what {@link parseFromHeader} is for. Names returned here can
|
|
99
|
+
* include addressparser's recovery output (trailing tokens, garbage
|
|
100
|
+
* before the address); treat as opaque text for display.
|
|
101
|
+
*/
|
|
102
|
+
declare function parseFromHeaderLoose(header: string | null | undefined): ParsedAddress | null; //#endregion
|
|
3
103
|
//#region src/parser/attachment-parser.d.ts
|
|
4
104
|
interface ParsedAttachment {
|
|
5
105
|
id: string;
|
|
@@ -61,7 +161,9 @@ declare function sha256Hex(buffer: Buffer): string;
|
|
|
61
161
|
* Sanitize a filename for safe use in Content-Disposition headers.
|
|
62
162
|
* Prevents path traversal, removes control characters, enforces length limits.
|
|
63
163
|
*/
|
|
64
|
-
declare function sanitizeFilename(filename: string | null, partIndex: number): string;
|
|
164
|
+
declare function sanitizeFilename(filename: string | null, partIndex: number): string;
|
|
165
|
+
|
|
166
|
+
//#endregion
|
|
65
167
|
//#region src/parser/attachment-bundler.d.ts
|
|
66
168
|
/**
|
|
67
169
|
* Result of bundling attachments into a tar.gz archive
|
|
@@ -187,4 +289,4 @@ declare function toCanonicalHeaders(parsed: ParsedEmailWithAttachments): {
|
|
|
187
289
|
declare function sanitizeHtml(html: string): string;
|
|
188
290
|
|
|
189
291
|
//#endregion
|
|
190
|
-
export { AttachmentMetadata, BundleResult, ParsedAttachment, ParsedEmail, ParsedEmailWithAttachments, attachmentMetadataToWebhookAttachments, bundleAttachments, extractAttachmentMetadata, getAttachmentsStorageKey, normalizeContentType, parseEmail, parseEmailWithAttachments, sanitizeFilename, sanitizeHtml, sha256Hex, toCanonicalHeaders, toParsedDataComplete, toWebhookAttachments };
|
|
292
|
+
export { AttachmentMetadata, BundleResult, ParseFromHeaderFailureReason, ParseFromHeaderResult, ParsedAddress, ParsedAttachment, ParsedEmail, ParsedEmailWithAttachments, ValidatedAddress, attachmentMetadataToWebhookAttachments, bundleAttachments, extractAttachmentMetadata, getAttachmentsStorageKey, normalizeContentType, parseEmail, parseEmailWithAttachments, parseFromHeader, parseFromHeaderLoose, sanitizeFilename, sanitizeHtml, sha256Hex, toCanonicalHeaders, toParsedDataComplete, toWebhookAttachments };
|
package/dist/parser/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseFromHeader, parseFromHeaderLoose } from "../address-parser-CfPHs3mE.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { createGzip } from "node:zlib";
|
|
3
4
|
import { pack } from "tar-stream";
|
|
@@ -557,4 +558,4 @@ function requireNonEmptyHeader(value, headerName) {
|
|
|
557
558
|
}
|
|
558
559
|
|
|
559
560
|
//#endregion
|
|
560
|
-
export { attachmentMetadataToWebhookAttachments, bundleAttachments, extractAttachmentMetadata, getAttachmentsStorageKey, normalizeContentType, parseEmail, parseEmailWithAttachments, sanitizeFilename, sanitizeHtml, sha256Hex, toCanonicalHeaders, toParsedDataComplete, toWebhookAttachments };
|
|
561
|
+
export { attachmentMetadataToWebhookAttachments, bundleAttachments, extractAttachmentMetadata, getAttachmentsStorageKey, normalizeContentType, parseEmail, parseEmailWithAttachments, parseFromHeader, parseFromHeaderLoose, sanitizeFilename, sanitizeHtml, sha256Hex, toCanonicalHeaders, toParsedDataComplete, toWebhookAttachments };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { EmailAnalysis, EmailAuth, EmailReceivedEvent, WebhookAttachment } from "./types-CIOzt1FY.js";
|
|
2
|
+
|
|
3
|
+
//#region src/webhook/received-email.d.ts
|
|
4
|
+
interface ReceivedEmailAddress {
|
|
5
|
+
address: string;
|
|
6
|
+
name: string | null;
|
|
7
|
+
}
|
|
8
|
+
interface ReceivedEmailThread {
|
|
9
|
+
messageId: string | null;
|
|
10
|
+
inReplyTo: string[];
|
|
11
|
+
references: string[];
|
|
12
|
+
}
|
|
13
|
+
interface ReceivedEmail {
|
|
14
|
+
id: string;
|
|
15
|
+
eventId: string;
|
|
16
|
+
receivedAt: string;
|
|
17
|
+
sender: ReceivedEmailAddress;
|
|
18
|
+
replyTarget: ReceivedEmailAddress;
|
|
19
|
+
receivedBy: string;
|
|
20
|
+
receivedByAll: string[];
|
|
21
|
+
subject: string | null;
|
|
22
|
+
replySubject: string;
|
|
23
|
+
forwardSubject: string;
|
|
24
|
+
text: string | null;
|
|
25
|
+
thread: ReceivedEmailThread;
|
|
26
|
+
attachments: WebhookAttachment[];
|
|
27
|
+
auth: EmailAuth;
|
|
28
|
+
analysis: EmailAnalysis;
|
|
29
|
+
raw: EmailReceivedEvent;
|
|
30
|
+
}
|
|
31
|
+
declare function normalizeReceivedEmail(event: EmailReceivedEvent): ReceivedEmail;
|
|
32
|
+
declare function buildReplySubject(subject: string | null | undefined): string;
|
|
33
|
+
declare function buildForwardSubject(subject: string | null | undefined): string;
|
|
34
|
+
declare function formatAddress(address: ReceivedEmailAddress): string;
|
|
35
|
+
declare function parseHeaderAddress(value: string | null | undefined): ReceivedEmailAddress | null; //#endregion
|
|
36
|
+
export { ReceivedEmail, ReceivedEmailAddress, ReceivedEmailThread, buildForwardSubject as buildForwardSubject$1, buildReplySubject as buildReplySubject$1, formatAddress as formatAddress$1, normalizeReceivedEmail as normalizeReceivedEmail$1, parseHeaderAddress as parseHeaderAddress$1 };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseFromHeaderLoose } from "./address-parser-CfPHs3mE.js";
|
|
2
|
+
|
|
3
|
+
//#region src/webhook/received-email.ts
|
|
4
|
+
const REPLY_PREFIX_RE = /^re\s*:/i;
|
|
5
|
+
const FORWARD_PREFIX_RE = /^(fwd?|fw)\s*:/i;
|
|
6
|
+
function normalizeReceivedEmail(event) {
|
|
7
|
+
const receivedBy = event.email.smtp.rcpt_to[0];
|
|
8
|
+
if (!receivedBy) throw new Error("email.smtp.rcpt_to must contain at least one recipient");
|
|
9
|
+
const sender = parseHeaderAddress(event.email.headers.from) ?? {
|
|
10
|
+
address: event.email.smtp.mail_from.trim().toLowerCase(),
|
|
11
|
+
name: null
|
|
12
|
+
};
|
|
13
|
+
const replyTarget = firstStructuredAddress(event.email.parsed.reply_to) ?? sender;
|
|
14
|
+
const subject = event.email.headers.subject ?? null;
|
|
15
|
+
const references = event.email.parsed.references ?? [];
|
|
16
|
+
const messageId = event.email.headers.message_id ?? null;
|
|
17
|
+
return {
|
|
18
|
+
id: event.email.id,
|
|
19
|
+
eventId: event.id,
|
|
20
|
+
receivedAt: event.email.received_at,
|
|
21
|
+
sender,
|
|
22
|
+
replyTarget,
|
|
23
|
+
receivedBy,
|
|
24
|
+
receivedByAll: [...event.email.smtp.rcpt_to],
|
|
25
|
+
subject,
|
|
26
|
+
replySubject: buildReplySubject(subject),
|
|
27
|
+
forwardSubject: buildForwardSubject(subject),
|
|
28
|
+
text: event.email.parsed.body_text ?? null,
|
|
29
|
+
thread: {
|
|
30
|
+
messageId,
|
|
31
|
+
inReplyTo: event.email.parsed.in_reply_to ?? [],
|
|
32
|
+
references
|
|
33
|
+
},
|
|
34
|
+
attachments: event.email.parsed.attachments ?? [],
|
|
35
|
+
auth: event.email.auth,
|
|
36
|
+
analysis: event.email.analysis,
|
|
37
|
+
raw: event
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function buildReplySubject(subject) {
|
|
41
|
+
const trimmed = subject?.trim() ?? "";
|
|
42
|
+
if (trimmed.length === 0) return "Re:";
|
|
43
|
+
return REPLY_PREFIX_RE.test(trimmed) ? trimmed : `Re: ${trimmed}`;
|
|
44
|
+
}
|
|
45
|
+
function buildForwardSubject(subject) {
|
|
46
|
+
const trimmed = subject?.trim() ?? "";
|
|
47
|
+
if (trimmed.length === 0) return "Fwd:";
|
|
48
|
+
return FORWARD_PREFIX_RE.test(trimmed) ? trimmed : `Fwd: ${trimmed}`;
|
|
49
|
+
}
|
|
50
|
+
function formatAddress(address) {
|
|
51
|
+
return address.name ? `${address.name} <${address.address}>` : address.address;
|
|
52
|
+
}
|
|
53
|
+
function firstStructuredAddress(addresses) {
|
|
54
|
+
const address = addresses?.[0];
|
|
55
|
+
if (!address) return null;
|
|
56
|
+
return {
|
|
57
|
+
address: address.address.trim().toLowerCase(),
|
|
58
|
+
name: address.name ?? null
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function parseHeaderAddress(value) {
|
|
62
|
+
const parsed = parseFromHeaderLoose(value);
|
|
63
|
+
if (!parsed) return null;
|
|
64
|
+
return {
|
|
65
|
+
address: parsed.address,
|
|
66
|
+
name: parsed.name?.trim() || null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { buildForwardSubject, buildReplySubject, formatAddress, normalizeReceivedEmail, parseHeaderAddress };
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Primitive webhook event types derived from the canonical JSON schema.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export const EventType = {
|
|
7
|
+
EmailReceived: "email.received",
|
|
8
|
+
};
|
|
9
|
+
export const ParsedStatus = {
|
|
10
|
+
Complete: "complete",
|
|
11
|
+
Failed: "failed",
|
|
12
|
+
};
|
|
13
|
+
export const ForwardVerdict = {
|
|
14
|
+
Legit: "legit",
|
|
15
|
+
Unknown: "unknown",
|
|
16
|
+
};
|
|
17
|
+
export const SpfResult = {
|
|
18
|
+
Pass: "pass",
|
|
19
|
+
Fail: "fail",
|
|
20
|
+
Softfail: "softfail",
|
|
21
|
+
Neutral: "neutral",
|
|
22
|
+
None: "none",
|
|
23
|
+
Temperror: "temperror",
|
|
24
|
+
Permerror: "permerror",
|
|
25
|
+
};
|
|
26
|
+
export const DmarcResult = {
|
|
27
|
+
Pass: "pass",
|
|
28
|
+
Fail: "fail",
|
|
29
|
+
None: "none",
|
|
30
|
+
Temperror: "temperror",
|
|
31
|
+
Permerror: "permerror",
|
|
32
|
+
};
|
|
33
|
+
export const DmarcPolicy = {
|
|
34
|
+
Reject: "reject",
|
|
35
|
+
Quarantine: "quarantine",
|
|
36
|
+
None: "none",
|
|
37
|
+
};
|
|
38
|
+
export const DkimResult = {
|
|
39
|
+
Pass: "pass",
|
|
40
|
+
Fail: "fail",
|
|
41
|
+
Temperror: "temperror",
|
|
42
|
+
Permerror: "permerror",
|
|
43
|
+
};
|
|
44
|
+
export const AuthConfidence = {
|
|
45
|
+
High: "high",
|
|
46
|
+
Medium: "medium",
|
|
47
|
+
Low: "low",
|
|
48
|
+
};
|
|
49
|
+
export const AuthVerdict = {
|
|
50
|
+
Legit: "legit",
|
|
51
|
+
Suspicious: "suspicious",
|
|
52
|
+
Unknown: "unknown",
|
|
53
|
+
};
|
package/dist/webhook/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { AuthConfidence$1 as AuthConfidence, AuthVerdict$1 as AuthVerdict, DkimResult$1 as DkimResult, DkimSignature, DmarcPolicy$1 as DmarcPolicy, DmarcResult$1 as DmarcResult, EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, EventType$1 as EventType, ForwardAnalysis, ForwardOriginalSender, ForwardResult, ForwardResultAttachmentAnalyzed, ForwardResultAttachmentSkipped, ForwardResultInline, ForwardVerdict$1 as ForwardVerdict, ForwardVerification, KnownWebhookEvent, ParsedData, ParsedDataComplete, ParsedDataFailed, ParsedError, ParsedStatus$1 as ParsedStatus, RawContent, RawContentDownloadOnly, RawContentInline, SpfResult$1 as SpfResult, UnknownEvent, ValidateEmailAuthResult, WebhookAttachment, WebhookEvent } from "../types-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { AuthConfidence$1 as AuthConfidence, AuthVerdict$1 as AuthVerdict, DkimResult$1 as DkimResult, DkimSignature, DmarcPolicy$1 as DmarcPolicy, DmarcResult$1 as DmarcResult, EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, EventType$1 as EventType, ForwardAnalysis, ForwardOriginalSender, ForwardResult, ForwardResultAttachmentAnalyzed, ForwardResultAttachmentSkipped, ForwardResultInline, ForwardVerdict$1 as ForwardVerdict, ForwardVerification, KnownWebhookEvent, ParsedData, ParsedDataComplete, ParsedDataFailed, ParsedError, ParsedStatus$1 as ParsedStatus, RawContent, RawContentDownloadOnly, RawContentInline, SpfResult$1 as SpfResult, UnknownEvent, ValidateEmailAuthResult, WebhookAttachment, WebhookEvent } from "../types-CIOzt1FY.js";
|
|
2
|
+
import { ReceivedEmail, ReceivedEmailAddress, ReceivedEmailThread, buildForwardSubject$1 as buildForwardSubject, buildReplySubject$1 as buildReplySubject, formatAddress$1 as formatAddress, normalizeReceivedEmail$1 as normalizeReceivedEmail, parseHeaderAddress$1 as parseHeaderAddress } from "../received-email-C67Z7Dha.js";
|
|
3
|
+
import { DecodeRawEmailOptions, GenerateDownloadTokenOptions, HandleWebhookOptions, LEGACY_CONFIRMED_HEADER$1 as LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER$1 as LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS$1 as PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER$1 as PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER$1 as PRIMITIVE_SIGNATURE_HEADER, PrimitiveWebhookError$1 as PrimitiveWebhookError, RAW_EMAIL_ERRORS$1 as RAW_EMAIL_ERRORS, RawEmailDecodeError$1 as RawEmailDecodeError, RawEmailDecodeErrorCode, ReceiveRequestOptions, STANDARD_WEBHOOK_ID_HEADER$1 as STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER$1 as STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER$1 as STANDARD_WEBHOOK_TIMESTAMP_HEADER, SignResult, StandardWebhooksSignResult, StandardWebhooksVerifyOptions, VERIFICATION_ERRORS$1 as VERIFICATION_ERRORS, VerifyDownloadTokenOptions, VerifyDownloadTokenResult, VerifyOptions, WEBHOOK_VERSION$1 as WEBHOOK_VERSION, WebhookErrorCode, WebhookHeaders, WebhookPayloadError$1 as WebhookPayloadError, WebhookPayloadErrorCode, WebhookValidationError$1 as WebhookValidationError, WebhookValidationErrorCode, WebhookVerificationError$1 as WebhookVerificationError, WebhookVerificationErrorCode, confirmedHeaders$1 as confirmedHeaders, decodeRawEmail$1 as decodeRawEmail, emailReceivedEventJsonSchema$1 as emailReceivedEventJsonSchema, generateDownloadToken$1 as generateDownloadToken, getDownloadTimeRemaining$1 as getDownloadTimeRemaining, handleWebhook$1 as handleWebhook, isDownloadExpired$1 as isDownloadExpired, isEmailReceivedEvent$1 as isEmailReceivedEvent, isRawIncluded$1 as isRawIncluded, parseWebhookEvent$1 as parseWebhookEvent, receive$1 as receive, safeValidateEmailReceivedEvent$1 as safeValidateEmailReceivedEvent, signStandardWebhooksPayload$1 as signStandardWebhooksPayload, signWebhookPayload$1 as signWebhookPayload, validateEmailAuth$1 as validateEmailAuth, validateEmailReceivedEvent$1 as validateEmailReceivedEvent, verifyDownloadToken$1 as verifyDownloadToken, verifyRawEmailDownload$1 as verifyRawEmailDownload, verifyStandardWebhooksSignature$1 as verifyStandardWebhooksSignature, verifyWebhookSignature$1 as verifyWebhookSignature } from "../index-CuuP1JkG.js";
|
|
4
|
+
export { AuthConfidence, AuthVerdict, DecodeRawEmailOptions, DkimResult, DkimSignature, DmarcPolicy, DmarcResult, EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, EventType, ForwardAnalysis, ForwardOriginalSender, ForwardResult, ForwardResultAttachmentAnalyzed, ForwardResultAttachmentSkipped, ForwardResultInline, ForwardVerdict, ForwardVerification, GenerateDownloadTokenOptions, HandleWebhookOptions, KnownWebhookEvent, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedData, ParsedDataComplete, ParsedDataFailed, ParsedError, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawContent, RawContentDownloadOnly, RawContentInline, RawEmailDecodeError, RawEmailDecodeErrorCode, ReceiveRequestOptions, ReceivedEmail, ReceivedEmailAddress, ReceivedEmailThread, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SignResult, SpfResult, StandardWebhooksSignResult, StandardWebhooksVerifyOptions, UnknownEvent, VERIFICATION_ERRORS, ValidateEmailAuthResult, VerifyDownloadTokenOptions, VerifyDownloadTokenResult, VerifyOptions, WEBHOOK_VERSION, WebhookAttachment, WebhookErrorCode, WebhookEvent, WebhookHeaders, WebhookPayloadError, WebhookPayloadErrorCode, WebhookValidationError, WebhookValidationErrorCode, WebhookVerificationError, WebhookVerificationErrorCode, buildForwardSubject, buildReplySubject, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, formatAddress, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, normalizeReceivedEmail, parseHeaderAddress, parseWebhookEvent, receive, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature };
|
package/dist/webhook/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../address-parser-CfPHs3mE.js";
|
|
2
|
+
import { buildForwardSubject, buildReplySubject, formatAddress, normalizeReceivedEmail, parseHeaderAddress } from "../received-email-Q6Cha3wc.js";
|
|
3
|
+
import { AuthConfidence, AuthVerdict, DkimResult, DmarcPolicy, DmarcResult, EventType, ForwardVerdict, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawEmailDecodeError, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, receive, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature } from "../webhook-2TALcBQz.js";
|
|
2
4
|
|
|
3
|
-
export { AuthConfidence, AuthVerdict, DkimResult, DmarcPolicy, DmarcResult, EventType, ForwardVerdict, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawEmailDecodeError, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature };
|
|
5
|
+
export { AuthConfidence, AuthVerdict, DkimResult, DmarcPolicy, DmarcResult, EventType, ForwardVerdict, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawEmailDecodeError, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, buildForwardSubject, buildReplySubject, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, formatAddress, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, normalizeReceivedEmail, parseHeaderAddress, parseWebhookEvent, receive, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { parseFromHeaderLoose } from "../parser/address-parser.js";
|
|
2
|
+
const REPLY_PREFIX_RE = /^re\s*:/i;
|
|
3
|
+
const FORWARD_PREFIX_RE = /^(fwd?|fw)\s*:/i;
|
|
4
|
+
export function normalizeReceivedEmail(event) {
|
|
5
|
+
const receivedBy = event.email.smtp.rcpt_to[0];
|
|
6
|
+
if (!receivedBy) {
|
|
7
|
+
throw new Error("email.smtp.rcpt_to must contain at least one recipient");
|
|
8
|
+
}
|
|
9
|
+
const sender = parseHeaderAddress(event.email.headers.from) ?? {
|
|
10
|
+
address: event.email.smtp.mail_from.trim().toLowerCase(),
|
|
11
|
+
name: null,
|
|
12
|
+
};
|
|
13
|
+
const replyTarget = firstStructuredAddress(event.email.parsed.reply_to) ?? sender;
|
|
14
|
+
const subject = event.email.headers.subject ?? null;
|
|
15
|
+
const references = event.email.parsed.references ?? [];
|
|
16
|
+
const messageId = event.email.headers.message_id ?? null;
|
|
17
|
+
return {
|
|
18
|
+
id: event.email.id,
|
|
19
|
+
eventId: event.id,
|
|
20
|
+
receivedAt: event.email.received_at,
|
|
21
|
+
sender,
|
|
22
|
+
replyTarget,
|
|
23
|
+
receivedBy,
|
|
24
|
+
receivedByAll: [...event.email.smtp.rcpt_to],
|
|
25
|
+
subject,
|
|
26
|
+
replySubject: buildReplySubject(subject),
|
|
27
|
+
forwardSubject: buildForwardSubject(subject),
|
|
28
|
+
text: event.email.parsed.body_text ?? null,
|
|
29
|
+
thread: {
|
|
30
|
+
messageId,
|
|
31
|
+
inReplyTo: event.email.parsed.in_reply_to ?? [],
|
|
32
|
+
references,
|
|
33
|
+
},
|
|
34
|
+
attachments: event.email.parsed.attachments ?? [],
|
|
35
|
+
auth: event.email.auth,
|
|
36
|
+
analysis: event.email.analysis,
|
|
37
|
+
raw: event,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function buildReplySubject(subject) {
|
|
41
|
+
const trimmed = subject?.trim() ?? "";
|
|
42
|
+
if (trimmed.length === 0) {
|
|
43
|
+
return "Re:";
|
|
44
|
+
}
|
|
45
|
+
return REPLY_PREFIX_RE.test(trimmed) ? trimmed : `Re: ${trimmed}`;
|
|
46
|
+
}
|
|
47
|
+
export function buildForwardSubject(subject) {
|
|
48
|
+
const trimmed = subject?.trim() ?? "";
|
|
49
|
+
if (trimmed.length === 0) {
|
|
50
|
+
return "Fwd:";
|
|
51
|
+
}
|
|
52
|
+
return FORWARD_PREFIX_RE.test(trimmed) ? trimmed : `Fwd: ${trimmed}`;
|
|
53
|
+
}
|
|
54
|
+
export function formatAddress(address) {
|
|
55
|
+
return address.name
|
|
56
|
+
? `${address.name} <${address.address}>`
|
|
57
|
+
: address.address;
|
|
58
|
+
}
|
|
59
|
+
function firstStructuredAddress(addresses) {
|
|
60
|
+
const address = addresses?.[0];
|
|
61
|
+
if (!address) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
address: address.address.trim().toLowerCase(),
|
|
66
|
+
name: address.name ?? null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// Lenient about quirky headers (unquoted commas in display names, missing
|
|
70
|
+
// closing angle brackets) but strict about the resulting address: it must
|
|
71
|
+
// validate as an email, otherwise the normalizer falls back to the SMTP
|
|
72
|
+
// envelope sender. Exported so cross-SDK fixtures can exercise it directly.
|
|
73
|
+
export function parseHeaderAddress(value) {
|
|
74
|
+
const parsed = parseFromHeaderLoose(value);
|
|
75
|
+
if (!parsed) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
address: parsed.address,
|
|
80
|
+
name: parsed.name?.trim() || null,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeReceivedEmail } from "./received-email-Q6Cha3wc.js";
|
|
1
2
|
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
2
3
|
|
|
3
4
|
//#region src/generated/email-received-event.validator.generated.ts
|
|
@@ -7829,6 +7830,20 @@ function handleWebhook(options) {
|
|
|
7829
7830
|
const parsed = parseJsonBody(body);
|
|
7830
7831
|
return validateEmailReceivedEvent(parsed);
|
|
7831
7832
|
}
|
|
7833
|
+
function receive(input, options) {
|
|
7834
|
+
if (input instanceof Request) return receiveFromRequest(input, options);
|
|
7835
|
+
return normalizeReceivedEmail(handleWebhook(input));
|
|
7836
|
+
}
|
|
7837
|
+
async function receiveFromRequest(request, options) {
|
|
7838
|
+
if (!options?.secret) throw new WebhookVerificationError("MISSING_SECRET", "Webhook secret is required but was empty or not provided");
|
|
7839
|
+
const body = Buffer.from(await request.arrayBuffer());
|
|
7840
|
+
return normalizeReceivedEmail(handleWebhook({
|
|
7841
|
+
body,
|
|
7842
|
+
headers: request.headers,
|
|
7843
|
+
secret: options.secret,
|
|
7844
|
+
toleranceSeconds: options.toleranceSeconds
|
|
7845
|
+
}));
|
|
7846
|
+
}
|
|
7832
7847
|
/**
|
|
7833
7848
|
* Returns headers for the optional "content discard" feature.
|
|
7834
7849
|
*
|
|
@@ -8003,4 +8018,4 @@ function verifyRawEmailDownload(downloaded, event) {
|
|
|
8003
8018
|
}
|
|
8004
8019
|
|
|
8005
8020
|
//#endregion
|
|
8006
|
-
export { AuthConfidence, AuthVerdict, DkimResult, DmarcPolicy, DmarcResult, EventType, ForwardVerdict, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawEmailDecodeError, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature };
|
|
8021
|
+
export { AuthConfidence, AuthVerdict, DkimResult, DmarcPolicy, DmarcResult, EventType, ForwardVerdict, LEGACY_CONFIRMED_HEADER, LEGACY_SIGNATURE_HEADER, PAYLOAD_ERRORS, PRIMITIVE_CONFIRMED_HEADER, PRIMITIVE_SIGNATURE_HEADER, ParsedStatus, PrimitiveWebhookError, RAW_EMAIL_ERRORS, RawEmailDecodeError, STANDARD_WEBHOOK_ID_HEADER, STANDARD_WEBHOOK_SIGNATURE_HEADER, STANDARD_WEBHOOK_TIMESTAMP_HEADER, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, generateDownloadToken, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, receive, safeValidateEmailReceivedEvent, signStandardWebhooksPayload, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyDownloadToken, verifyRawEmailDownload, verifyStandardWebhooksSignature, verifyWebhookSignature };
|
package/oclif.manifest.json
CHANGED
|
@@ -1136,6 +1136,52 @@
|
|
|
1136
1136
|
"summary": "Update a filter rule",
|
|
1137
1137
|
"enableJsonFlag": false
|
|
1138
1138
|
},
|
|
1139
|
+
"sending:send-email": {
|
|
1140
|
+
"aliases": [],
|
|
1141
|
+
"args": {},
|
|
1142
|
+
"description": "Sends an outbound email through Primitive's outbound relay. By default\nthe request returns once the relay accepts the message for delivery.\nSet `wait: true` to wait for the first downstream SMTP delivery outcome.\n",
|
|
1143
|
+
"flags": {
|
|
1144
|
+
"api-key": {
|
|
1145
|
+
"description": "Primitive API key (defaults to PRIMITIVE_API_KEY)",
|
|
1146
|
+
"env": "PRIMITIVE_API_KEY",
|
|
1147
|
+
"name": "api-key",
|
|
1148
|
+
"hasDynamicHelp": false,
|
|
1149
|
+
"multiple": false,
|
|
1150
|
+
"type": "option"
|
|
1151
|
+
},
|
|
1152
|
+
"base-url": {
|
|
1153
|
+
"description": "API base URL (defaults to PRIMITIVE_API_URL or production)",
|
|
1154
|
+
"env": "PRIMITIVE_API_URL",
|
|
1155
|
+
"name": "base-url",
|
|
1156
|
+
"hasDynamicHelp": false,
|
|
1157
|
+
"multiple": false,
|
|
1158
|
+
"type": "option"
|
|
1159
|
+
},
|
|
1160
|
+
"body": {
|
|
1161
|
+
"description": "JSON request body",
|
|
1162
|
+
"name": "body",
|
|
1163
|
+
"hasDynamicHelp": false,
|
|
1164
|
+
"multiple": false,
|
|
1165
|
+
"type": "option"
|
|
1166
|
+
},
|
|
1167
|
+
"body-file": {
|
|
1168
|
+
"description": "Path to a JSON file used as the request body",
|
|
1169
|
+
"name": "body-file",
|
|
1170
|
+
"hasDynamicHelp": false,
|
|
1171
|
+
"multiple": false,
|
|
1172
|
+
"type": "option"
|
|
1173
|
+
}
|
|
1174
|
+
},
|
|
1175
|
+
"hasDynamicHelp": false,
|
|
1176
|
+
"hiddenAliases": [],
|
|
1177
|
+
"id": "sending:send-email",
|
|
1178
|
+
"pluginAlias": "@primitivedotdev/sdk",
|
|
1179
|
+
"pluginName": "@primitivedotdev/sdk",
|
|
1180
|
+
"pluginType": "core",
|
|
1181
|
+
"strict": true,
|
|
1182
|
+
"summary": "Send outbound email",
|
|
1183
|
+
"enableJsonFlag": false
|
|
1184
|
+
},
|
|
1139
1185
|
"webhook-deliveries:list-deliveries": {
|
|
1140
1186
|
"aliases": [],
|
|
1141
1187
|
"args": {},
|
|
@@ -1263,5 +1309,5 @@
|
|
|
1263
1309
|
"enableJsonFlag": false
|
|
1264
1310
|
}
|
|
1265
1311
|
},
|
|
1266
|
-
"version": "0.
|
|
1312
|
+
"version": "0.8.0"
|
|
1267
1313
|
}
|