@dxv-systems/helpdesk 0.1.0 → 0.3.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 +299 -279
- package/dist/bounce.d.ts +6 -0
- package/dist/bounce.js +38 -0
- package/dist/controls.js +1 -6
- package/dist/draft-body.d.ts +0 -1
- package/dist/draft-body.js +0 -14
- package/dist/drafting.d.ts +1 -2
- package/dist/drafting.js +12 -80
- package/dist/errors.d.ts +0 -3
- package/dist/errors.js +1 -7
- package/dist/inbox/handlers.js +27 -36
- package/dist/inbox/messages.d.ts +4 -5
- package/dist/inbox/messages.js +23 -14
- package/dist/inbox/types.d.ts +12 -2
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -6
- package/dist/ingest.d.ts +4 -0
- package/dist/ingest.js +144 -22
- package/dist/react.d.ts +42 -2
- package/dist/react.js +249 -94
- package/dist/sending.d.ts +2 -1
- package/dist/sending.js +35 -58
- package/dist/states.d.ts +1 -1
- package/dist/states.js +1 -2
- package/dist/testing/index.d.ts +4 -2
- package/dist/testing/index.js +19 -29
- package/dist/types.d.ts +6 -8
- package/package.json +73 -73
- package/dist/autosend.d.ts +0 -43
- package/dist/autosend.js +0 -83
- package/dist/cleanup.d.ts +0 -7
- package/dist/cleanup.js +0 -39
package/dist/index.d.ts
CHANGED
|
@@ -5,9 +5,8 @@ export { DEFAULT_WRITE_MODE, isPaused, writeModeFor } from "./controls";
|
|
|
5
5
|
export { normalizeSubject, isForwardSubject } from "./subject";
|
|
6
6
|
export { classifyNoise, type NoiseInput, type NoiseVerdict } from "./noise";
|
|
7
7
|
export { matchThread, normalizeMessageId, type ThreadCandidate, type ThreadMatch } from "./threading";
|
|
8
|
-
export { connectMailbox, ingestPage, isSyncFailing, syncMailbox, SYNC_FAILING_AFTER, type IngestResult, } from "./ingest";
|
|
9
|
-
export { ensureDraft, completeDraft, regenerateDraft, editDraft,
|
|
10
|
-
export { renderCommentHtml,
|
|
8
|
+
export { connectMailbox, ingestPage, ingestSentPage, isSyncFailing, syncMailbox, SYNC_FAILING_AFTER, type IngestResult, type SyncFolder, } from "./ingest";
|
|
9
|
+
export { ensureDraft, completeDraft, regenerateDraft, editDraft, sweepStuckDrafts, unignoreThread, type EnsureDraftOutcome, } from "./drafting";
|
|
10
|
+
export { renderCommentHtml, prependToDraftBody, hasQuotedHistory, findQuoteStart, } from "./draft-body";
|
|
11
11
|
export { approveAndSend, reconcileUnknownSends, resolveUnknownSend, markRepliedExternally, markWaiting, closeThread, dismissThread, classifySendError, type SendOutcome, } from "./sending";
|
|
12
12
|
export { MAX_REPLY_ATTACHMENT_BYTES, MAX_REPLY_ATTACHMENTS, addReplyAttachment, pendingReplyAttachments, removeReplyAttachment, startReplyUpload, } from "./reply-attachments";
|
|
13
|
-
export { evaluateAutoSend, DEFAULT_AUTO_SEND_POLICY, type AutoSendPolicy, type AutoSendContext, type AutoSendDecision, type OfficeHours, } from "./autosend";
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
17
|
+
exports.startReplyUpload = exports.removeReplyAttachment = exports.pendingReplyAttachments = exports.addReplyAttachment = exports.MAX_REPLY_ATTACHMENTS = exports.MAX_REPLY_ATTACHMENT_BYTES = exports.classifySendError = exports.dismissThread = exports.closeThread = exports.markWaiting = exports.markRepliedExternally = exports.resolveUnknownSend = exports.reconcileUnknownSends = exports.approveAndSend = exports.findQuoteStart = exports.hasQuotedHistory = exports.prependToDraftBody = exports.renderCommentHtml = exports.unignoreThread = exports.sweepStuckDrafts = exports.editDraft = exports.regenerateDraft = exports.completeDraft = exports.ensureDraft = exports.SYNC_FAILING_AFTER = exports.syncMailbox = exports.isSyncFailing = exports.ingestSentPage = exports.ingestPage = exports.connectMailbox = exports.normalizeMessageId = exports.matchThread = exports.classifyNoise = exports.isForwardSubject = exports.normalizeSubject = exports.writeModeFor = exports.isPaused = exports.DEFAULT_WRITE_MODE = void 0;
|
|
18
18
|
__exportStar(require("./types"), exports);
|
|
19
19
|
__exportStar(require("./errors"), exports);
|
|
20
20
|
__exportStar(require("./states"), exports);
|
|
@@ -33,6 +33,7 @@ Object.defineProperty(exports, "normalizeMessageId", { enumerable: true, get: fu
|
|
|
33
33
|
var ingest_1 = require("./ingest");
|
|
34
34
|
Object.defineProperty(exports, "connectMailbox", { enumerable: true, get: function () { return ingest_1.connectMailbox; } });
|
|
35
35
|
Object.defineProperty(exports, "ingestPage", { enumerable: true, get: function () { return ingest_1.ingestPage; } });
|
|
36
|
+
Object.defineProperty(exports, "ingestSentPage", { enumerable: true, get: function () { return ingest_1.ingestSentPage; } });
|
|
36
37
|
Object.defineProperty(exports, "isSyncFailing", { enumerable: true, get: function () { return ingest_1.isSyncFailing; } });
|
|
37
38
|
Object.defineProperty(exports, "syncMailbox", { enumerable: true, get: function () { return ingest_1.syncMailbox; } });
|
|
38
39
|
Object.defineProperty(exports, "SYNC_FAILING_AFTER", { enumerable: true, get: function () { return ingest_1.SYNC_FAILING_AFTER; } });
|
|
@@ -41,12 +42,10 @@ Object.defineProperty(exports, "ensureDraft", { enumerable: true, get: function
|
|
|
41
42
|
Object.defineProperty(exports, "completeDraft", { enumerable: true, get: function () { return drafting_1.completeDraft; } });
|
|
42
43
|
Object.defineProperty(exports, "regenerateDraft", { enumerable: true, get: function () { return drafting_1.regenerateDraft; } });
|
|
43
44
|
Object.defineProperty(exports, "editDraft", { enumerable: true, get: function () { return drafting_1.editDraft; } });
|
|
44
|
-
Object.defineProperty(exports, "retryPlacement", { enumerable: true, get: function () { return drafting_1.retryPlacement; } });
|
|
45
45
|
Object.defineProperty(exports, "sweepStuckDrafts", { enumerable: true, get: function () { return drafting_1.sweepStuckDrafts; } });
|
|
46
46
|
Object.defineProperty(exports, "unignoreThread", { enumerable: true, get: function () { return drafting_1.unignoreThread; } });
|
|
47
47
|
var draft_body_1 = require("./draft-body");
|
|
48
48
|
Object.defineProperty(exports, "renderCommentHtml", { enumerable: true, get: function () { return draft_body_1.renderCommentHtml; } });
|
|
49
|
-
Object.defineProperty(exports, "replaceDraftComment", { enumerable: true, get: function () { return draft_body_1.replaceDraftComment; } });
|
|
50
49
|
Object.defineProperty(exports, "prependToDraftBody", { enumerable: true, get: function () { return draft_body_1.prependToDraftBody; } });
|
|
51
50
|
Object.defineProperty(exports, "hasQuotedHistory", { enumerable: true, get: function () { return draft_body_1.hasQuotedHistory; } });
|
|
52
51
|
Object.defineProperty(exports, "findQuoteStart", { enumerable: true, get: function () { return draft_body_1.findQuoteStart; } });
|
|
@@ -66,6 +65,3 @@ Object.defineProperty(exports, "addReplyAttachment", { enumerable: true, get: fu
|
|
|
66
65
|
Object.defineProperty(exports, "pendingReplyAttachments", { enumerable: true, get: function () { return reply_attachments_1.pendingReplyAttachments; } });
|
|
67
66
|
Object.defineProperty(exports, "removeReplyAttachment", { enumerable: true, get: function () { return reply_attachments_1.removeReplyAttachment; } });
|
|
68
67
|
Object.defineProperty(exports, "startReplyUpload", { enumerable: true, get: function () { return reply_attachments_1.startReplyUpload; } });
|
|
69
|
-
var autosend_1 = require("./autosend");
|
|
70
|
-
Object.defineProperty(exports, "evaluateAutoSend", { enumerable: true, get: function () { return autosend_1.evaluateAutoSend; } });
|
|
71
|
-
Object.defineProperty(exports, "DEFAULT_AUTO_SEND_POLICY", { enumerable: true, get: function () { return autosend_1.DEFAULT_AUTO_SEND_POLICY; } });
|
package/dist/ingest.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { HelpdeskDeps, Paused, SyncFailing, SyncState } from "./types";
|
|
2
|
+
export type SyncFolder = "inbox" | "sentitems";
|
|
2
3
|
export interface IngestResult {
|
|
4
|
+
folder: SyncFolder;
|
|
3
5
|
fetched: number;
|
|
4
6
|
created: number;
|
|
5
7
|
appended: number;
|
|
@@ -13,11 +15,13 @@ export interface IngestResult {
|
|
|
13
15
|
gone: number;
|
|
14
16
|
draftsStarted: number;
|
|
15
17
|
deliveryFailures: number;
|
|
18
|
+
unmatched: number;
|
|
16
19
|
restarted: boolean;
|
|
17
20
|
hasMore: boolean;
|
|
18
21
|
}
|
|
19
22
|
export declare function connectMailbox(deps: HelpdeskDeps, mailbox: string): Promise<SyncState>;
|
|
20
23
|
export declare function ingestPage(deps: HelpdeskDeps, mailbox: string): Promise<IngestResult | Paused>;
|
|
24
|
+
export declare function ingestSentPage(deps: HelpdeskDeps, mailbox: string): Promise<IngestResult | Paused>;
|
|
21
25
|
export declare function syncMailbox(deps: HelpdeskDeps, mailbox: string, options?: {
|
|
22
26
|
maxPages?: number;
|
|
23
27
|
}): Promise<IngestResult[] | Paused | SyncFailing>;
|
package/dist/ingest.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SYNC_FAILING_AFTER = void 0;
|
|
4
4
|
exports.connectMailbox = connectMailbox;
|
|
5
5
|
exports.ingestPage = ingestPage;
|
|
6
|
+
exports.ingestSentPage = ingestSentPage;
|
|
6
7
|
exports.syncMailbox = syncMailbox;
|
|
7
8
|
exports.isSyncFailing = isSyncFailing;
|
|
8
9
|
const controls_1 = require("./controls");
|
|
@@ -34,32 +35,44 @@ function threadingHeaders(msg) {
|
|
|
34
35
|
const references = msg.references ?? (raw ? (raw.match(/<[^>]+>/g) ?? []) : []);
|
|
35
36
|
return { inReplyTo, references };
|
|
36
37
|
}
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return new Date(Math.max(Date.parse(state.connectedAt), back)).toISOString();
|
|
38
|
+
function cursorOf(state, folder) {
|
|
39
|
+
return folder === "inbox"
|
|
40
|
+
? { link: state.link, lastReceivedAt: state.lastReceivedAt }
|
|
41
|
+
: { link: state.sentLink ?? null, lastReceivedAt: state.sentLastReceivedAt ?? null };
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
function withCursor(state, folder, cursor) {
|
|
44
|
+
return folder === "inbox"
|
|
45
|
+
? { ...state, link: cursor.link, lastReceivedAt: cursor.lastReceivedAt }
|
|
46
|
+
: { ...state, sentLink: cursor.link, sentLastReceivedAt: cursor.lastReceivedAt };
|
|
47
|
+
}
|
|
48
|
+
function restartFrom(connectedAt, lastReceivedAt, overlapMs) {
|
|
49
|
+
if (!lastReceivedAt)
|
|
50
|
+
return connectedAt;
|
|
51
|
+
const back = Date.parse(lastReceivedAt) - overlapMs;
|
|
52
|
+
return new Date(Math.max(Date.parse(connectedAt), back)).toISOString();
|
|
53
|
+
}
|
|
54
|
+
async function fetchPage(deps, gateway, state, folder) {
|
|
44
55
|
const pageSize = deps.config.pageSize;
|
|
45
|
-
const
|
|
46
|
-
|
|
56
|
+
const cursor = cursorOf(state, folder);
|
|
57
|
+
const first = (link) => gateway.delta(link
|
|
58
|
+
? { link, ...(pageSize ? { pageSize } : {}) }
|
|
47
59
|
: {
|
|
48
|
-
folderId:
|
|
49
|
-
since: restartFrom(
|
|
60
|
+
folderId: folder,
|
|
61
|
+
since: restartFrom(state.connectedAt, cursor.lastReceivedAt, deps.config.restartOverlapMs ?? DEFAULT_RESTART_OVERLAP_MS),
|
|
50
62
|
...(pageSize ? { pageSize } : {}),
|
|
51
63
|
});
|
|
52
64
|
try {
|
|
53
|
-
return { page: await first(
|
|
65
|
+
return { page: await first(cursor.link), restarted: false };
|
|
54
66
|
}
|
|
55
67
|
catch (err) {
|
|
56
|
-
if (!
|
|
68
|
+
if (!cursor.link || !(0, errors_1.isDeltaLinkExpired)(err))
|
|
57
69
|
throw err;
|
|
58
|
-
return { page: await first(
|
|
70
|
+
return { page: await first(null), restarted: true };
|
|
59
71
|
}
|
|
60
72
|
}
|
|
61
|
-
function emptyResult() {
|
|
73
|
+
function emptyResult(folder) {
|
|
62
74
|
return {
|
|
75
|
+
folder,
|
|
63
76
|
fetched: 0,
|
|
64
77
|
created: 0,
|
|
65
78
|
appended: 0,
|
|
@@ -73,12 +86,13 @@ function emptyResult() {
|
|
|
73
86
|
gone: 0,
|
|
74
87
|
draftsStarted: 0,
|
|
75
88
|
deliveryFailures: 0,
|
|
89
|
+
unmatched: 0,
|
|
76
90
|
restarted: false,
|
|
77
91
|
hasMore: false,
|
|
78
92
|
};
|
|
79
93
|
}
|
|
80
94
|
async function reconcileExisting(deps, existing, result) {
|
|
81
|
-
if (existing.removedAt)
|
|
95
|
+
if (existing.removedAt || existing.direction === "outbound")
|
|
82
96
|
return;
|
|
83
97
|
const thread = await deps.store.getThread(existing.threadId);
|
|
84
98
|
if (thread && (thread.state === "new" || thread.state === "drafted")) {
|
|
@@ -126,6 +140,7 @@ async function processNew(deps, gateway, mailbox, item, state, result) {
|
|
|
126
140
|
noise: { action: noise.action, reason: noise.reason },
|
|
127
141
|
suppressAutoResponse: noise.suppressAutoResponse === true,
|
|
128
142
|
removedAt: null,
|
|
143
|
+
direction: "inbound",
|
|
129
144
|
};
|
|
130
145
|
if (noise.reason === "bounce") {
|
|
131
146
|
const refs = [...new Set([...(0, bounce_1.bouncedReplyRefs)(msg.body?.content ?? ""), ...headerRefs(headers)])];
|
|
@@ -260,7 +275,7 @@ async function processItem(deps, gateway, mailbox, item, state, result) {
|
|
|
260
275
|
}
|
|
261
276
|
await processNew(deps, gateway, mailbox, item, state, result);
|
|
262
277
|
}
|
|
263
|
-
async function
|
|
278
|
+
async function ingestFolderPage(deps, mailbox, folder, process) {
|
|
264
279
|
const controls = await (0, controls_1.loadControls)(deps);
|
|
265
280
|
if (controls.paused)
|
|
266
281
|
return (0, controls_1.paused)();
|
|
@@ -268,35 +283,142 @@ async function ingestPage(deps, mailbox) {
|
|
|
268
283
|
const state = await deps.store.getSyncState(mailbox);
|
|
269
284
|
if (!state)
|
|
270
285
|
throw new errors_1.MailboxNotConnectedError(mailbox);
|
|
271
|
-
const { page, restarted } = await fetchPage(deps, gateway, state);
|
|
286
|
+
const { page, restarted } = await fetchPage(deps, gateway, state, folder);
|
|
272
287
|
const link = page.nextLink ?? page.deltaLink;
|
|
273
288
|
if (!link)
|
|
274
289
|
throw new errors_1.InvalidDeltaPageError();
|
|
275
|
-
const result = emptyResult();
|
|
290
|
+
const result = emptyResult(folder);
|
|
276
291
|
result.restarted = restarted;
|
|
277
292
|
result.fetched = page.items.length;
|
|
278
293
|
const stamp = (i) => i.receivedDateTime ?? "";
|
|
279
294
|
const live = page.items.filter((i) => !i.removed).sort((a, b) => stamp(a).localeCompare(stamp(b)));
|
|
280
295
|
const gone = page.items.filter((i) => i.removed);
|
|
281
|
-
let newest = state.lastReceivedAt;
|
|
296
|
+
let newest = cursorOf(state, folder).lastReceivedAt;
|
|
282
297
|
for (const item of [...live, ...gone]) {
|
|
283
|
-
await
|
|
298
|
+
await process(deps, gateway, mailbox, item, state, result);
|
|
284
299
|
if (item.receivedDateTime && (!newest || item.receivedDateTime > newest)) {
|
|
285
300
|
newest = item.receivedDateTime;
|
|
286
301
|
}
|
|
287
302
|
}
|
|
288
|
-
await deps.store.saveSyncState(mailbox,
|
|
303
|
+
await deps.store.saveSyncState(mailbox, withCursor(state, folder, { link, lastReceivedAt: newest }));
|
|
289
304
|
result.hasMore = page.nextLink !== null;
|
|
290
305
|
return result;
|
|
291
306
|
}
|
|
307
|
+
async function ingestPage(deps, mailbox) {
|
|
308
|
+
return ingestFolderPage(deps, mailbox, "inbox", processItem);
|
|
309
|
+
}
|
|
310
|
+
async function ingestSentPage(deps, mailbox) {
|
|
311
|
+
return ingestFolderPage(deps, mailbox, "sentitems", processSentItem);
|
|
312
|
+
}
|
|
313
|
+
async function processSentItem(deps, gateway, mailbox, item, state, result) {
|
|
314
|
+
if (item.removed) {
|
|
315
|
+
const stored = await deps.store.getMessage(mailbox, item.id);
|
|
316
|
+
if (stored)
|
|
317
|
+
await deps.store.markMessageRemoved(mailbox, item.id, (0, internal_1.nowIso)(deps));
|
|
318
|
+
result.removed++;
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (item.isDraft) {
|
|
322
|
+
result.skippedDrafts++;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (await deps.store.getMessage(mailbox, item.id)) {
|
|
326
|
+
result.unchanged++;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (item.receivedDateTime && Date.parse(item.receivedDateTime) < Date.parse(state.connectedAt)) {
|
|
330
|
+
result.skippedPredates++;
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const msg = await gateway.getMessage(item.id, { includeHeaders: true, bodyType: "text" });
|
|
334
|
+
if (!msg) {
|
|
335
|
+
result.gone++;
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (msg.isDraft === true) {
|
|
339
|
+
result.skippedDrafts++;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const conversationId = msg.conversationId ?? item.conversationId ?? null;
|
|
343
|
+
const recipients = [...msg.toRecipients, ...msg.ccRecipients]
|
|
344
|
+
.map((a) => a.address.trim().toLowerCase())
|
|
345
|
+
.filter(Boolean);
|
|
346
|
+
const message = {
|
|
347
|
+
id: item.id,
|
|
348
|
+
mailbox,
|
|
349
|
+
internetMessageId: (0, threading_1.normalizeMessageId)(msg.internetMessageId ?? item.internetMessageId),
|
|
350
|
+
conversationId,
|
|
351
|
+
subject: msg.subject ?? item.subject ?? "",
|
|
352
|
+
fromAddress: mailbox.trim().toLowerCase(),
|
|
353
|
+
receivedAt: msg.sentDateTime ?? msg.receivedDateTime ?? item.receivedDateTime ?? (0, internal_1.nowIso)(deps),
|
|
354
|
+
noise: { action: "process", reason: "none" },
|
|
355
|
+
suppressAutoResponse: false,
|
|
356
|
+
removedAt: null,
|
|
357
|
+
direction: "outbound",
|
|
358
|
+
};
|
|
359
|
+
const headers = threadingHeaders(msg);
|
|
360
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
361
|
+
const thread = await matchSent(deps, { mailbox, headers, conversationId, recipients });
|
|
362
|
+
if (!thread) {
|
|
363
|
+
result.unmatched++;
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const outcome = await deps.store.appendMessage({ ...message, threadId: thread.id }, { threadId: thread.id, expectedState: thread.state, patch: {} });
|
|
367
|
+
if (outcome === "stale")
|
|
368
|
+
continue;
|
|
369
|
+
if (outcome === "duplicate")
|
|
370
|
+
result.duplicates++;
|
|
371
|
+
else
|
|
372
|
+
result.appended++;
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
throw new errors_1.StaleThreadError(item.id);
|
|
376
|
+
}
|
|
377
|
+
async function matchSent(deps, input) {
|
|
378
|
+
const { mailbox, headers, conversationId, recipients } = input;
|
|
379
|
+
const refs = [...new Set(headerRefs(headers))];
|
|
380
|
+
const hits = refs.length ? await deps.store.findMessageThreads(mailbox, refs) : [];
|
|
381
|
+
const parent = (0, threading_1.normalizeMessageId)(headers.inReplyTo);
|
|
382
|
+
const direct = parent ? hits.find((h) => h.internetMessageId === parent) : undefined;
|
|
383
|
+
const headerIds = new Set(direct ? [direct.threadId] : hits.map((h) => h.threadId));
|
|
384
|
+
const candidates = new Map();
|
|
385
|
+
for (const id of headerIds) {
|
|
386
|
+
const t = await deps.store.getThread(id);
|
|
387
|
+
if (t && t.mailbox === mailbox)
|
|
388
|
+
candidates.set(t.id, t);
|
|
389
|
+
}
|
|
390
|
+
if (!direct && conversationId) {
|
|
391
|
+
for (const t of await deps.store.findThreadsByConversationId(mailbox, conversationId)) {
|
|
392
|
+
if (t.mailbox !== mailbox)
|
|
393
|
+
continue;
|
|
394
|
+
if (headerIds.has(t.id) || recipients.some((r) => t.participants.includes(r)))
|
|
395
|
+
candidates.set(t.id, t);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (candidates.size !== 1)
|
|
399
|
+
return null;
|
|
400
|
+
return [...candidates.values()][0] ?? null;
|
|
401
|
+
}
|
|
292
402
|
async function syncMailbox(deps, mailbox, options = {}) {
|
|
293
403
|
const results = [];
|
|
404
|
+
const maxPages = options.maxPages ?? 20;
|
|
294
405
|
try {
|
|
295
|
-
|
|
406
|
+
let inboxDone = false;
|
|
407
|
+
for (let i = 0; i < maxPages; i++) {
|
|
296
408
|
const r = await ingestPage(deps, mailbox);
|
|
297
409
|
if ((0, controls_1.isPaused)(r))
|
|
298
410
|
return results.length ? results : r;
|
|
299
411
|
results.push(r);
|
|
412
|
+
if (!r.hasMore) {
|
|
413
|
+
inboxDone = true;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
for (let i = 0; inboxDone && i < maxPages; i++) {
|
|
418
|
+
const r = await ingestSentPage(deps, mailbox);
|
|
419
|
+
if ((0, controls_1.isPaused)(r))
|
|
420
|
+
return results;
|
|
421
|
+
results.push(r);
|
|
300
422
|
if (!r.hasMore)
|
|
301
423
|
break;
|
|
302
424
|
}
|
package/dist/react.d.ts
CHANGED
|
@@ -10,27 +10,67 @@ export interface HelpdeskInboxClassNames {
|
|
|
10
10
|
title: string;
|
|
11
11
|
filters: string;
|
|
12
12
|
field: string;
|
|
13
|
+
fieldWide: string;
|
|
13
14
|
label: string;
|
|
15
|
+
selectWrap: string;
|
|
14
16
|
select: string;
|
|
17
|
+
selectIcon: string;
|
|
15
18
|
list: string;
|
|
16
19
|
listItem: string;
|
|
17
20
|
listItemCurrent: string;
|
|
21
|
+
listItemTop: string;
|
|
18
22
|
listItemTitle: string;
|
|
23
|
+
listItemTime: string;
|
|
19
24
|
listItemMeta: string;
|
|
20
25
|
card: string;
|
|
26
|
+
header: string;
|
|
27
|
+
headerTop: string;
|
|
28
|
+
headerActions: string;
|
|
21
29
|
heading: string;
|
|
22
30
|
subheading: string;
|
|
23
31
|
text: string;
|
|
24
32
|
muted: string;
|
|
25
33
|
meta: string;
|
|
26
|
-
badges: string;
|
|
27
34
|
badge: string;
|
|
28
35
|
badgeAttention: string;
|
|
29
36
|
badgeDone: string;
|
|
30
|
-
|
|
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;
|
|
31
51
|
message: string;
|
|
52
|
+
messageOurs: string;
|
|
53
|
+
messageEvent: string;
|
|
32
54
|
messageHeader: string;
|
|
33
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;
|
|
34
74
|
textarea: string;
|
|
35
75
|
actions: string;
|
|
36
76
|
primaryButton: string;
|