@primitivedotdev/sdk 0.2.2 → 0.2.3

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 CHANGED
@@ -12,7 +12,7 @@ This package ships three Node.js modules:
12
12
 
13
13
  ## Requirements
14
14
 
15
- - Node.js `>=20`
15
+ - Node.js `>=22`
16
16
 
17
17
  ## Installation
18
18
 
@@ -1,5 +1,5 @@
1
- import { EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, ParsedDataComplete, ParsedDataFailed, ParsedError, RawContentDownloadOnly, RawContentInline, WebhookAttachment } from "../types-C6M6oCRS.js";
2
- import { SignResult, WEBHOOK_VERSION$1 as WEBHOOK_VERSION, signWebhookPayload$1 as signWebhookPayload } from "../index-pNcbeqPI.js";
1
+ import { EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, ParsedDataComplete, ParsedDataFailed, ParsedError, RawContentDownloadOnly, RawContentInline, WebhookAttachment } from "../types-B5IgP-Zx.js";
2
+ import { SignResult, WEBHOOK_VERSION$1 as WEBHOOK_VERSION, signWebhookPayload$1 as signWebhookPayload } from "../index-BdRIHaXz.js";
3
3
 
4
4
  //#region src/contract/contract.d.ts
5
5
  /** Maximum raw email size for inline inclusion (256 KB). */
@@ -86,8 +86,8 @@ interface EmailReceivedEventInput {
86
86
  * Generate a stable event ID for webhook deduplication.
87
87
  *
88
88
  * Format: `evt_{sha256_hex}` where the hash is deterministic based on the
89
- * event type, endpoint ID, and email ID. The same email sent
90
- * to the same endpoint will always get the same event ID.
89
+ * event type, webhook version, endpoint ID, and email ID. The same email
90
+ * sent to the same endpoint will always get the same event ID.
91
91
  *
92
92
  * @param endpoint_id - Webhook endpoint ID.
93
93
  * @param email_id - Primitive email ID.
@@ -1,4 +1,4 @@
1
- import { WEBHOOK_VERSION, signWebhookPayload, validateEmailReceivedEvent } from "../webhook-Cz3QsQnS.js";
1
+ import { WEBHOOK_VERSION, signWebhookPayload, validateEmailReceivedEvent } from "../webhook-Be2vM0F-.js";
2
2
  import { createHash } from "node:crypto";
3
3
 
4
4
  //#region src/contract/contract.ts
@@ -31,15 +31,15 @@ function validateTimestamp(timestamp, fieldName) {
31
31
  * Generate a stable event ID for webhook deduplication.
32
32
  *
33
33
  * Format: `evt_{sha256_hex}` where the hash is deterministic based on the
34
- * event type, endpoint ID, and email ID. The same email sent
35
- * to the same endpoint will always get the same event ID.
34
+ * event type, webhook version, endpoint ID, and email ID. The same email
35
+ * sent to the same endpoint will always get the same event ID.
36
36
  *
37
37
  * @param endpoint_id - Webhook endpoint ID.
38
38
  * @param email_id - Primitive email ID.
39
39
  * @returns Stable event ID with `evt_` prefix.
40
40
  */
41
41
  function generateEventId(endpoint_id, email_id) {
42
- const hashInput = `email.received:${endpoint_id}:${email_id}`;
42
+ const hashInput = `email.received:${WEBHOOK_VERSION}:${endpoint_id}:${email_id}`;
43
43
  const hash = createHash("sha256").update(hashInput).digest("hex");
44
44
  return `evt_${hash}`;
45
45
  }
@@ -1,4 +1,4 @@
1
- import { EmailAuth, EmailReceivedEvent, ValidateEmailAuthResult, WebhookEvent } from "./types-C6M6oCRS.js";
1
+ import { EmailAuth, EmailReceivedEvent, ValidateEmailAuthResult, WebhookEvent } from "./types-B5IgP-Zx.js";
2
2
  import { ErrorObject } from "ajv";
3
3
 
4
4
  //#region src/webhook/errors.d.ts
@@ -1034,11 +1034,11 @@ declare const emailReceivedEventJsonSchema: {
1034
1034
  };
1035
1035
  readonly dmarcSpfAligned: {
1036
1036
  readonly type: "boolean";
1037
- readonly description: "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode). Optional in self-hosted environments.";
1037
+ readonly description: "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode).";
1038
1038
  };
1039
1039
  readonly dmarcDkimAligned: {
1040
1040
  readonly type: "boolean";
1041
- readonly description: "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain. Optional in self-hosted environments.";
1041
+ readonly description: "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain.";
1042
1042
  };
1043
1043
  readonly dmarcSpfStrict: {
1044
1044
  readonly type: ["boolean", "null"];
@@ -1056,7 +1056,7 @@ declare const emailReceivedEventJsonSchema: {
1056
1056
  readonly description: "All DKIM signatures found in the email with their verification results.\n\nMay be empty if no DKIM signatures were present.";
1057
1057
  };
1058
1058
  };
1059
- readonly required: ["spf", "dmarc", "dmarcPolicy", "dmarcFromDomain", "dmarcSpfStrict", "dmarcDkimStrict", "dkimSignatures"];
1059
+ readonly required: ["spf", "dmarc", "dmarcPolicy", "dmarcFromDomain", "dmarcSpfAligned", "dmarcDkimAligned", "dmarcSpfStrict", "dmarcDkimStrict", "dkimSignatures"];
1060
1060
  readonly description: "Email authentication results for SPF, DKIM, and DMARC.\n\nUse `validateEmailAuth()` to compute a verdict based on these results.";
1061
1061
  };
1062
1062
  readonly SpfResult: {
@@ -1099,8 +1099,8 @@ declare const emailReceivedEventJsonSchema: {
1099
1099
  readonly description: "Signing algorithm (e.g., \"rsa-sha256\", \"ed25519-sha256\").\n\nOptional in self-hosted environments.";
1100
1100
  };
1101
1101
  };
1102
- readonly required: ["domain", "result", "aligned"];
1103
- readonly description: "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently.\n\nFields marked optional (`selector`, `keyBits`, `algo`) may be unavailable in self-hosted environments where the milter provides limited DKIM detail.";
1102
+ readonly required: ["domain", "selector", "result", "aligned", "keyBits", "algo"];
1103
+ readonly description: "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently.";
1104
1104
  };
