@remit/mailbox-service 0.0.8 → 0.0.9
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
|
-
import { MailboxSpecialUse } from "@remit/domain-enums";
|
|
3
|
+
import { MailboxAttribute, MailboxSpecialUse } from "@remit/domain-enums";
|
|
4
4
|
import {
|
|
5
5
|
hasChildren,
|
|
6
6
|
isNoSelect,
|
|
@@ -50,7 +50,33 @@ describe("parseImapAttributes special-use", () => {
|
|
|
50
50
|
it("separates standard attributes from special-use", () => {
|
|
51
51
|
const parsed = parseImapAttributes(["\\HasChildren", "\\Sent"]);
|
|
52
52
|
assert.deepStrictEqual(parsed.specialUse, [MailboxSpecialUse.Sent]);
|
|
53
|
-
assert.deepStrictEqual(parsed.attributes, ["HasChildren"]);
|
|
53
|
+
assert.deepStrictEqual(parsed.attributes, ["\\HasChildren"]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("keeps standard attributes in the RFC 9051 backslash-prefixed form", () => {
|
|
57
|
+
const parsed = parseImapAttributes([
|
|
58
|
+
"\\NonExistent",
|
|
59
|
+
"\\Noinferiors",
|
|
60
|
+
"\\Noselect",
|
|
61
|
+
"\\HasChildren",
|
|
62
|
+
"\\HasNoChildren",
|
|
63
|
+
"\\Marked",
|
|
64
|
+
"\\Unmarked",
|
|
65
|
+
"\\Subscribed",
|
|
66
|
+
"\\Remote",
|
|
67
|
+
]);
|
|
68
|
+
assert.deepStrictEqual(parsed.attributes, [
|
|
69
|
+
"\\NonExistent",
|
|
70
|
+
"\\Noinferiors",
|
|
71
|
+
"\\Noselect",
|
|
72
|
+
"\\HasChildren",
|
|
73
|
+
"\\HasNoChildren",
|
|
74
|
+
"\\Marked",
|
|
75
|
+
"\\Unmarked",
|
|
76
|
+
"\\Subscribed",
|
|
77
|
+
"\\Remote",
|
|
78
|
+
]);
|
|
79
|
+
assert.deepStrictEqual(parsed.attributes, Object.values(MailboxAttribute));
|
|
54
80
|
});
|
|
55
81
|
|
|
56
82
|
it("collects unknown attributes without dropping them", () => {
|
package/src/attribute-mapper.ts
CHANGED
|
@@ -11,8 +11,9 @@ type MailboxSpecialUseValue =
|
|
|
11
11
|
(typeof MailboxSpecialUse)[keyof typeof MailboxSpecialUse];
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Map from IMAP attribute strings to MailboxAttribute enum values
|
|
15
|
-
*
|
|
14
|
+
* Map from IMAP attribute strings to MailboxAttribute enum values.
|
|
15
|
+
* MailboxAttribute keeps the RFC 9051 backslash prefix; MailboxSpecialUse
|
|
16
|
+
* below is a canonical bare designation, so only that map strips it.
|
|
16
17
|
*/
|
|
17
18
|
const ATTRIBUTE_MAP: Record<string, MailboxAttributeValue> = {
|
|
18
19
|
"\\NonExistent": MailboxAttribute.NonExistent,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
MailboxAttribute,
|
|
5
|
+
MessageKeywordFlag,
|
|
6
|
+
MessageSystemFlag,
|
|
7
|
+
} from "@remit/domain-enums";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* RFC 9051 §2.3.2 system flags and §7.3.1 mailbox attributes are
|
|
11
|
+
* backslash-prefixed on the wire, and these enum values reach an IMAP server
|
|
12
|
+
* verbatim: `handleFlagPush` passes a marker's `flagName` straight to
|
|
13
|
+
* `ImapFlowConnection.addFlags`/`removeFlags`. A value that has lost its
|
|
14
|
+
* backslash is still a legal STORE argument — the server takes it as a custom
|
|
15
|
+
* keyword — so the push silently sets the wrong thing rather than failing.
|
|
16
|
+
*
|
|
17
|
+
* These enums are generated, and the emitter writes their values into
|
|
18
|
+
* JavaScript source where an unescaped `\S` collapses to `S` (issue #64).
|
|
19
|
+
* Pin the exact bytes so a regression fails here instead of on a real
|
|
20
|
+
* mailbox.
|
|
21
|
+
*/
|
|
22
|
+
const SYSTEM_FLAG_WIRE_FORMAT = {
|
|
23
|
+
Seen: "\\Seen",
|
|
24
|
+
Answered: "\\Answered",
|
|
25
|
+
Flagged: "\\Flagged",
|
|
26
|
+
Deleted: "\\Deleted",
|
|
27
|
+
Draft: "\\Draft",
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
const MAILBOX_ATTRIBUTE_WIRE_FORMAT = {
|
|
31
|
+
NonExistent: "\\NonExistent",
|
|
32
|
+
NoInferiors: "\\Noinferiors",
|
|
33
|
+
NoSelect: "\\Noselect",
|
|
34
|
+
HasChildren: "\\HasChildren",
|
|
35
|
+
HasNoChildren: "\\HasNoChildren",
|
|
36
|
+
Marked: "\\Marked",
|
|
37
|
+
Unmarked: "\\Unmarked",
|
|
38
|
+
Subscribed: "\\Subscribed",
|
|
39
|
+
Remote: "\\Remote",
|
|
40
|
+
} as const;
|
|
41
|
+
|
|
42
|
+
describe("IMAP system flag wire format (issue #64)", () => {
|
|
43
|
+
it("carries the RFC 9051 backslash prefix on every member", () => {
|
|
44
|
+
assert.deepEqual({ ...MessageSystemFlag }, { ...SYSTEM_FLAG_WIRE_FORMAT });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
for (const [name, wireValue] of Object.entries(SYSTEM_FLAG_WIRE_FORMAT)) {
|
|
48
|
+
it(`${name} is one backslash followed by the flag name`, () => {
|
|
49
|
+
assert.equal(wireValue.charCodeAt(0), 0x5c);
|
|
50
|
+
assert.equal(wireValue.slice(1), name);
|
|
51
|
+
assert.equal(wireValue.length, name.length + 1);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
it("leaves keyword flags unprefixed", () => {
|
|
56
|
+
for (const wireValue of Object.values(MessageKeywordFlag)) {
|
|
57
|
+
assert.equal(wireValue.startsWith("\\"), false);
|
|
58
|
+
assert.equal(wireValue.startsWith("$"), true);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("IMAP mailbox attribute wire format (issue #64)", () => {
|
|
64
|
+
it("carries the RFC 9051 backslash prefix on every member", () => {
|
|
65
|
+
assert.deepEqual(
|
|
66
|
+
{ ...MailboxAttribute },
|
|
67
|
+
{ ...MAILBOX_ATTRIBUTE_WIRE_FORMAT },
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("prefixes every value with exactly one backslash", () => {
|
|
72
|
+
for (const wireValue of Object.values(MailboxAttribute)) {
|
|
73
|
+
assert.equal(wireValue.charCodeAt(0), 0x5c);
|
|
74
|
+
assert.equal(wireValue.charCodeAt(1) === 0x5c, false);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|