@dxv-systems/helpdesk 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -2
- package/dist/bounce.d.ts +13 -0
- package/dist/bounce.js +79 -0
- package/dist/controls.d.ts +13 -0
- package/dist/controls.js +82 -0
- package/dist/draft-body.d.ts +4 -0
- package/dist/draft-body.js +38 -0
- package/dist/drafting.d.ts +18 -0
- package/dist/drafting.js +243 -0
- package/dist/errors.d.ts +60 -0
- package/dist/errors.js +133 -0
- package/dist/inbox/handlers.d.ts +36 -0
- package/dist/inbox/handlers.js +523 -0
- package/dist/inbox/messages.d.ts +34 -0
- package/dist/inbox/messages.js +66 -0
- package/dist/inbox/plain-text.d.ts +1 -0
- package/dist/inbox/plain-text.js +58 -0
- package/dist/inbox/types.d.ts +116 -0
- package/dist/inbox/types.js +2 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +66 -0
- package/dist/ingest.d.ts +25 -0
- package/dist/ingest.js +335 -0
- package/dist/internal.d.ts +8 -0
- package/dist/internal.js +44 -0
- package/dist/noise.d.ts +17 -0
- package/dist/noise.js +77 -0
- package/dist/react.d.ts +97 -0
- package/dist/react.js +576 -0
- package/dist/reply-attachments.d.ts +28 -0
- package/dist/reply-attachments.js +119 -0
- package/dist/sending.d.ts +34 -0
- package/dist/sending.js +268 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +10 -0
- package/dist/states.d.ts +13 -0
- package/dist/states.js +62 -0
- package/dist/subject.d.ts +2 -0
- package/dist/subject.js +30 -0
- package/dist/testing/index.d.ts +97 -0
- package/dist/testing/index.js +472 -0
- package/dist/threading.d.ts +18 -0
- package/dist/threading.js +66 -0
- package/dist/types.d.ts +339 -0
- package/dist/types.js +2 -0
- package/package.json +71 -4
package/dist/noise.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { InternetMessageHeader, NoiseReason } from "./types";
|
|
2
|
+
export interface NoiseInput {
|
|
3
|
+
from: string;
|
|
4
|
+
subject?: string;
|
|
5
|
+
headers?: InternetMessageHeader[] | Record<string, string | undefined>;
|
|
6
|
+
replyTo?: string[];
|
|
7
|
+
ownAddresses: string[];
|
|
8
|
+
connectedMailboxes: string[];
|
|
9
|
+
}
|
|
10
|
+
export type NoiseVerdict = {
|
|
11
|
+
action: "ignore" | "process";
|
|
12
|
+
reason: NoiseReason;
|
|
13
|
+
detail?: string;
|
|
14
|
+
customerAddress?: string;
|
|
15
|
+
suppressAutoResponse?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function classifyNoise(input: NoiseInput): NoiseVerdict;
|
package/dist/noise.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classifyNoise = classifyNoise;
|
|
4
|
+
const MACHINE_LOCAL = /^(?:no[-_.]?reply|do[-_.]?not[-_.]?reply|mailer-daemon|postmaster|bounces?)(?:[+._-].*)?$/i;
|
|
5
|
+
const EXCHANGE_SYSTEM_LOCAL = /^microsoftexchange[0-9a-f]{32}$/i;
|
|
6
|
+
const OOO_SUBJECT = /^\s*(?:automatic reply|automatisch antwoord|auto[- ]?reply|autoreply|out of office|afwezigheidsmelding|abwesenheitsnotiz)\b/i;
|
|
7
|
+
function headerMap(headers) {
|
|
8
|
+
const map = new Map();
|
|
9
|
+
if (!headers)
|
|
10
|
+
return map;
|
|
11
|
+
const entries = Array.isArray(headers)
|
|
12
|
+
? headers.map((h) => [h.name, h.value])
|
|
13
|
+
: Object.entries(headers);
|
|
14
|
+
for (const [name, value] of entries) {
|
|
15
|
+
if (value === undefined || value === null)
|
|
16
|
+
continue;
|
|
17
|
+
const key = name.trim().toLowerCase();
|
|
18
|
+
map.set(key, map.has(key) ? `${map.get(key)}, ${String(value)}` : String(value));
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
function keyword(value) {
|
|
23
|
+
return (value ?? "").split(";")[0]?.trim().toLowerCase() ?? "";
|
|
24
|
+
}
|
|
25
|
+
function realReplyTo(input, from) {
|
|
26
|
+
const own = [...input.ownAddresses, ...input.connectedMailboxes].map((a) => a.trim().toLowerCase());
|
|
27
|
+
for (const raw of input.replyTo ?? []) {
|
|
28
|
+
const a = raw.trim().toLowerCase();
|
|
29
|
+
const local = a.split("@")[0] ?? "";
|
|
30
|
+
if (a.includes("@") && a !== from && !own.includes(a) && !MACHINE_LOCAL.test(local))
|
|
31
|
+
return a;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function classifyNoise(input) {
|
|
36
|
+
const from = input.from.trim().toLowerCase();
|
|
37
|
+
const h = headerMap(input.headers);
|
|
38
|
+
const ignore = (reason, detail) => ({
|
|
39
|
+
action: "ignore",
|
|
40
|
+
reason,
|
|
41
|
+
...(detail ? { detail } : {}),
|
|
42
|
+
});
|
|
43
|
+
if (input.ownAddresses.some((a) => a.trim().toLowerCase() === from))
|
|
44
|
+
return ignore("own_address");
|
|
45
|
+
if (input.connectedMailboxes.some((a) => a.trim().toLowerCase() === from)) {
|
|
46
|
+
return ignore("connected_mailbox");
|
|
47
|
+
}
|
|
48
|
+
const local = from.split("@")[0] ?? "";
|
|
49
|
+
const contentType = (h.get("content-type") ?? "").toLowerCase();
|
|
50
|
+
const isNdrReport = contentType.includes("report-type=delivery-status") || contentType.includes("delivery-status");
|
|
51
|
+
if (isNdrReport || h.has("x-ms-exchange-message-is-ndr"))
|
|
52
|
+
return ignore("bounce", "ndr");
|
|
53
|
+
if (/^(?:mailer-daemon|postmaster)$/i.test(local))
|
|
54
|
+
return ignore("bounce", local);
|
|
55
|
+
if (EXCHANGE_SYSTEM_LOCAL.test(local))
|
|
56
|
+
return ignore("bounce", "exchange");
|
|
57
|
+
const auto = keyword(h.get("auto-submitted"));
|
|
58
|
+
if (auto && auto !== "no")
|
|
59
|
+
return ignore("auto_submitted", auto);
|
|
60
|
+
const precedence = keyword(h.get("precedence"));
|
|
61
|
+
if (["bulk", "junk", "list", "auto_reply"].includes(precedence))
|
|
62
|
+
return ignore("precedence", precedence);
|
|
63
|
+
if (h.has("x-autoreply") || h.has("x-autorespond") || OOO_SUBJECT.test(input.subject ?? "")) {
|
|
64
|
+
return ignore("out_of_office");
|
|
65
|
+
}
|
|
66
|
+
if (h.has("list-id") || h.has("list-unsubscribe"))
|
|
67
|
+
return ignore("mailing_list");
|
|
68
|
+
const suppressAutoResponse = (h.get("x-auto-response-suppress") ?? "").trim() !== "";
|
|
69
|
+
const flags = suppressAutoResponse ? { suppressAutoResponse } : {};
|
|
70
|
+
if (MACHINE_LOCAL.test(local)) {
|
|
71
|
+
const customer = realReplyTo(input, from);
|
|
72
|
+
if (customer)
|
|
73
|
+
return { action: "process", reason: "none", customerAddress: customer, ...flags };
|
|
74
|
+
return ignore("machine_sender", local);
|
|
75
|
+
}
|
|
76
|
+
return { action: "process", reason: "none", ...flags };
|
|
77
|
+
}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { InboxThreadDetail } from "./inbox/types";
|
|
3
|
+
export type { InboxActionResult, InboxThreadDetail, InboxThreadList, InboxThreadSummary, } from "./inbox/types";
|
|
4
|
+
export interface HelpdeskInboxClassNames {
|
|
5
|
+
root: string;
|
|
6
|
+
layout: string;
|
|
7
|
+
listPane: string;
|
|
8
|
+
detailPane: string;
|
|
9
|
+
hiddenOnMobile: string;
|
|
10
|
+
title: string;
|
|
11
|
+
filters: string;
|
|
12
|
+
field: string;
|
|
13
|
+
fieldWide: string;
|
|
14
|
+
label: string;
|
|
15
|
+
selectWrap: string;
|
|
16
|
+
select: string;
|
|
17
|
+
selectIcon: string;
|
|
18
|
+
list: string;
|
|
19
|
+
listItem: string;
|
|
20
|
+
listItemCurrent: string;
|
|
21
|
+
listItemTop: string;
|
|
22
|
+
listItemTitle: string;
|
|
23
|
+
listItemTime: string;
|
|
24
|
+
listItemMeta: string;
|
|
25
|
+
card: string;
|
|
26
|
+
header: string;
|
|
27
|
+
headerTop: string;
|
|
28
|
+
headerActions: string;
|
|
29
|
+
heading: string;
|
|
30
|
+
subheading: string;
|
|
31
|
+
text: string;
|
|
32
|
+
muted: string;
|
|
33
|
+
meta: string;
|
|
34
|
+
badge: string;
|
|
35
|
+
badgeAttention: string;
|
|
36
|
+
badgeDone: string;
|
|
37
|
+
badgeError: string;
|
|
38
|
+
reasonNote: string;
|
|
39
|
+
toolButton: string;
|
|
40
|
+
assignedChip: string;
|
|
41
|
+
iconButton: string;
|
|
42
|
+
menu: string;
|
|
43
|
+
menuItem: string;
|
|
44
|
+
backLink: string;
|
|
45
|
+
conversation: string;
|
|
46
|
+
entry: string;
|
|
47
|
+
entryOurs: string;
|
|
48
|
+
avatar: string;
|
|
49
|
+
avatarOurs: string;
|
|
50
|
+
avatarEvent: string;
|
|
51
|
+
message: string;
|
|
52
|
+
messageOurs: string;
|
|
53
|
+
messageEvent: string;
|
|
54
|
+
messageHeader: string;
|
|
55
|
+
messageBody: string;
|
|
56
|
+
emptyBody: string;
|
|
57
|
+
eventTitle: string;
|
|
58
|
+
details: string;
|
|
59
|
+
detailsPre: string;
|
|
60
|
+
fileChips: string;
|
|
61
|
+
fileChip: string;
|
|
62
|
+
fileChipName: string;
|
|
63
|
+
fileChipMeta: string;
|
|
64
|
+
sentNote: string;
|
|
65
|
+
composer: string;
|
|
66
|
+
composerHeader: string;
|
|
67
|
+
aiChip: string;
|
|
68
|
+
composerFooter: string;
|
|
69
|
+
replyChip: string;
|
|
70
|
+
chipRemove: string;
|
|
71
|
+
dashedButton: string;
|
|
72
|
+
srOnly: string;
|
|
73
|
+
icon: string;
|
|
74
|
+
textarea: string;
|
|
75
|
+
actions: string;
|
|
76
|
+
primaryButton: string;
|
|
77
|
+
secondaryButton: string;
|
|
78
|
+
dangerButton: string;
|
|
79
|
+
linkButton: string;
|
|
80
|
+
banner: string;
|
|
81
|
+
success: string;
|
|
82
|
+
warning: string;
|
|
83
|
+
error: string;
|
|
84
|
+
info: string;
|
|
85
|
+
context: string;
|
|
86
|
+
}
|
|
87
|
+
export declare const DEFAULT_HELPDESK_INBOX_CLASSNAMES: HelpdeskInboxClassNames;
|
|
88
|
+
export interface HelpdeskInboxProps {
|
|
89
|
+
apiBasePath?: string;
|
|
90
|
+
classNames?: Partial<HelpdeskInboxClassNames>;
|
|
91
|
+
pollIntervalMs?: number;
|
|
92
|
+
fetch?: typeof fetch;
|
|
93
|
+
renderCustomerContext?: (thread: InboxThreadDetail["thread"]) => ReactNode;
|
|
94
|
+
initialThreadId?: string;
|
|
95
|
+
onThreadChange?: (threadId: string | null) => void;
|
|
96
|
+
}
|
|
97
|
+
export declare function HelpdeskInbox({ apiBasePath, classNames, pollIntervalMs, fetch: fetchImpl, renderCustomerContext, initialThreadId, onThreadChange, }: HelpdeskInboxProps): import("react").JSX.Element;
|