mymx 0.3.5 → 0.3.7
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/dist/contract.d.ts +1 -1
- package/dist/index.d.ts +170 -4
- package/dist/index.js +341 -2
- package/dist/{types-BRl0ogvI.d.cts → types-C8JlcpcT.d.ts} +211 -1
- package/dist/{zod-Ced9Kav9.js → zod-CalKEwR4.js} +65 -2
- package/dist/zod.d.ts +232 -2
- package/dist/zod.js +2 -2
- package/package.json +8 -27
- package/dist/contract.cjs +0 -188
- package/dist/contract.d.cts +0 -146
- package/dist/errors-CwKIO2XZ.d.cts +0 -211
- package/dist/errors-DOkb_I6u.cjs +0 -318
- package/dist/index.cjs +0 -869
- package/dist/index.d.cts +0 -764
- package/dist/signing-Bqe14lp0.cjs +0 -218
- package/dist/signing-ChbxCBRQ.d.cts +0 -84
- package/dist/types-DJTmrgCz.d.ts +0 -520
- package/dist/zod-CyQz4zEa.cjs +0 -384
- package/dist/zod.cjs +0 -16
- package/dist/zod.d.cts +0 -1356
package/dist/contract.cjs
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const require_errors = require('./errors-DOkb_I6u.cjs');
|
|
3
|
-
const require_signing = require('./signing-Bqe14lp0.cjs');
|
|
4
|
-
const node_crypto = require_errors.__toESM(require("node:crypto"));
|
|
5
|
-
|
|
6
|
-
//#region src/contract.ts
|
|
7
|
-
/** Maximum raw email size for inline inclusion (256 KB) */
|
|
8
|
-
const RAW_EMAIL_INLINE_THRESHOLD = 262144;
|
|
9
|
-
/**
|
|
10
|
-
* Generate a stable event ID for webhook deduplication.
|
|
11
|
-
*
|
|
12
|
-
* Format: `evt_{sha256_hex}` where the hash is deterministic based on:
|
|
13
|
-
* - event_type ("email.received")
|
|
14
|
-
* - version (WEBHOOK_VERSION)
|
|
15
|
-
* - endpoint_id
|
|
16
|
-
* - email_id
|
|
17
|
-
*
|
|
18
|
-
* This ensures the same email delivered to the same endpoint always has
|
|
19
|
-
* the same event ID, enabling idempotent processing.
|
|
20
|
-
*
|
|
21
|
-
* The full 64-character SHA-256 hash is used for maximum collision resistance.
|
|
22
|
-
*/
|
|
23
|
-
function generateEventId(endpoint_id, email_id) {
|
|
24
|
-
const hashInput = `email.received:${require_errors.WEBHOOK_VERSION}:${endpoint_id}:${email_id}`;
|
|
25
|
-
const hash = (0, node_crypto.createHash)("sha256").update(hashInput).digest("hex");
|
|
26
|
-
return `evt_${hash}`;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* ISO 8601 timestamp pattern.
|
|
30
|
-
* Matches: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ssZ
|
|
31
|
-
* Does NOT match loose formats like "Tuesday" that Date.parse accepts.
|
|
32
|
-
*/
|
|
33
|
-
const ISO_8601_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/;
|
|
34
|
-
/**
|
|
35
|
-
* Validate that a timestamp is a valid ISO 8601 string in UTC format.
|
|
36
|
-
* Does NOT transform the input - preserves original format and precision.
|
|
37
|
-
*
|
|
38
|
-
* @param timestamp - The timestamp string to validate
|
|
39
|
-
* @returns The validated timestamp (unchanged)
|
|
40
|
-
* @throws Error if timestamp is not valid ISO 8601 UTC format
|
|
41
|
-
*/
|
|
42
|
-
function validateTimestamp(timestamp, fieldName) {
|
|
43
|
-
if (!ISO_8601_PATTERN.test(timestamp)) throw new Error(`[mymx/contract] Invalid ${fieldName}: "${timestamp}". Expected ISO 8601 UTC format (e.g., "2025-01-15T10:30:00.000Z")`);
|
|
44
|
-
const date = new Date(timestamp);
|
|
45
|
-
if (Number.isNaN(date.getTime())) throw new Error(`[mymx/contract] Invalid ${fieldName}: "${timestamp}" is not a valid date`);
|
|
46
|
-
return timestamp;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Build an EmailReceivedEvent from server input.
|
|
50
|
-
*
|
|
51
|
-
* This is the exact function used by MyMX servers to construct webhook payloads.
|
|
52
|
-
* By importing this from the SDK, the server gets build-time guarantees that
|
|
53
|
-
* the payload will match what consumers expect.
|
|
54
|
-
*
|
|
55
|
-
* @param input - The server-side input data
|
|
56
|
-
* @param options - Optional overrides for testing
|
|
57
|
-
* @returns A fully constructed EmailReceivedEvent
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```typescript
|
|
61
|
-
* import { buildEmailReceivedEvent } from 'mymx/contract';
|
|
62
|
-
*
|
|
63
|
-
* const event = buildEmailReceivedEvent({
|
|
64
|
-
* email_id: 'email-123',
|
|
65
|
-
* endpoint_id: 'endpoint-456',
|
|
66
|
-
* message_id: '<msg@example.com>',
|
|
67
|
-
* sender: 'from@example.com',
|
|
68
|
-
* recipient: 'to@example.com',
|
|
69
|
-
* subject: 'Hello',
|
|
70
|
-
* received_at: '2025-01-01T00:00:00Z',
|
|
71
|
-
* smtp_helo: 'mail.example.com',
|
|
72
|
-
* smtp_mail_from: 'from@example.com',
|
|
73
|
-
* smtp_rcpt_to: ['to@example.com'],
|
|
74
|
-
* raw_bytes: Buffer.from('...'),
|
|
75
|
-
* raw_sha256: 'abc123...',
|
|
76
|
-
* raw_size_bytes: 1234,
|
|
77
|
-
* attempt_count: 1,
|
|
78
|
-
* date_header: 'Mon, 1 Jan 2025 00:00:00 +0000',
|
|
79
|
-
* download_url: 'https://...',
|
|
80
|
-
* download_expires_at: '2025-01-02T00:00:00Z',
|
|
81
|
-
* attachments_download_url: null,
|
|
82
|
-
* });
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
function buildEmailReceivedEvent(input, options) {
|
|
86
|
-
const event_id = options?.event_id ?? generateEventId(input.endpoint_id, input.email_id);
|
|
87
|
-
const attempted_at = options?.attempted_at ? validateTimestamp(options.attempted_at, "attempted_at") : new Date().toISOString();
|
|
88
|
-
const shouldInline = input.raw_size_bytes <= RAW_EMAIL_INLINE_THRESHOLD;
|
|
89
|
-
const rawContent = shouldInline ? {
|
|
90
|
-
included: true,
|
|
91
|
-
encoding: "base64",
|
|
92
|
-
max_inline_bytes: RAW_EMAIL_INLINE_THRESHOLD,
|
|
93
|
-
size_bytes: input.raw_size_bytes,
|
|
94
|
-
sha256: input.raw_sha256,
|
|
95
|
-
data: input.raw_bytes.toString("base64")
|
|
96
|
-
} : {
|
|
97
|
-
included: false,
|
|
98
|
-
reason_code: "size_exceeded",
|
|
99
|
-
max_inline_bytes: RAW_EMAIL_INLINE_THRESHOLD,
|
|
100
|
-
size_bytes: input.raw_size_bytes,
|
|
101
|
-
sha256: input.raw_sha256
|
|
102
|
-
};
|
|
103
|
-
let parsedData;
|
|
104
|
-
if (input.parsed?.status === "complete") parsedData = {
|
|
105
|
-
status: "complete",
|
|
106
|
-
error: null,
|
|
107
|
-
body_text: shouldInline ? input.parsed.body_text : null,
|
|
108
|
-
body_html: shouldInline ? input.parsed.body_html : null,
|
|
109
|
-
reply_to: input.parsed.reply_to ?? null,
|
|
110
|
-
cc: input.parsed.cc ?? null,
|
|
111
|
-
bcc: input.parsed.bcc ?? null,
|
|
112
|
-
in_reply_to: input.parsed.in_reply_to ?? null,
|
|
113
|
-
references: input.parsed.references ?? null,
|
|
114
|
-
attachments: input.parsed.attachments,
|
|
115
|
-
attachments_download_url: input.attachments_download_url
|
|
116
|
-
};
|
|
117
|
-
else if (input.parsed?.status === "failed") parsedData = {
|
|
118
|
-
status: "failed",
|
|
119
|
-
error: input.parsed.error,
|
|
120
|
-
body_text: null,
|
|
121
|
-
body_html: null,
|
|
122
|
-
reply_to: null,
|
|
123
|
-
cc: null,
|
|
124
|
-
bcc: null,
|
|
125
|
-
in_reply_to: null,
|
|
126
|
-
references: null,
|
|
127
|
-
attachments: [],
|
|
128
|
-
attachments_download_url: null
|
|
129
|
-
};
|
|
130
|
-
else parsedData = {
|
|
131
|
-
status: "failed",
|
|
132
|
-
error: {
|
|
133
|
-
code: "PARSE_FAILED",
|
|
134
|
-
message: "Parsing not attempted",
|
|
135
|
-
retryable: false
|
|
136
|
-
},
|
|
137
|
-
body_text: null,
|
|
138
|
-
body_html: null,
|
|
139
|
-
reply_to: null,
|
|
140
|
-
cc: null,
|
|
141
|
-
bcc: null,
|
|
142
|
-
in_reply_to: null,
|
|
143
|
-
references: null,
|
|
144
|
-
attachments: [],
|
|
145
|
-
attachments_download_url: null
|
|
146
|
-
};
|
|
147
|
-
return {
|
|
148
|
-
id: event_id,
|
|
149
|
-
event: "email.received",
|
|
150
|
-
version: require_errors.WEBHOOK_VERSION,
|
|
151
|
-
delivery: {
|
|
152
|
-
endpoint_id: input.endpoint_id,
|
|
153
|
-
attempt: input.attempt_count,
|
|
154
|
-
attempted_at
|
|
155
|
-
},
|
|
156
|
-
email: {
|
|
157
|
-
id: input.email_id,
|
|
158
|
-
received_at: validateTimestamp(input.received_at, "received_at"),
|
|
159
|
-
smtp: {
|
|
160
|
-
helo: input.smtp_helo,
|
|
161
|
-
mail_from: input.smtp_mail_from,
|
|
162
|
-
rcpt_to: input.smtp_rcpt_to
|
|
163
|
-
},
|
|
164
|
-
headers: {
|
|
165
|
-
message_id: input.message_id,
|
|
166
|
-
subject: input.subject,
|
|
167
|
-
from: input.sender,
|
|
168
|
-
to: input.recipient,
|
|
169
|
-
date: input.date_header
|
|
170
|
-
},
|
|
171
|
-
content: {
|
|
172
|
-
raw: rawContent,
|
|
173
|
-
download: {
|
|
174
|
-
url: input.download_url,
|
|
175
|
-
expires_at: validateTimestamp(input.download_expires_at, "download_expires_at")
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
parsed: parsedData
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
//#endregion
|
|
184
|
-
exports.RAW_EMAIL_INLINE_THRESHOLD = RAW_EMAIL_INLINE_THRESHOLD
|
|
185
|
-
exports.WEBHOOK_VERSION = require_errors.WEBHOOK_VERSION
|
|
186
|
-
exports.buildEmailReceivedEvent = buildEmailReceivedEvent
|
|
187
|
-
exports.generateEventId = generateEventId
|
|
188
|
-
exports.signWebhookPayload = require_signing.signWebhookPayload
|
package/dist/contract.d.cts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { EmailAddress, EmailReceivedEvent, ParsedDataComplete, ParsedDataFailed, ParsedError, RawContentDownloadOnly, RawContentInline, WEBHOOK_VERSION, WebhookAttachment } from "./types-BRl0ogvI.cjs";
|
|
2
|
-
import { SignResult, signWebhookPayload } from "./signing-ChbxCBRQ.cjs";
|
|
3
|
-
|
|
4
|
-
//#region src/contract.d.ts
|
|
5
|
-
/** Maximum raw email size for inline inclusion (256 KB) */
|
|
6
|
-
|
|
7
|
-
/** Maximum raw email size for inline inclusion (256 KB) */
|
|
8
|
-
declare const RAW_EMAIL_INLINE_THRESHOLD = 262144;
|
|
9
|
-
/**
|
|
10
|
-
* Parsed content input when parsing succeeded.
|
|
11
|
-
*/
|
|
12
|
-
interface ParsedInputComplete {
|
|
13
|
-
status: "complete";
|
|
14
|
-
body_text: string | null;
|
|
15
|
-
body_html: string | null;
|
|
16
|
-
/** Parsed Reply-To header addresses (optional, defaults to null) */
|
|
17
|
-
reply_to?: EmailAddress[] | null;
|
|
18
|
-
/** Parsed CC header addresses (optional, defaults to null) */
|
|
19
|
-
cc?: EmailAddress[] | null;
|
|
20
|
-
/** Parsed BCC header addresses (optional, defaults to null) */
|
|
21
|
-
bcc?: EmailAddress[] | null;
|
|
22
|
-
/** In-Reply-To header values (optional, defaults to null) */
|
|
23
|
-
in_reply_to?: string[] | null;
|
|
24
|
-
/** References header values (optional, defaults to null) */
|
|
25
|
-
references?: string[] | null;
|
|
26
|
-
attachments: WebhookAttachment[];
|
|
27
|
-
/** Storage key for attachments tarball (used to generate download URL) */
|
|
28
|
-
attachments_storage_key: string | null;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Parsed content input when parsing failed.
|
|
32
|
-
*/
|
|
33
|
-
interface ParsedInputFailed {
|
|
34
|
-
status: "failed";
|
|
35
|
-
error: ParsedError;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Parsed content input (discriminated union on status).
|
|
39
|
-
*/
|
|
40
|
-
type ParsedInput = ParsedInputComplete | ParsedInputFailed;
|
|
41
|
-
/**
|
|
42
|
-
* Input for building an EmailReceivedEvent.
|
|
43
|
-
*
|
|
44
|
-
* This is the strict input shape that the MyMX server must provide.
|
|
45
|
-
* TypeScript will enforce this at build time, ensuring the server
|
|
46
|
-
* cannot construct a payload that doesn't match the SDK's expectations.
|
|
47
|
-
*/
|
|
48
|
-
interface EmailReceivedEventInput {
|
|
49
|
-
/** Unique email ID in MyMX */
|
|
50
|
-
email_id: string;
|
|
51
|
-
/** ID of the webhook endpoint receiving this event */
|
|
52
|
-
endpoint_id: string;
|
|
53
|
-
/** Message-ID header (may be null) */
|
|
54
|
-
message_id: string | null;
|
|
55
|
-
/** From header value */
|
|
56
|
-
sender: string;
|
|
57
|
-
/** To header value */
|
|
58
|
-
recipient: string;
|
|
59
|
-
/** Subject header (may be null) */
|
|
60
|
-
subject: string | null;
|
|
61
|
-
/** ISO 8601 timestamp when MyMX received the email */
|
|
62
|
-
received_at: string;
|
|
63
|
-
/** HELO/EHLO hostname from the sending server */
|
|
64
|
-
smtp_helo: string | null;
|
|
65
|
-
/** SMTP envelope sender (MAIL FROM) */
|
|
66
|
-
smtp_mail_from: string;
|
|
67
|
-
/** SMTP envelope recipients (RCPT TO) */
|
|
68
|
-
smtp_rcpt_to: string[];
|
|
69
|
-
/** Raw email bytes (will be base64 encoded if small enough) */
|
|
70
|
-
raw_bytes: Buffer;
|
|
71
|
-
/** SHA-256 hash of raw email (hex) */
|
|
72
|
-
raw_sha256: string;
|
|
73
|
-
/** Size of raw email in bytes */
|
|
74
|
-
raw_size_bytes: number;
|
|
75
|
-
/** Delivery attempt number (starts at 1) */
|
|
76
|
-
attempt_count: number;
|
|
77
|
-
/** Date header value parsed from raw email (may be null) */
|
|
78
|
-
date_header: string | null;
|
|
79
|
-
/** Download URL for raw email */
|
|
80
|
-
download_url: string;
|
|
81
|
-
/** ISO 8601 timestamp when download URL expires */
|
|
82
|
-
download_expires_at: string;
|
|
83
|
-
/** URL to download attachments tarball (null if no attachments) */
|
|
84
|
-
attachments_download_url: string | null;
|
|
85
|
-
/** Parsed email content (optional, defaults to failed state) */
|
|
86
|
-
parsed?: ParsedInput;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Generate a stable event ID for webhook deduplication.
|
|
90
|
-
*
|
|
91
|
-
* Format: `evt_{sha256_hex}` where the hash is deterministic based on:
|
|
92
|
-
* - event_type ("email.received")
|
|
93
|
-
* - version (WEBHOOK_VERSION)
|
|
94
|
-
* - endpoint_id
|
|
95
|
-
* - email_id
|
|
96
|
-
*
|
|
97
|
-
* This ensures the same email delivered to the same endpoint always has
|
|
98
|
-
* the same event ID, enabling idempotent processing.
|
|
99
|
-
*
|
|
100
|
-
* The full 64-character SHA-256 hash is used for maximum collision resistance.
|
|
101
|
-
*/
|
|
102
|
-
declare function generateEventId(endpoint_id: string, email_id: string): string;
|
|
103
|
-
/**
|
|
104
|
-
* Build an EmailReceivedEvent from server input.
|
|
105
|
-
*
|
|
106
|
-
* This is the exact function used by MyMX servers to construct webhook payloads.
|
|
107
|
-
* By importing this from the SDK, the server gets build-time guarantees that
|
|
108
|
-
* the payload will match what consumers expect.
|
|
109
|
-
*
|
|
110
|
-
* @param input - The server-side input data
|
|
111
|
-
* @param options - Optional overrides for testing
|
|
112
|
-
* @returns A fully constructed EmailReceivedEvent
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```typescript
|
|
116
|
-
* import { buildEmailReceivedEvent } from 'mymx/contract';
|
|
117
|
-
*
|
|
118
|
-
* const event = buildEmailReceivedEvent({
|
|
119
|
-
* email_id: 'email-123',
|
|
120
|
-
* endpoint_id: 'endpoint-456',
|
|
121
|
-
* message_id: '<msg@example.com>',
|
|
122
|
-
* sender: 'from@example.com',
|
|
123
|
-
* recipient: 'to@example.com',
|
|
124
|
-
* subject: 'Hello',
|
|
125
|
-
* received_at: '2025-01-01T00:00:00Z',
|
|
126
|
-
* smtp_helo: 'mail.example.com',
|
|
127
|
-
* smtp_mail_from: 'from@example.com',
|
|
128
|
-
* smtp_rcpt_to: ['to@example.com'],
|
|
129
|
-
* raw_bytes: Buffer.from('...'),
|
|
130
|
-
* raw_sha256: 'abc123...',
|
|
131
|
-
* raw_size_bytes: 1234,
|
|
132
|
-
* attempt_count: 1,
|
|
133
|
-
* date_header: 'Mon, 1 Jan 2025 00:00:00 +0000',
|
|
134
|
-
* download_url: 'https://...',
|
|
135
|
-
* download_expires_at: '2025-01-02T00:00:00Z',
|
|
136
|
-
* attachments_download_url: null,
|
|
137
|
-
* });
|
|
138
|
-
* ```
|
|
139
|
-
*/
|
|
140
|
-
declare function buildEmailReceivedEvent(input: EmailReceivedEventInput, options?: {
|
|
141
|
-
/** Override event ID (for testing or custom ID generation) */
|
|
142
|
-
event_id?: string;
|
|
143
|
-
/** Override attempted_at timestamp (for testing) */
|
|
144
|
-
attempted_at?: string;
|
|
145
|
-
}): EmailReceivedEvent; //#endregion
|
|
146
|
-
export { EmailAddress, EmailReceivedEvent, EmailReceivedEventInput, ParsedDataComplete, ParsedDataFailed, ParsedError, ParsedInput, ParsedInputComplete, ParsedInputFailed, RAW_EMAIL_INLINE_THRESHOLD, RawContentDownloadOnly, RawContentInline, SignResult, WEBHOOK_VERSION, WebhookAttachment, buildEmailReceivedEvent, generateEventId, signWebhookPayload };
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { ZodError } from "zod";
|
|
2
|
-
|
|
3
|
-
//#region src/errors.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Verification error definitions.
|
|
6
|
-
* Use these for documentation, dashboards, and i18n.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Verification error definitions.
|
|
10
|
-
* Use these for documentation, dashboards, and i18n.
|
|
11
|
-
*/
|
|
12
|
-
declare const VERIFICATION_ERRORS: {
|
|
13
|
-
readonly INVALID_SIGNATURE_HEADER: {
|
|
14
|
-
readonly message: "Missing or malformed MyMX-Signature header";
|
|
15
|
-
readonly suggestion: "Check that you're reading the correct header (MyMX-Signature) and it's being passed correctly from your web framework.";
|
|
16
|
-
};
|
|
17
|
-
readonly TIMESTAMP_OUT_OF_RANGE: {
|
|
18
|
-
readonly message: "Timestamp is too old (possible replay attack)";
|
|
19
|
-
readonly suggestion: "This could indicate a replay attack, network delay, or server clock drift. Check your server's time is synced.";
|
|
20
|
-
};
|
|
21
|
-
readonly SIGNATURE_MISMATCH: {
|
|
22
|
-
readonly message: "Signature doesn't match expected value";
|
|
23
|
-
readonly suggestion: "Verify the webhook secret matches and you're using the raw request body (not re-serialized JSON).";
|
|
24
|
-
};
|
|
25
|
-
readonly MISSING_SECRET: {
|
|
26
|
-
readonly message: "No webhook secret was provided";
|
|
27
|
-
readonly suggestion: "Pass your webhook secret from the MyMX dashboard. Check that the environment variable is set.";
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Payload parsing error definitions.
|
|
32
|
-
* Use these for documentation, dashboards, and i18n.
|
|
33
|
-
*/
|
|
34
|
-
declare const PAYLOAD_ERRORS: {
|
|
35
|
-
readonly PAYLOAD_NULL: {
|
|
36
|
-
readonly message: "Webhook payload is null";
|
|
37
|
-
readonly suggestion: "Ensure you're passing the parsed JSON body, not null. Check your framework's body parsing middleware.";
|
|
38
|
-
};
|
|
39
|
-
readonly PAYLOAD_UNDEFINED: {
|
|
40
|
-
readonly message: "Webhook payload is undefined";
|
|
41
|
-
readonly suggestion: "The payload was not provided. Make sure you're passing the request body to the handler.";
|
|
42
|
-
};
|
|
43
|
-
readonly PAYLOAD_WRONG_TYPE: {
|
|
44
|
-
readonly message: "Webhook payload must be an object";
|
|
45
|
-
readonly suggestion: "The payload should be a parsed JSON object. Check that you're not passing a string or other primitive.";
|
|
46
|
-
};
|
|
47
|
-
readonly PAYLOAD_IS_ARRAY: {
|
|
48
|
-
readonly message: "Webhook payload is an array, expected object";
|
|
49
|
-
readonly suggestion: "MyMX webhooks are single event objects, not arrays. Check the payload structure.";
|
|
50
|
-
};
|
|
51
|
-
readonly PAYLOAD_MISSING_EVENT: {
|
|
52
|
-
readonly message: "Webhook payload missing 'event' field";
|
|
53
|
-
readonly suggestion: "All webhook payloads must have an 'event' field. This may not be a valid MyMX webhook.";
|
|
54
|
-
};
|
|
55
|
-
readonly PAYLOAD_UNKNOWN_EVENT: {
|
|
56
|
-
readonly message: "Unknown webhook event type";
|
|
57
|
-
readonly suggestion: "This event type is not recognized. You may need to update your SDK or handle unknown events gracefully.";
|
|
58
|
-
};
|
|
59
|
-
readonly PAYLOAD_EMPTY_BODY: {
|
|
60
|
-
readonly message: "Request body is empty";
|
|
61
|
-
readonly suggestion: "The request body was empty. Ensure the webhook is sending data and your framework is parsing it correctly.";
|
|
62
|
-
};
|
|
63
|
-
readonly JSON_PARSE_FAILED: {
|
|
64
|
-
readonly message: "Failed to parse JSON body";
|
|
65
|
-
readonly suggestion: "The request body is not valid JSON. Check the raw body content and Content-Type header.";
|
|
66
|
-
};
|
|
67
|
-
readonly INVALID_ENCODING: {
|
|
68
|
-
readonly message: "Invalid body encoding";
|
|
69
|
-
readonly suggestion: "The request body encoding is not supported. MyMX webhooks use UTF-8 encoded JSON.";
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Raw email decode error definitions.
|
|
74
|
-
* Use these for documentation, dashboards, and i18n.
|
|
75
|
-
*/
|
|
76
|
-
declare const RAW_EMAIL_ERRORS: {
|
|
77
|
-
readonly NOT_INCLUDED: {
|
|
78
|
-
readonly message: "Raw email content not included inline";
|
|
79
|
-
readonly suggestion: "Use the download URL at event.email.content.download.url to fetch the raw email.";
|
|
80
|
-
};
|
|
81
|
-
readonly HASH_MISMATCH: {
|
|
82
|
-
readonly message: "SHA-256 hash verification failed";
|
|
83
|
-
readonly suggestion: "The raw email data may be corrupted. Try downloading from the URL instead.";
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* All error codes that can be thrown by the SDK.
|
|
88
|
-
*/
|
|
89
|
-
type WebhookErrorCode = WebhookVerificationErrorCode | WebhookPayloadErrorCode | WebhookValidationErrorCode | RawEmailDecodeErrorCode;
|
|
90
|
-
type RawEmailDecodeErrorCode = keyof typeof RAW_EMAIL_ERRORS;
|
|
91
|
-
/**
|
|
92
|
-
* Base class for all MyMX webhook errors.
|
|
93
|
-
*
|
|
94
|
-
* Catch this to handle any error from the SDK in a single catch block.
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```typescript
|
|
98
|
-
* import { handleWebhook, MyMXWebhookError } from 'mymx';
|
|
99
|
-
*
|
|
100
|
-
* try {
|
|
101
|
-
* const event = handleWebhook({ body, signature, secret });
|
|
102
|
-
* } catch (err) {
|
|
103
|
-
* if (err instanceof MyMXWebhookError) {
|
|
104
|
-
* console.error(`[${err.code}] ${err.message}`);
|
|
105
|
-
* return res.status(400).json({ error: err.code });
|
|
106
|
-
* }
|
|
107
|
-
* throw err;
|
|
108
|
-
* }
|
|
109
|
-
* ```
|
|
110
|
-
*/
|
|
111
|
-
declare abstract class MyMXWebhookError extends Error {
|
|
112
|
-
/** Programmatic error code for monitoring and handling */
|
|
113
|
-
abstract readonly code: WebhookErrorCode;
|
|
114
|
-
/** Actionable guidance for fixing the issue */
|
|
115
|
-
abstract readonly suggestion: string;
|
|
116
|
-
/**
|
|
117
|
-
* Formats the error for logging/display.
|
|
118
|
-
*/
|
|
119
|
-
toString(): string;
|
|
120
|
-
/**
|
|
121
|
-
* Serializes cleanly for structured logging (Datadog, CloudWatch, etc.)
|
|
122
|
-
*/
|
|
123
|
-
toJSON(): {
|
|
124
|
-
name: string;
|
|
125
|
-
code: WebhookErrorCode;
|
|
126
|
-
message: string;
|
|
127
|
-
suggestion: string;
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Error codes for webhook verification failures.
|
|
132
|
-
* Derived from VERIFICATION_ERRORS keys.
|
|
133
|
-
*/
|
|
134
|
-
type WebhookVerificationErrorCode = keyof typeof VERIFICATION_ERRORS;
|
|
135
|
-
/**
|
|
136
|
-
* Error thrown when webhook signature verification fails.
|
|
137
|
-
*
|
|
138
|
-
* Use the `code` property to programmatically handle specific error cases.
|
|
139
|
-
*/
|
|
140
|
-
declare class WebhookVerificationError extends MyMXWebhookError {
|
|
141
|
-
readonly code: WebhookVerificationErrorCode;
|
|
142
|
-
readonly suggestion: string;
|
|
143
|
-
constructor(code: WebhookVerificationErrorCode, message?: string, suggestion?: string);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Error codes for webhook payload parsing failures.
|
|
147
|
-
* Derived from PAYLOAD_ERRORS keys.
|
|
148
|
-
*/
|
|
149
|
-
type WebhookPayloadErrorCode = keyof typeof PAYLOAD_ERRORS;
|
|
150
|
-
/**
|
|
151
|
-
* Error thrown when webhook payload parsing fails (lightweight parser).
|
|
152
|
-
*
|
|
153
|
-
* Use the `code` property for programmatic handling and monitoring.
|
|
154
|
-
* The `suggestion` property contains actionable guidance for fixing the issue.
|
|
155
|
-
*/
|
|
156
|
-
declare class WebhookPayloadError extends MyMXWebhookError {
|
|
157
|
-
readonly code: WebhookPayloadErrorCode;
|
|
158
|
-
readonly suggestion: string;
|
|
159
|
-
/** Original error if this wraps another error (e.g., JSON.parse failure) */
|
|
160
|
-
readonly cause?: Error;
|
|
161
|
-
constructor(code: WebhookPayloadErrorCode, message?: string, suggestion?: string, cause?: Error);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Error code for Zod schema validation failures.
|
|
165
|
-
*/
|
|
166
|
-
type WebhookValidationErrorCode = "SCHEMA_VALIDATION_FAILED";
|
|
167
|
-
/**
|
|
168
|
-
* Error thrown when Zod schema validation fails.
|
|
169
|
-
*
|
|
170
|
-
* Wraps ZodError with human-friendly messages and actionable suggestions.
|
|
171
|
-
*/
|
|
172
|
-
declare class WebhookValidationError extends MyMXWebhookError {
|
|
173
|
-
readonly code: WebhookValidationErrorCode;
|
|
174
|
-
readonly suggestion: string;
|
|
175
|
-
/** The specific field path that failed (e.g., "email.headers.from") */
|
|
176
|
-
readonly field: string;
|
|
177
|
-
/** Original Zod error for advanced debugging */
|
|
178
|
-
readonly zodError: ZodError;
|
|
179
|
-
/** Number of additional validation errors beyond the first */
|
|
180
|
-
readonly additionalErrorCount: number;
|
|
181
|
-
constructor(field: string, message: string, suggestion: string, zodError: ZodError);
|
|
182
|
-
/**
|
|
183
|
-
* Formats the error for logging/display.
|
|
184
|
-
* Includes error count and suggestion.
|
|
185
|
-
*/
|
|
186
|
-
toString(): string;
|
|
187
|
-
/**
|
|
188
|
-
* Serializes cleanly for structured logging (Datadog, CloudWatch, etc.)
|
|
189
|
-
*/
|
|
190
|
-
toJSON(): {
|
|
191
|
-
name: string;
|
|
192
|
-
code: "SCHEMA_VALIDATION_FAILED";
|
|
193
|
-
field: string;
|
|
194
|
-
message: string;
|
|
195
|
-
suggestion: string;
|
|
196
|
-
additionalErrorCount: number;
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Error thrown when raw email decoding or verification fails.
|
|
201
|
-
*
|
|
202
|
-
* Use the `code` property to determine the failure reason:
|
|
203
|
-
* - `NOT_INCLUDED`: Raw email not inline, must download from URL
|
|
204
|
-
* - `HASH_MISMATCH`: SHA-256 verification failed, content may be corrupted
|
|
205
|
-
*/
|
|
206
|
-
declare class RawEmailDecodeError extends MyMXWebhookError {
|
|
207
|
-
readonly code: RawEmailDecodeErrorCode;
|
|
208
|
-
readonly suggestion: string;
|
|
209
|
-
constructor(code: RawEmailDecodeErrorCode, message?: string);
|
|
210
|
-
} //#endregion
|
|
211
|
-
export { MyMXWebhookError, PAYLOAD_ERRORS, RAW_EMAIL_ERRORS, RawEmailDecodeError, RawEmailDecodeErrorCode, VERIFICATION_ERRORS, WebhookErrorCode, WebhookPayloadError, WebhookPayloadErrorCode, WebhookValidationError, WebhookValidationErrorCode, WebhookVerificationError, WebhookVerificationErrorCode };
|