@vlayer/sdk 0.1.0-nightly-20241001-aa0406f → 0.1.0-nightly-20241001-f254bee

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vlayer/sdk",
3
3
  "type": "module",
4
4
  "module": "src/index.ts",
5
- "version": "0.1.0-nightly-20241001-aa0406f",
5
+ "version": "0.1.0-nightly-20241001-f254bee",
6
6
  "scripts": {
7
7
  "build": "npm run gen:types",
8
8
  "test": "vitest --run",
@@ -19,7 +19,9 @@
19
19
  "typescript": "^5.0.0"
20
20
  },
21
21
  "dependencies": {
22
+ "dns-over-http-resolver": "^3.0.3",
22
23
  "mailparser": "^3.7.1",
24
+ "postal-mime": "^2.3.2",
23
25
  "viem": "^2.21.0"
24
26
  }
25
27
  }
@@ -1,14 +1,7 @@
1
- import dns from "node:dns";
1
+ import DnsResolver from "dns-over-http-resolver";
2
2
 
3
3
  export async function resolveDkimDns(domain: string, selector: string) {
4
- return new Promise<string>((resolve, reject) => {
5
- dns.resolveTxt(`${selector}._domainkey.${domain}`, (err, addresses) => {
6
- if (err) {
7
- reject(err);
8
- return;
9
- }
10
-
11
- resolve(addresses.flat()[0]);
12
- });
13
- });
4
+ const resolver = new DnsResolver();
5
+ const address = await resolver.resolveTxt(`${selector}._domainkey.${domain}`);
6
+ return address.flat()[0];
14
7
  }
@@ -1,7 +1,5 @@
1
- import assert from "node:assert";
2
1
  import { describe, expect, test } from "vitest";
3
- import { getDkimSigners, parseEmail } from "./parseEmail.ts";
4
- import { StructuredHeader } from "mailparser";
2
+ import { getDkimSigners, parseEmail, parseParams } from "./parseEmail.ts";
5
3
 