1105
1105
  readonly DkimResult: {
1106
1106
  readonly type: "string";
package/dist/index.d.ts CHANGED
@@ -1,3 +1,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-C6M6oCRS.js";
2
- import { DecodeRawEmailOptions, 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, SignResult, VERIFICATION_ERRORS$1 as VERIFICATION_ERRORS, 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, getDownloadTimeRemaining$1 as getDownloadTimeRemaining, handleWebhook$1 as handleWebhook, isDownloadExpired$1 as isDownloadExpired, isEmailReceivedEvent$1 as isEmailReceivedEvent, isRawIncluded$1 as isRawIncluded, parseWebhookEvent$1 as parseWebhookEvent, safeValidateEmailReceivedEvent$1 as safeValidateEmailReceivedEvent, signWebhookPayload$1 as signWebhookPayload, validateEmailAuth$1 as validateEmailAuth, validateEmailReceivedEvent$1 as validateEmailReceivedEvent, verifyRawEmailDownload$1 as verifyRawEmailDownload, verifyWebhookSignature$1 as verifyWebhookSignature } from "./index-pNcbeqPI.js";
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-B5IgP-Zx.js";
2
+ import { DecodeRawEmailOptions, 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, SignResult, VERIFICATION_ERRORS$1 as VERIFICATION_ERRORS, 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, getDownloadTimeRemaining$1 as getDownloadTimeRemaining, handleWebhook$1 as handleWebhook, isDownloadExpired$1 as isDownloadExpired, isEmailReceivedEvent$1 as isEmailReceivedEvent, isRawIncluded$1 as isRawIncluded, parseWebhookEvent$1 as parseWebhookEvent, safeValidateEmailReceivedEvent$1 as safeValidateEmailReceivedEvent, signWebhookPayload$1 as signWebhookPayload, validateEmailAuth$1 as validateEmailAuth, validateEmailReceivedEvent$1 as validateEmailReceivedEvent, verifyRawEmailDownload$1 as verifyRawEmailDownload, verifyWebhookSignature$1 as verifyWebhookSignature } from "./index-BdRIHaXz.js";
3
3
  export { AuthConfidence, AuthVerdict, DecodeRawEmailOptions, DkimResult, DkimSignature, DmarcPolicy, DmarcResult, EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, EventType, ForwardAnalysis, ForwardOriginalSender, ForwardResult, ForwardResultAttachmentAnalyzed, ForwardResultAttachmentSkipped, ForwardResultInline, ForwardVerdict, ForwardVerification, 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, SignResult, SpfResult, UnknownEvent, VERIFICATION_ERRORS, ValidateEmailAuthResult, VerifyOptions, WEBHOOK_VERSION, WebhookAttachment, WebhookErrorCode, WebhookEvent, WebhookHeaders, WebhookPayloadError, WebhookPayloadErrorCode, WebhookValidationError, WebhookValidationErrorCode, WebhookVerificationError, WebhookVerificationErrorCode, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- 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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature } from "./webhook-Cz3QsQnS.js";
1
+ 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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature } from "./webhook-Be2vM0F-.js";
2
2
 
3
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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature };
@@ -1,4 +1,4 @@
1
- import { EmailAddress, ParsedDataComplete, WebhookAttachment } from "../types-C6M6oCRS.js";
1
+ import { EmailAddress, ParsedDataComplete, WebhookAttachment } from "../types-B5IgP-Zx.js";
2
2
 
3
3
  //#region src/parser/attachment-parser.d.ts
4
4
  interface ParsedAttachment {
@@ -1,12 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { PassThrough } from "node:stream";
3
+ import archiver from "archiver";
4
+ import { simpleParser } from "mailparser";
3
5
  import DOMPurify from "isomorphic-dompurify";
4
6
 
5
7
  //#region src/parser/attachment-bundler.ts
6
- async function loadArchiver() {
7
- const module = await import("archiver");
8
- return module.default;
9
- }
10
8
  /**
11
9
  * Bundle downloadable attachments into a tar.gz archive.
12
10
  *
@@ -20,7 +18,6 @@ async function loadArchiver() {
20
18
  async function bundleAttachments(attachments) {
21
19
  const downloadable = attachments.filter((att) => att.isDownloadable);
22
20
  if (downloadable.length === 0) return null;
23
- const archiver = await loadArchiver();
24
21
  const archive = archiver("tar", {
25
22
  gzip: true,
26
23
  gzipOptions: { level: 6 }
@@ -181,51 +178,49 @@ const ALLOWED_ATTRS = [
181
178
  "size",
182
179
  "face"
183
180
  ];
184
- const ALLOWED_URI_REGEXP = /^(data:|mailto:|#)/i;
181
+ const ALLOWED_URI_REGEXP = /^(https?:|data:image\/(?!svg\+xml)[a-z0-9][a-z0-9+.-]*[;,]|mailto:|cid:|#)/i;
182
+ const SVG_DATA_URI_RE = /^data:image\/svg\+xml/i;
183
+ DOMPurify.addHook("uponSanitizeAttribute", (_node, data) => {
184
+ if (data.attrName.startsWith("on")) data.keepAttr = false;
185
+ if (data.attrName === "style") data.keepAttr = false;
186
+ if ((data.attrName === "src" || data.attrName === "href") && SVG_DATA_URI_RE.test(data.attrValue)) data.keepAttr = false;
187
+ });
188
+ DOMPurify.addHook("afterSanitizeAttributes", (node) => {
189
+ if (node.tagName === "A") {
190
+ const target = node.getAttribute("target");
191
+ if (target === "_blank") node.setAttribute("rel", "noopener noreferrer");
192
+ }
193
+ });
194
+ const SANITIZE_OPTIONS = {
195
+ ALLOWED_TAGS,
196
+ ALLOWED_ATTR: ALLOWED_ATTRS,
197
+ ALLOW_DATA_ATTR: false,
198
+ ALLOW_UNKNOWN_PROTOCOLS: false,
199
+ ALLOWED_URI_REGEXP,
200
+ FORBID_TAGS: [
201
+ "style",
202
+ "script",
203
+ "iframe",
204
+ "object",
205
+ "embed",
206
+ "form",
207
+ "input",
208
+ "button",
209
+ "select",
210
+ "textarea",
211
+ "link",
212
+ "meta",
213
+ "base",
214
+ "svg",
215
+ "math"
216
+ ]
217
+ };
185
218
  function sanitizeHtml(html) {
186
- DOMPurify.addHook("uponSanitizeAttribute", (_node, data) => {
187
- if (data.attrName.startsWith("on")) data.keepAttr = false;
188
- if (data.attrName === "style") data.keepAttr = false;
189
- });
190
- DOMPurify.addHook("afterSanitizeAttributes", (node) => {
191
- if (node.tagName === "A") {
192
- const target = node.getAttribute("target");
193
- if (target === "_blank") node.setAttribute("rel", "noopener noreferrer");
194
- }
195
- });
196
- const result = DOMPurify.sanitize(html, {
197
- ALLOWED_TAGS,
198
- ALLOWED_ATTR: ALLOWED_ATTRS,
199
- ALLOW_DATA_ATTR: false,
200
- ALLOW_UNKNOWN_PROTOCOLS: false,
201
- ALLOWED_URI_REGEXP,
202
- FORBID_TAGS: [
203
- "style",
204
- "script",
205
- "iframe",
206
- "object",
207
- "embed",
208
- "form",
209
- "input",
210
- "button",
211
- "select",
212
- "textarea",
213
- "link",
214
- "meta",
215
- "base",
216
- "svg",
217
- "math"
218
- ]
219
- });
220
- DOMPurify.removeAllHooks();
221
- return result;
219
+ return DOMPurify.sanitize(html, SANITIZE_OPTIONS);
222
220
  }
223
221
 
224
222
  //#endregion
225
223
  //#region src/parser/attachment-parser.ts
226
- async function loadMailparser$1() {
227
- return import("mailparser");
228
- }
229
224
  const SIGNATURE_ARTIFACTS = new Set([
230
225
  "application/pkcs7-signature",
231
226
  "application/x-pkcs7-signature",
@@ -251,7 +246,6 @@ const SAFE_INLINE_TYPES = new Set([
251
246
  */
252
247
  async function parseEmailWithAttachments(emlBuffer, options) {
253
248
  const generateId = options?.generateAttachmentId ?? (() => crypto.randomUUID());
254
- const { simpleParser } = await loadMailparser$1();
255
249
  const parsed = await simpleParser(emlBuffer);
256
250
  const attachments = [];
257
251
  for (let i = 0; i < (parsed.attachments?.length ?? 0); i++) {
@@ -399,15 +393,11 @@ function sanitizeFilename(filename, partIndex) {
399
393
 
400
394
  //#endregion
401
395
  //#region src/parser/email-parser.ts
402
- async function loadMailparser() {
403
- return import("mailparser");
404
- }
405
396
  /**
406
397
  * Parse a raw .eml file into structured data
407
398
  * Uses mailparser library for robust email parsing
408
399
  */
409
400
  async function parseEmail(emlRaw) {
410
- const { simpleParser } = await loadMailparser();
411
401
  const parsed = await simpleParser(emlRaw);
412
402
  const headers = {};
413
403
  parsed.headers.forEach((value, key) => {
@@ -614,15 +614,15 @@ interface EmailAuth$1 {
614
614
  /**
615
615
  * Whether SPF aligned with the From: domain for DMARC purposes.
616
616
  *
617
- * True if the envelope sender domain matches the From: domain (per alignment mode). Optional in self-hosted environments.
617
+ * True if the envelope sender domain matches the From: domain (per alignment mode).
618
618
  */
619
- dmarcSpfAligned?: boolean;
619
+ dmarcSpfAligned: boolean;
620
620
  /**
621
621
  * Whether DKIM aligned with the From: domain for DMARC purposes.
622
622
  *
623
- * True if at least one DKIM signature's domain matches the From: domain. Optional in self-hosted environments.
623
+ * True if at least one DKIM signature's domain matches the From: domain.
624
624
  */
625
- dmarcDkimAligned?: boolean;
625
+ dmarcDkimAligned: boolean;
626
626
  /**
627
627
  * Whether DMARC SPF alignment mode is strict.
628
628
  *
@@ -651,8 +651,6 @@ interface EmailAuth$1 {
651
651
  *
652
652
  * An email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently.
653
653
  *
654
- * Fields marked optional (`selector`, `keyBits`, `algo`) may be unavailable in self-hosted environments where the milter provides limited DKIM detail.
655
- *
656
654
  * This interface was referenced by `EmailReceivedEvent`'s JSON-Schema
657
655
  * via the `definition` "DkimSignature".
658
656
  */
@@ -666,7 +664,7 @@ interface DkimSignature$1 {
666
664
  *
667
665
  * Optional in self-hosted environments where the milter may not provide selector info.
668
666
  */
669
- selector?: (string | null);
667
+ selector: (string | null);
670
668
  /**
671
669
  * Verification result for this specific signature.
672
670
  */
@@ -684,13 +682,13 @@ interface DkimSignature$1 {
684
682
  *
685
683
  * Optional in self-hosted environments.
686
684
  */
687
- keyBits?: (number | null);
685
+ keyBits: (number | null);
688
686
  /**
689
687
  * Signing algorithm (e.g., "rsa-sha256", "ed25519-sha256").
690
688
  *
691
689
  * Optional in self-hosted environments.
692
690
  */
693
- algo?: (string | null);
691
+ algo: (string | null);
694
692
  } //#endregion
695
693
  //#region src/types.d.ts
696
694
 
@@ -1,3 +1,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-C6M6oCRS.js";
2
- import { DecodeRawEmailOptions, 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, SignResult, VERIFICATION_ERRORS$1 as VERIFICATION_ERRORS, 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, getDownloadTimeRemaining$1 as getDownloadTimeRemaining, handleWebhook$1 as handleWebhook, isDownloadExpired$1 as isDownloadExpired, isEmailReceivedEvent$1 as isEmailReceivedEvent, isRawIncluded$1 as isRawIncluded, parseWebhookEvent$1 as parseWebhookEvent, safeValidateEmailReceivedEvent$1 as safeValidateEmailReceivedEvent, signWebhookPayload$1 as signWebhookPayload, validateEmailAuth$1 as validateEmailAuth, validateEmailReceivedEvent$1 as validateEmailReceivedEvent, verifyRawEmailDownload$1 as verifyRawEmailDownload, verifyWebhookSignature$1 as verifyWebhookSignature } from "../index-pNcbeqPI.js";
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-B5IgP-Zx.js";
2
+ import { DecodeRawEmailOptions, 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, SignResult, VERIFICATION_ERRORS$1 as VERIFICATION_ERRORS, 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, getDownloadTimeRemaining$1 as getDownloadTimeRemaining, handleWebhook$1 as handleWebhook, isDownloadExpired$1 as isDownloadExpired, isEmailReceivedEvent$1 as isEmailReceivedEvent, isRawIncluded$1 as isRawIncluded, parseWebhookEvent$1 as parseWebhookEvent, safeValidateEmailReceivedEvent$1 as safeValidateEmailReceivedEvent, signWebhookPayload$1 as signWebhookPayload, validateEmailAuth$1 as validateEmailAuth, validateEmailReceivedEvent$1 as validateEmailReceivedEvent, verifyRawEmailDownload$1 as verifyRawEmailDownload, verifyWebhookSignature$1 as verifyWebhookSignature } from "../index-BdRIHaXz.js";
3
3
  export { AuthConfidence, AuthVerdict, DecodeRawEmailOptions, DkimResult, DkimSignature, DmarcPolicy, DmarcResult, EmailAddress, EmailAnalysis, EmailAuth, EmailReceivedEvent, EventType, ForwardAnalysis, ForwardOriginalSender, ForwardResult, ForwardResultAttachmentAnalyzed, ForwardResultAttachmentSkipped, ForwardResultInline, ForwardVerdict, ForwardVerification, 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, SignResult, SpfResult, UnknownEvent, VERIFICATION_ERRORS, ValidateEmailAuthResult, VerifyOptions, WEBHOOK_VERSION, WebhookAttachment, WebhookErrorCode, WebhookEvent, WebhookHeaders, WebhookPayloadError, WebhookPayloadErrorCode, WebhookValidationError, WebhookValidationErrorCode, WebhookVerificationError, WebhookVerificationErrorCode, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature };
@@ -1,3 +1,3 @@
1
- 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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature } from "../webhook-Cz3QsQnS.js";
1
+ 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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature } from "../webhook-Be2vM0F-.js";
2
2
 
3
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, SpfResult, VERIFICATION_ERRORS, WEBHOOK_VERSION, WebhookPayloadError, WebhookValidationError, WebhookVerificationError, confirmedHeaders, decodeRawEmail, emailReceivedEventJsonSchema, getDownloadTimeRemaining, handleWebhook, isDownloadExpired, isEmailReceivedEvent, isRawIncluded, parseWebhookEvent, safeValidateEmailReceivedEvent, signWebhookPayload, validateEmailAuth, validateEmailReceivedEvent, verifyRawEmailDownload, verifyWebhookSignature };
@@ -4042,11 +4042,11 @@ const schema38 = {
4042
4042
  },
4043
4043
  "dmarcSpfAligned": {
4044
4044
  "type": "boolean",
4045
- "description": "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode). Optional in self-hosted environments."
4045
+ "description": "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode)."
4046
4046
  },
4047
4047
  "dmarcDkimAligned": {
4048
4048
  "type": "boolean",
4049
- "description": "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain. Optional in self-hosted environments."
4049
+ "description": "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain."
4050
4050
  },
4051
4051
  "dmarcSpfStrict": {
4052
4052
  "type": ["boolean", "null"],
@@ -4067,6 +4067,8 @@ const schema38 = {
4067
4067
  "dmarc",
4068
4068
  "dmarcPolicy",
4069
4069
  "dmarcFromDomain",
4070
+ "dmarcSpfAligned",
4071
+ "dmarcDkimAligned",
4070
4072
  "dmarcSpfStrict",
4071
4073
  "dmarcDkimStrict",
4072
4074
  "dkimSignatures"
@@ -4129,10 +4131,13 @@ const schema42 = {
4129
4131
  },
4130
4132
  "required": [
4131
4133
  "domain",
4134
+ "selector",
4132
4135
  "result",
4133
- "aligned"
4136
+ "aligned",
4137
+ "keyBits",
4138
+ "algo"
4134
4139
  ],
4135
- "description": "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently.\n\nFields marked optional (`selector`, `keyBits`, `algo`) may be unavailable in self-hosted environments where the milter provides limited DKIM detail."
4140
+ "description": "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently."
4136
4141
  };
4137
4142
  const schema43 = {
4138
4143
  "type": "string",
@@ -4160,117 +4165,153 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
4160
4165
  else vErrors.push(err0);
4161
4166
  errors++;
4162
4167
  }
4163
- if (data.result === void 0) {
4168
+ if (data.selector === void 0) {
4164
4169
  const err1 = {
4165
4170
  instancePath,
4166
4171
  schemaPath: "#/required",
4167
4172
  keyword: "required",
4168
- params: { missingProperty: "result" },
4169
- message: "must have required property 'result'"
4173
+ params: { missingProperty: "selector" },
4174
+ message: "must have required property 'selector'"
4170
4175
  };
4171
4176
  if (vErrors === null) vErrors = [err1];
4172
4177
  else vErrors.push(err1);
4173
4178
  errors++;
4174
4179
  }
4175
- if (data.aligned === void 0) {
4180
+ if (data.result === void 0) {
4176
4181
  const err2 = {
4177
4182
  instancePath,
4178
4183
  schemaPath: "#/required",
4179
4184
  keyword: "required",
4180
- params: { missingProperty: "aligned" },
4181
- message: "must have required property 'aligned'"
4185
+ params: { missingProperty: "result" },
4186
+ message: "must have required property 'result'"
4182
4187
  };
4183
4188
  if (vErrors === null) vErrors = [err2];
4184
4189
  else vErrors.push(err2);
4185
4190
  errors++;
4186
4191
  }
4192
+ if (data.aligned === void 0) {
4193
+ const err3 = {
4194
+ instancePath,
4195
+ schemaPath: "#/required",
4196
+ keyword: "required",
4197
+ params: { missingProperty: "aligned" },
4198
+ message: "must have required property 'aligned'"
4199
+ };
4200
+ if (vErrors === null) vErrors = [err3];
4201
+ else vErrors.push(err3);
4202
+ errors++;
4203
+ }
4204
+ if (data.keyBits === void 0) {
4205
+ const err4 = {
4206
+ instancePath,
4207
+ schemaPath: "#/required",
4208
+ keyword: "required",
4209
+ params: { missingProperty: "keyBits" },
4210
+ message: "must have required property 'keyBits'"
4211
+ };
4212
+ if (vErrors === null) vErrors = [err4];
4213
+ else vErrors.push(err4);
4214
+ errors++;
4215
+ }
4216
+ if (data.algo === void 0) {
4217
+ const err5 = {
4218
+ instancePath,
4219
+ schemaPath: "#/required",
4220
+ keyword: "required",
4221
+ params: { missingProperty: "algo" },
4222
+ message: "must have required property 'algo'"
4223
+ };
4224
+ if (vErrors === null) vErrors = [err5];
4225
+ else vErrors.push(err5);
4226
+ errors++;
4227
+ }
4187
4228
  if (data.domain !== void 0) {
4188
4229
  if (typeof data.domain !== "string") {
4189
- const err3 = {
4230
+ const err6 = {
4190
4231
  instancePath: instancePath + "/domain",
4191
4232
  schemaPath: "#/properties/domain/type",
4192
4233
  keyword: "type",
4193
4234
  params: { type: "string" },
4194
4235
  message: "must be string"
4195
4236
  };
4196
- if (vErrors === null) vErrors = [err3];
4197
- else vErrors.push(err3);
4237
+ if (vErrors === null) vErrors = [err6];
4238
+ else vErrors.push(err6);
4198
4239
  errors++;
4199
4240
  }
4200
4241
  }
4201
4242
  if (data.selector !== void 0) {
4202
4243
  let data1 = data.selector;
4203
4244
  if (typeof data1 !== "string" && data1 !== null) {
4204
- const err4 = {
4245
+ const err7 = {
4205
4246
  instancePath: instancePath + "/selector",
4206
4247
  schemaPath: "#/properties/selector/type",
4207
4248
  keyword: "type",
4208
4249
  params: { type: schema42.properties.selector.type },
4209
4250
  message: "must be string,null"
4210
4251
  };
4211
- if (vErrors === null) vErrors = [err4];
4212
- else vErrors.push(err4);
4252
+ if (vErrors === null) vErrors = [err7];
4253
+ else vErrors.push(err7);
4213
4254
  errors++;
4214
4255
  }
4215
4256
  }
4216
4257
  if (data.result !== void 0) {
4217
4258
  let data2 = data.result;
4218
4259
  if (typeof data2 !== "string") {
4219
- const err5 = {
4260
+ const err8 = {
4220
4261
  instancePath: instancePath + "/result",
4221
4262
  schemaPath: "#/definitions/DkimResult/type",
4222
4263
  keyword: "type",
4223
4264
  params: { type: "string" },
4224
4265
  message: "must be string"
4225
4266
  };
4226
- if (vErrors === null) vErrors = [err5];
4227
- else vErrors.push(err5);
4267
+ if (vErrors === null) vErrors = [err8];
4268
+ else vErrors.push(err8);
4228
4269
  errors++;
4229
4270
  }
4230
4271
  if (!(data2 === "pass" || data2 === "fail" || data2 === "temperror" || data2 === "permerror")) {
4231
- const err6 = {
4272
+ const err9 = {
4232
4273
  instancePath: instancePath + "/result",
4233
4274
  schemaPath: "#/definitions/DkimResult/enum",
4234
4275
  keyword: "enum",
4235
4276
  params: { allowedValues: schema43.enum },
4236
4277
  message: "must be equal to one of the allowed values"
4237
4278
  };
4238
- if (vErrors === null) vErrors = [err6];
4239
- else vErrors.push(err6);
4279
+ if (vErrors === null) vErrors = [err9];
4280
+ else vErrors.push(err9);
4240
4281
  errors++;
4241
4282
  }
4242
4283
  }
4243
4284
  if (data.aligned !== void 0) {
4244
4285
  if (typeof data.aligned !== "boolean") {
4245
- const err7 = {
4286
+ const err10 = {
4246
4287
  instancePath: instancePath + "/aligned",
4247
4288
  schemaPath: "#/properties/aligned/type",
4248
4289
  keyword: "type",
4249
4290
  params: { type: "boolean" },
4250
4291
  message: "must be boolean"
4251
4292
  };
4252
- if (vErrors === null) vErrors = [err7];
4253
- else vErrors.push(err7);
4293
+ if (vErrors === null) vErrors = [err10];
4294
+ else vErrors.push(err10);
4254
4295
  errors++;
4255
4296
  }
4256
4297
  }
4257
4298
  if (data.keyBits !== void 0) {
4258
4299
  let data4 = data.keyBits;
4259
4300
  if (!(typeof data4 == "number" && !(data4 % 1) && !isNaN(data4)) && data4 !== null) {
4260
- const err8 = {
4301
+ const err11 = {
4261
4302
  instancePath: instancePath + "/keyBits",
4262
4303
  schemaPath: "#/properties/keyBits/type",
4263
4304
  keyword: "type",
4264
4305
  params: { type: schema42.properties.keyBits.type },
4265
4306
  message: "must be integer,null"
4266
4307
  };
4267
- if (vErrors === null) vErrors = [err8];
4268
- else vErrors.push(err8);
4308
+ if (vErrors === null) vErrors = [err11];
4309
+ else vErrors.push(err11);
4269
4310
  errors++;
4270
4311
  }
4271
4312
  if (typeof data4 == "number") {
4272
4313
  if (data4 > 16384 || isNaN(data4)) {
4273
- const err9 = {
4314
+ const err12 = {
4274
4315
  instancePath: instancePath + "/keyBits",
4275
4316
  schemaPath: "#/properties/keyBits/maximum",
4276
4317
  keyword: "maximum",
@@ -4280,12 +4321,12 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
4280
4321
  },
4281
4322
  message: "must be <= 16384"
4282
4323
  };
4283
- if (vErrors === null) vErrors = [err9];
4284
- else vErrors.push(err9);
4324
+ if (vErrors === null) vErrors = [err12];
4325
+ else vErrors.push(err12);
4285
4326
  errors++;
4286
4327
  }
4287
4328
  if (data4 < 1 || isNaN(data4)) {
4288
- const err10 = {
4329
+ const err13 = {
4289
4330
  instancePath: instancePath + "/keyBits",
4290
4331
  schemaPath: "#/properties/keyBits/minimum",
4291
4332
  keyword: "minimum",
@@ -4295,8 +4336,8 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
4295
4336
  },
4296
4337
  message: "must be >= 1"
4297
4338
  };
4298
- if (vErrors === null) vErrors = [err10];
4299
- else vErrors.push(err10);
4339
+ if (vErrors === null) vErrors = [err13];
4340
+ else vErrors.push(err13);
4300
4341
  errors++;
4301
4342
  }
4302
4343
  }
@@ -4304,28 +4345,28 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
4304
4345
  if (data.algo !== void 0) {
4305
4346
  let data5 = data.algo;
4306
4347
  if (typeof data5 !== "string" && data5 !== null) {
4307
- const err11 = {
4348
+ const err14 = {
4308
4349
  instancePath: instancePath + "/algo",
4309
4350
  schemaPath: "#/properties/algo/type",
4310
4351
  keyword: "type",
4311
4352
  params: { type: schema42.properties.algo.type },
4312
4353
  message: "must be string,null"
4313
4354
  };
4314
- if (vErrors === null) vErrors = [err11];
4315
- else vErrors.push(err11);
4355
+ if (vErrors === null) vErrors = [err14];
4356
+ else vErrors.push(err14);
4316
4357
  errors++;
4317
4358
  }
4318
4359
  }
4319
4360
  } else {
4320
- const err12 = {
4361
+ const err15 = {
4321
4362
  instancePath,
4322
4363
  schemaPath: "#/type",
4323
4364
  keyword: "type",
4324
4365
  params: { type: "object" },
4325
4366
  message: "must be object"
4326
4367
  };
4327
- if (vErrors === null) vErrors = [err12];
4328
- else vErrors.push(err12);
4368
+ if (vErrors === null) vErrors = [err15];
4369
+ else vErrors.push(err15);
4329
4370
  errors++;
4330
4371
  }
4331
4372
  validate34.errors = vErrors;
@@ -4383,193 +4424,217 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
4383
4424
  else vErrors.push(err3);
4384
4425
  errors++;
4385
4426
  }
4386
- if (data.dmarcSpfStrict === void 0) {
4427
+ if (data.dmarcSpfAligned === void 0) {
4387
4428
  const err4 = {
4388
4429
  instancePath,
4389
4430
  schemaPath: "#/required",
4390
4431
  keyword: "required",
4391
- params: { missingProperty: "dmarcSpfStrict" },
4392
- message: "must have required property 'dmarcSpfStrict'"
4432
+ params: { missingProperty: "dmarcSpfAligned" },
4433
+ message: "must have required property 'dmarcSpfAligned'"
4393
4434
  };
4394
4435
  if (vErrors === null) vErrors = [err4];
4395
4436
  else vErrors.push(err4);
4396
4437
  errors++;
4397
4438
  }
4398
- if (data.dmarcDkimStrict === void 0) {
4439
+ if (data.dmarcDkimAligned === void 0) {
4399
4440
  const err5 = {
4400
4441
  instancePath,
4401
4442
  schemaPath: "#/required",
4402
4443
  keyword: "required",
4403
- params: { missingProperty: "dmarcDkimStrict" },
4404
- message: "must have required property 'dmarcDkimStrict'"
4444
+ params: { missingProperty: "dmarcDkimAligned" },
4445
+ message: "must have required property 'dmarcDkimAligned'"
4405
4446
  };
4406
4447
  if (vErrors === null) vErrors = [err5];
4407
4448
  else vErrors.push(err5);
4408
4449
  errors++;
4409
4450
  }
4410
- if (data.dkimSignatures === void 0) {
4451
+ if (data.dmarcSpfStrict === void 0) {
4411
4452
  const err6 = {
4412
4453
  instancePath,
4413
4454
  schemaPath: "#/required",
4414
4455
  keyword: "required",
4415
- params: { missingProperty: "dkimSignatures" },
4416
- message: "must have required property 'dkimSignatures'"
4456
+ params: { missingProperty: "dmarcSpfStrict" },
4457
+ message: "must have required property 'dmarcSpfStrict'"
4417
4458
  };
4418
4459
  if (vErrors === null) vErrors = [err6];
4419
4460
  else vErrors.push(err6);
4420
4461
  errors++;
4421
4462
  }
4463
+ if (data.dmarcDkimStrict === void 0) {
4464
+ const err7 = {
4465
+ instancePath,
4466
+ schemaPath: "#/required",
4467
+ keyword: "required",
4468
+ params: { missingProperty: "dmarcDkimStrict" },
4469
+ message: "must have required property 'dmarcDkimStrict'"
4470
+ };
4471
+ if (vErrors === null) vErrors = [err7];
4472
+ else vErrors.push(err7);
4473
+ errors++;
4474
+ }
4475
+ if (data.dkimSignatures === void 0) {
4476
+ const err8 = {
4477
+ instancePath,
4478
+ schemaPath: "#/required",
4479
+ keyword: "required",
4480
+ params: { missingProperty: "dkimSignatures" },
4481
+ message: "must have required property 'dkimSignatures'"
4482
+ };
4483
+ if (vErrors === null) vErrors = [err8];
4484
+ else vErrors.push(err8);
4485
+ errors++;
4486
+ }
4422
4487
  if (data.spf !== void 0) {
4423
4488
  let data0 = data.spf;
4424
4489
  if (typeof data0 !== "string") {
4425
- const err7 = {
4490
+ const err9 = {
4426
4491
  instancePath: instancePath + "/spf",
4427
4492
  schemaPath: "#/definitions/SpfResult/type",
4428
4493
  keyword: "type",
4429
4494
  params: { type: "string" },
4430
4495
  message: "must be string"
4431
4496
  };
4432
- if (vErrors === null) vErrors = [err7];
4433
- else vErrors.push(err7);
4497
+ if (vErrors === null) vErrors = [err9];
4498
+ else vErrors.push(err9);
4434
4499
  errors++;
4435
4500
  }
4436
4501
  if (!(data0 === "pass" || data0 === "fail" || data0 === "softfail" || data0 === "neutral" || data0 === "none" || data0 === "temperror" || data0 === "permerror")) {
4437
- const err8 = {
4502
+ const err10 = {
4438
4503
  instancePath: instancePath + "/spf",
4439
4504
  schemaPath: "#/definitions/SpfResult/enum",
4440
4505
  keyword: "enum",
4441
4506
  params: { allowedValues: schema39.enum },
4442
4507
  message: "must be equal to one of the allowed values"
4443
4508
  };
4444
- if (vErrors === null) vErrors = [err8];
4445
- else vErrors.push(err8);
4509
+ if (vErrors === null) vErrors = [err10];
4510
+ else vErrors.push(err10);
4446
4511
  errors++;
4447
4512
  }
4448
4513
  }
4449
4514
  if (data.dmarc !== void 0) {
4450
4515
  let data1 = data.dmarc;
4451
4516
  if (typeof data1 !== "string") {
4452
- const err9 = {
4517
+ const err11 = {
4453
4518
  instancePath: instancePath + "/dmarc",
4454
4519
  schemaPath: "#/definitions/DmarcResult/type",
4455
4520
  keyword: "type",
4456
4521
  params: { type: "string" },
4457
4522
  message: "must be string"
4458
4523
  };
4459
- if (vErrors === null) vErrors = [err9];
4460
- else vErrors.push(err9);
4524
+ if (vErrors === null) vErrors = [err11];
4525
+ else vErrors.push(err11);
4461
4526
  errors++;
4462
4527
  }
4463
4528
  if (!(data1 === "pass" || data1 === "fail" || data1 === "none" || data1 === "temperror" || data1 === "permerror")) {
4464
- const err10 = {
4529
+ const err12 = {
4465
4530
  instancePath: instancePath + "/dmarc",
4466
4531
  schemaPath: "#/definitions/DmarcResult/enum",
4467
4532
  keyword: "enum",
4468
4533
  params: { allowedValues: schema40.enum },
4469
4534
  message: "must be equal to one of the allowed values"
4470
4535
  };
4471
- if (vErrors === null) vErrors = [err10];
4472
- else vErrors.push(err10);
4536
+ if (vErrors === null) vErrors = [err12];
4537
+ else vErrors.push(err12);
4473
4538
  errors++;
4474
4539
  }
4475
4540
  }
4476
4541
  if (data.dmarcPolicy !== void 0) {
4477
4542
  let data2 = data.dmarcPolicy;
4478
4543
  if (typeof data2 !== "string" && data2 !== null) {
4479
- const err11 = {
4544
+ const err13 = {
4480
4545
  instancePath: instancePath + "/dmarcPolicy",
4481
4546
  schemaPath: "#/definitions/DmarcPolicy/type",
4482
4547
  keyword: "type",
4483
4548
  params: { type: schema34.type },
4484
4549
  message: "must be string,null"
4485
4550
  };
4486
- if (vErrors === null) vErrors = [err11];
4487
- else vErrors.push(err11);
4551
+ if (vErrors === null) vErrors = [err13];
4552
+ else vErrors.push(err13);
4488
4553
  errors++;
4489
4554
  }
4490
4555
  if (!(data2 === "reject" || data2 === "quarantine" || data2 === "none" || data2 === null)) {
4491
- const err12 = {
4556
+ const err14 = {
4492
4557
  instancePath: instancePath + "/dmarcPolicy",
4493
4558
  schemaPath: "#/definitions/DmarcPolicy/enum",
4494
4559
  keyword: "enum",
4495
4560
  params: { allowedValues: schema34.enum },
4496
4561
  message: "must be equal to one of the allowed values"
4497
4562
  };
4498
- if (vErrors === null) vErrors = [err12];
4499
- else vErrors.push(err12);
4563
+ if (vErrors === null) vErrors = [err14];
4564
+ else vErrors.push(err14);
4500
4565
  errors++;
4501
4566
  }
4502
4567
  }
4503
4568
  if (data.dmarcFromDomain !== void 0) {
4504
4569
  let data3 = data.dmarcFromDomain;
4505
4570
  if (typeof data3 !== "string" && data3 !== null) {
4506
- const err13 = {
4571
+ const err15 = {
4507
4572
  instancePath: instancePath + "/dmarcFromDomain",
4508
4573
  schemaPath: "#/properties/dmarcFromDomain/type",
4509
4574
  keyword: "type",
4510
4575
  params: { type: schema38.properties.dmarcFromDomain.type },
4511
4576
  message: "must be string,null"
4512
4577
  };
4513
- if (vErrors === null) vErrors = [err13];
4514
- else vErrors.push(err13);
4578
+ if (vErrors === null) vErrors = [err15];
4579
+ else vErrors.push(err15);
4515
4580
  errors++;
4516
4581
  }
4517
4582
  }
4518
4583
  if (data.dmarcSpfAligned !== void 0) {
4519
4584
  if (typeof data.dmarcSpfAligned !== "boolean") {
4520
- const err14 = {
4585
+ const err16 = {
4521
4586
  instancePath: instancePath + "/dmarcSpfAligned",
4522
4587
  schemaPath: "#/properties/dmarcSpfAligned/type",
4523
4588
  keyword: "type",
4524
4589
  params: { type: "boolean" },
4525
4590
  message: "must be boolean"
4526
4591
  };
4527
- if (vErrors === null) vErrors = [err14];
4528
- else vErrors.push(err14);
4592
+ if (vErrors === null) vErrors = [err16];
4593
+ else vErrors.push(err16);
4529
4594
  errors++;
4530
4595
  }
4531
4596
  }
4532
4597
  if (data.dmarcDkimAligned !== void 0) {
4533
4598
  if (typeof data.dmarcDkimAligned !== "boolean") {
4534
- const err15 = {
4599
+ const err17 = {
4535
4600
  instancePath: instancePath + "/dmarcDkimAligned",
4536
4601
  schemaPath: "#/properties/dmarcDkimAligned/type",
4537
4602
  keyword: "type",
4538
4603
  params: { type: "boolean" },
4539
4604
  message: "must be boolean"
4540
4605
  };
4541
- if (vErrors === null) vErrors = [err15];
4542
- else vErrors.push(err15);
4606
+ if (vErrors === null) vErrors = [err17];
4607
+ else vErrors.push(err17);
4543
4608
  errors++;
4544
4609
  }
4545
4610
  }
4546
4611
  if (data.dmarcSpfStrict !== void 0) {
4547
4612
  let data6 = data.dmarcSpfStrict;
4548
4613
  if (typeof data6 !== "boolean" && data6 !== null) {
4549
- const err16 = {
4614
+ const err18 = {
4550
4615
  instancePath: instancePath + "/dmarcSpfStrict",
4551
4616
  schemaPath: "#/properties/dmarcSpfStrict/type",
4552
4617
  keyword: "type",
4553
4618
  params: { type: schema38.properties.dmarcSpfStrict.type },
4554
4619
  message: "must be boolean,null"
4555
4620
  };
4556
- if (vErrors === null) vErrors = [err16];
4557
- else vErrors.push(err16);
4621
+ if (vErrors === null) vErrors = [err18];
4622
+ else vErrors.push(err18);
4558
4623
  errors++;
4559
4624
  }
4560
4625
  }
4561
4626
  if (data.dmarcDkimStrict !== void 0) {
4562
4627
  let data7 = data.dmarcDkimStrict;
4563
4628
  if (typeof data7 !== "boolean" && data7 !== null) {
4564
- const err17 = {
4629
+ const err19 = {
4565
4630
  instancePath: instancePath + "/dmarcDkimStrict",
4566
4631
  schemaPath: "#/properties/dmarcDkimStrict/type",
4567
4632
  keyword: "type",
4568
4633
  params: { type: schema38.properties.dmarcDkimStrict.type },
4569
4634
  message: "must be boolean,null"
4570
4635
  };
4571
- if (vErrors === null) vErrors = [err17];
4572
- else vErrors.push(err17);
4636
+ if (vErrors === null) vErrors = [err19];
4637
+ else vErrors.push(err19);
4573
4638
  errors++;
4574
4639
  }
4575
4640
  }
@@ -4587,28 +4652,28 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
4587
4652
  errors = vErrors.length;
4588
4653
  }
4589
4654
  } else {
4590
- const err18 = {
4655
+ const err20 = {
4591
4656
  instancePath: instancePath + "/dkimSignatures",
4592
4657
  schemaPath: "#/properties/dkimSignatures/type",
4593
4658
  keyword: "type",
4594
4659
  params: { type: "array" },
4595
4660
  message: "must be array"
4596
4661
  };
4597
- if (vErrors === null) vErrors = [err18];
4598
- else vErrors.push(err18);
4662
+ if (vErrors === null) vErrors = [err20];
4663
+ else vErrors.push(err20);
4599
4664
  errors++;
4600
4665
  }
4601
4666
  }
4602
4667
  } else {
4603
- const err19 = {
4668
+ const err21 = {
4604
4669
  instancePath,
4605
4670
  schemaPath: "#/type",
4606
4671
  keyword: "type",
4607
4672
  params: { type: "object" },
4608
4673
  message: "must be object"
4609
4674
  };
4610
- if (vErrors === null) vErrors = [err19];
4611
- else vErrors.push(err19);
4675
+ if (vErrors === null) vErrors = [err21];
4676
+ else vErrors.push(err21);
4612
4677
  errors++;
4613
4678
  }
4614
4679
  validate33.errors = vErrors;
@@ -6956,11 +7021,11 @@ const emailReceivedEventJsonSchema = {
6956
7021
  },
6957
7022
  "dmarcSpfAligned": {
6958
7023
  "type": "boolean",
6959
- "description": "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode). Optional in self-hosted environments."
7024
+ "description": "Whether SPF aligned with the From: domain for DMARC purposes.\n\nTrue if the envelope sender domain matches the From: domain (per alignment mode)."
6960
7025
  },
6961
7026
  "dmarcDkimAligned": {
6962
7027
  "type": "boolean",
6963
- "description": "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain. Optional in self-hosted environments."
7028
+ "description": "Whether DKIM aligned with the From: domain for DMARC purposes.\n\nTrue if at least one DKIM signature's domain matches the From: domain."
6964
7029
  },
6965
7030
  "dmarcSpfStrict": {
6966
7031
  "type": ["boolean", "null"],
@@ -6981,6 +7046,8 @@ const emailReceivedEventJsonSchema = {
6981
7046
  "dmarc",
6982
7047
  "dmarcPolicy",
6983
7048
  "dmarcFromDomain",
7049
+ "dmarcSpfAligned",
7050
+ "dmarcDkimAligned",
6984
7051
  "dmarcSpfStrict",
6985
7052
  "dmarcDkimStrict",
6986
7053
  "dkimSignatures"
@@ -7043,10 +7110,13 @@ const emailReceivedEventJsonSchema = {
7043
7110
  },
7044
7111
  "required": [
7045
7112
  "domain",
7113
+ "selector",
7046
7114
  "result",
7047
- "aligned"
7115
+ "aligned",
7116
+ "keyBits",
7117
+ "algo"
7048
7118
  ],
7049
- "description": "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently.\n\nFields marked optional (`selector`, `keyBits`, `algo`) may be unavailable in self-hosted environments where the milter provides limited DKIM detail."
7119
+ "description": "Details about a single DKIM signature found in the email.\n\nAn email may have multiple DKIM signatures (e.g., one from the sending domain and one from the ESP). Each signature is verified independently."
7050
7120
  },
7051
7121
  "DkimResult": {
7052
7122
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitivedotdev/sdk",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Official Primitive Node.js SDK — webhook, contract, and parser modules",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
@@ -66,7 +66,6 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "ajv": "^8.17.1",
69
- "ajv-formats": "^3.0.1",
70
69
  "archiver": "^7.0.1",
71
70
  "isomorphic-dompurify": "^3.8.0",
72
71
  "mailparser": "^3.9.0"