6
4
  const emailHeaders = `From: "John Doe" <john@d.oe>
7
5
  To: "Jane Doe" <jane@d.oe>
@@ -17,18 +15,12 @@ const body = "Hello, World!";
17
15
  const emailFixture = `${emailHeaders}${dkimHeader}\n\n${body}`;
18
16
 
19
17
  describe("parseEmail", () => {
20
- test("should get dkim header from email", async () => {
21
- const email = await parseEmail(emailFixture);
22
- const dkim = email.headers.get("dkim-signature")!;
23
- assert(typeof dkim === "object" && "params" in dkim);
24
- expect(dkim.params.d).toBe("example.com");
25
- expect(dkim.params.s).toBe("selector1");
26
- });
18
+ test("should get dkim header from email", async () => {});
27
19
 
28
20
  test("correctly parses untrimmed email", async () => {
29
21
  const untrimmed = `\n ${emailFixture} \n`;
30
22
  const email = await parseEmail(untrimmed);
31
- expect(email.headers.get("dkim-signature")).toBeDefined();
23
+ expect(email.headers.find((h) => h.key === "dkim-signature")).toBeDefined();
32
24
  });
33
25
 
34
26
  test("works well with multiple dkim headers", async () => {
@@ -38,12 +30,11 @@ describe("parseEmail", () => {
38
30
  const email = await parseEmail(
39
31
  `${emailHeaders}${dkimHeader}\n${dkimHeader2}\n\n${body}`,
40
32
  );
41
- const dkim = email.headers.get(
42
- "dkim-signature",
43
- )! as unknown as StructuredHeader[];
33
+ const dkim = email.headers.filter((h) => h.key === "dkim-signature")!;
34
+
44
35
  expect(dkim).toHaveLength(2);
45
- expect(dkim[0].params.s).toBe("selector1");
46
- expect(dkim[1].params.s).toBe("selector2");
36
+ expect(parseParams(dkim[0].value).s).toBe("selector1");
37
+ expect(parseParams(dkim[1].value).s).toBe("selector2");
47
38
  });
48
39
  });
49
40
 
@@ -103,3 +94,40 @@ describe("getDkimSigners", () => {
103
94
  );
104
95
  });
105
96
  });
97
+
98
+ describe("parseParams", () => {
99
+ test("should parse single parameter", () => {
100
+ const params = parseParams("a=b");
101
+ expect(params).toEqual({ a: "b" });
102
+ });
103
+
104
+ test("should parse multiple parameters", () => {
105
+ const params = parseParams("a=b; c=d; e=f");
106
+ expect(params).toEqual({ a: "b", c: "d", e: "f" });
107
+ });
108
+
109
+ test("should trim spaces around parameters", () => {
110
+ const params = parseParams(" a = b ; c = d ; e = f ");
111
+ expect(params).toEqual({ a: "b", c: "d", e: "f" });
112
+ });
113
+
114
+ test("should handle empty values", () => {
115
+ const params = parseParams("a=; b=c");
116
+ expect(params).toEqual({ a: "", b: "c" });
117
+ });
118
+
119
+ test("should handle missing values", () => {
120
+ const params = parseParams("a; b=c");
121
+ expect(params).toEqual({ a: undefined, b: "c" });
122
+ });
123
+
124
+ test("should handle empty string", () => {
125
+ const params = parseParams("");
126
+ expect(params).toEqual({});
127
+ });
128
+
129
+ test("should handle parameters with extra semicolons", () => {
130
+ const params = parseParams("a=b;; c=d;");
131
+ expect(params).toEqual({ a: "b", c: "d" });
132
+ });
133
+ });
@@ -1,4 +1,4 @@
1
- import { simpleParser, HeaderValue, type ParsedMail } from "mailparser";
1
+ import PostalMime, { Email, Header } from "postal-mime";
2
2
 
3
3
  export class DkimParsingError extends Error {
4
4
  constructor(message: string) {
@@ -8,38 +8,42 @@ export class DkimParsingError extends Error {
8
8
  }
9
9
 
10
10
  export async function parseEmail(mime: string) {
11
- return simpleParser(mime.trim(), {
12
- skipHtmlToText: true,
13
- skipTextToHtml: true,
14
- skipTextLinks: true,
15
- skipImageLinks: true,
16
- });
11
+ return await PostalMime.parse(mime.trim());
17
12
  }
18
13
 
19
- export function getDkimSigners(mail: ParsedMail) {
20
- const dkimHeader = mail.headers.get("dkim-signature");
21
- if (!dkimHeader) throw new DkimParsingError("No DKIM header found");
22
- if (Array.isArray(dkimHeader)) {
23
- return dkimHeader.map(parseHeader);
24
- }
25
- return [parseHeader(dkimHeader)];
14
+ export function getDkimSigners(mail: Email) {
15
+ const dkimHeader = mail.headers.filter((h) => h.key === "dkim-signature");
16
+ if (dkimHeader.length === 0)
17
+ throw new DkimParsingError("No DKIM header found");
18
+ return dkimHeader.map(parseHeader);
19
+ }
20
+
21
+ export function parseParams(str: string) {
22
+ return Object.fromEntries(
23
+ str.split(";").map((s) =>
24
+ s
25
+ .trim()
26
+ .split("=")
27
+ .map((v) => v && v.trim()),
28
+ ),
29
+ );
26
30
  }
27
31
 
28
- function parseHeader(header: HeaderValue) {
29
- if (typeof header === "string" || !("params" in header)) {
32
+ function parseHeader(header: Header) {
33
+ const params = parseParams(header.value);
34
+ if (!params) {
30
35
  throw new DkimParsingError(`Invalid DKIM header ${header}`);
31
36
  }
32
37
 
33
- if (!header.params.d) {
38
+ if (!params.d) {
34
39
  throw new DkimParsingError("DKIM header missing domain");
35
40
  }
36
41
 
37
- if (!header.params.s) {
42
+ if (!params.s) {
38
43
  throw new DkimParsingError("DKIM header missing selector");
39
44
  }
40
-
41
45
  return {
42
- domain: header.params.d,
43
- selector: header.params.s,
46
+ domain: params.d,
47
+ selector: params.s,
44
48
  };
45
49
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from "vitest";
2
2
  import { preverifyEmail } from "./preverify.ts";
3
- import { readFile } from "testHelpers/readFile";
3
+ import { readFile } from "../../testHelpers/readFile";
4
4
 
5
5
  describe("Preverify email: integration", () => {
6
6
  test("adds dns record to email mime", async () => {