@push.rocks/smartjmap 1.0.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.
@@ -0,0 +1,650 @@
1
+ import * as plugins from './smartjmap.plugins.js';
2
+ export const JMAP_CORE_CAPABILITY = 'urn:ietf:params:jmap:core';
3
+ export const JMAP_MAIL_CAPABILITY = 'urn:ietf:params:jmap:mail';
4
+ export const JMAP_SUBMISSION_CAPABILITY = 'urn:ietf:params:jmap:submission';
5
+ /** Error thrown for HTTP-level (RFC 7807 problem details) and JMAP method-level errors. */
6
+ export class JmapError extends Error {
7
+ constructor(message, fields = {}) {
8
+ super(message);
9
+ this.name = 'JmapError';
10
+ Object.assign(this, fields);
11
+ }
12
+ }
13
+ const EMAIL_PROPERTIES = [
14
+ 'id',
15
+ 'blobId',
16
+ 'threadId',
17
+ 'mailboxIds',
18
+ 'keywords',
19
+ 'size',
20
+ 'receivedAt',
21
+ 'sentAt',
22
+ 'subject',
23
+ 'from',
24
+ 'to',
25
+ 'cc',
26
+ 'bcc',
27
+ 'replyTo',
28
+ 'hasAttachment',
29
+ 'preview',
30
+ 'bodyValues',
31
+ 'textBody',
32
+ 'htmlBody',
33
+ 'attachments',
34
+ ];
35
+ export class JmapClient extends plugins.events.EventEmitter {
36
+ constructor(config) {
37
+ super();
38
+ this.session = null;
39
+ this.accountId = '';
40
+ this.apiUrl = '';
41
+ this.mailbox = null;
42
+ this.connected = false;
43
+ this.stopped = false;
44
+ this.lastEmailState = null;
45
+ this.seenEmailIds = new Set();
46
+ this.pollTimer = null;
47
+ this.sseAbortController = null;
48
+ this.fetchingDeltas = false;
49
+ this.deltaQueued = false;
50
+ const auth = config.auth;
51
+ const hasBearer = typeof auth.accessToken === 'string';
52
+ const hasBasic = typeof auth.user === 'string' && typeof auth.pass === 'string';
53
+ if (!hasBearer && !hasBasic) {
54
+ throw new Error('JmapClient requires auth as either { accessToken } (Bearer) or { user, pass } (Basic).');
55
+ }
56
+ if (hasBearer && (typeof auth.user === 'string' || typeof auth.pass === 'string')) {
57
+ throw new Error('JmapClient auth accepts either { accessToken } or { user, pass }, not both.');
58
+ }
59
+ if (typeof config.sessionUrl !== 'string' || !config.sessionUrl) {
60
+ throw new Error('JmapClient requires a sessionUrl, e.g. https://host/.well-known/jmap');
61
+ }
62
+ this.config = config;
63
+ }
64
+ /**
65
+ * Fetches and validates the JMAP session, resolves the target mailbox,
66
+ * emits 'connected', emits 'message' for every email currently in the
67
+ * mailbox, then watches for new mail via the JMAP event source (SSE),
68
+ * falling back to polling when the event stream is unavailable.
69
+ * Failures are emitted as 'error' events; connect() does not throw.
70
+ */
71
+ async connect() {
72
+ // Reconnecting on the same instance is supported; release any watchers
73
+ // from a previous connect() so no SSE stream or poll timer is stranded.
74
+ this.teardownWatchers();
75
+ this.stopped = false;
76
+ try {
77
+ const response = await fetch(this.config.sessionUrl, {
78
+ headers: {
79
+ authorization: this.getAuthHeader(),
80
+ accept: 'application/json',
81
+ },
82
+ });
83
+ if (!response.ok) {
84
+ throw await this.createHttpError(response, 'Failed to fetch JMAP session');
85
+ }
86
+ const session = (await response.json());
87
+ if (!session.capabilities || !(JMAP_CORE_CAPABILITY in session.capabilities)) {
88
+ throw new Error(`JMAP session is missing the ${JMAP_CORE_CAPABILITY} capability.`);
89
+ }
90
+ if (!(JMAP_MAIL_CAPABILITY in session.capabilities)) {
91
+ throw new Error(`JMAP session is missing the ${JMAP_MAIL_CAPABILITY} capability.`);
92
+ }
93
+ const accountId = session.primaryAccounts?.[JMAP_MAIL_CAPABILITY] ??
94
+ session.primaryAccounts?.[JMAP_CORE_CAPABILITY];
95
+ if (!accountId) {
96
+ throw new Error('JMAP session has no primary account for urn:ietf:params:jmap:mail.');
97
+ }
98
+ this.session = session;
99
+ this.accountId = accountId;
100
+ this.apiUrl = new URL(session.apiUrl, this.config.sessionUrl).toString();
101
+ this.mailbox = await this.resolveMailbox();
102
+ // Capture the Email state before the initial sweep so no change is lost
103
+ // between the sweep and the start of watching (dedupe handles overlap).
104
+ this.lastEmailState = await this.fetchEmailState();
105
+ if (this.stopped) {
106
+ // disconnect() was called while connect() was in flight.
107
+ return;
108
+ }
109
+ this.connected = true;
110
+ this.emit('connected');
111
+ await this.emitInitialEmails();
112
+ this.startWatching();
113
+ }
114
+ catch (error) {
115
+ // Clean up anything that may have been started; this instance holds no
116
+ // sockets or timers after a failed connect.
117
+ this.teardownWatchers();
118
+ this.connected = false;
119
+ this.emit('error', error);
120
+ }
121
+ }
122
+ /**
123
+ * Stops watching (event stream and/or polling timer) and emits
124
+ * 'disconnected' when the client was connected. Leaves no open handles.
125
+ */
126
+ async disconnect() {
127
+ this.stopped = true;
128
+ this.teardownWatchers();
129
+ if (this.connected) {
130
+ this.connected = false;
131
+ this.emit('disconnected');
132
+ }
133
+ }
134
+ /**
135
+ * Core JMAP method-call helper (RFC 8620 §3.2): POSTs { using, methodCalls }
136
+ * to the session's apiUrl and returns the methodResponses. HTTP problem
137
+ * details (RFC 7807) and JMAP `error` method responses are thrown as
138
+ * JmapError with `httpStatus`/`problemType`/`jmapErrorType` fields.
139
+ */
140
+ async request(methodCalls) {
141
+ if (!this.apiUrl) {
142
+ throw new Error('JmapClient is not connected yet — call connect() first.');
143
+ }
144
+ const response = await fetch(this.apiUrl, {
145
+ method: 'POST',
146
+ headers: {
147
+ authorization: this.getAuthHeader(),
148
+ 'content-type': 'application/json',
149
+ accept: 'application/json',
150
+ },
151
+ body: JSON.stringify({
152
+ using: [JMAP_CORE_CAPABILITY, JMAP_MAIL_CAPABILITY, JMAP_SUBMISSION_CAPABILITY],
153
+ methodCalls,
154
+ }),
155
+ });
156
+ if (!response.ok) {
157
+ throw await this.createHttpError(response, 'JMAP API request failed');
158
+ }
159
+ const parsed = (await response.json());
160
+ const methodResponses = parsed.methodResponses ?? [];
161
+ for (const [name, args, callId] of methodResponses) {
162
+ if (name === 'error') {
163
+ throw new JmapError(`JMAP method error "${args?.type}"${args?.description ? `: ${args.description}` : ''} (call ${callId})`, {
164
+ jmapErrorType: args?.type,
165
+ jmapErrorDescription: args?.description,
166
+ jmapCallId: callId,
167
+ });
168
+ }
169
+ }
170
+ return methodResponses;
171
+ }
172
+ /** Returns all mailboxes of the account (Mailbox/get with ids: null). */
173
+ async getMailboxes() {
174
+ const responses = await this.request([
175
+ ['Mailbox/get', { accountId: this.accountId, ids: null }, 'mb0'],
176
+ ]);
177
+ return (responses[0][1].list ?? []);
178
+ }
179
+ /**
180
+ * Runs Email/query (default filter: the watched mailbox) followed by a full
181
+ * Email/get and returns resolved messages, newest first.
182
+ */
183
+ async queryEmails(filter, limit) {
184
+ const effectiveFilter = filter ?? (this.mailbox ? { inMailbox: this.mailbox.id } : {});
185
+ const queryArgs = {
186
+ accountId: this.accountId,
187
+ filter: effectiveFilter,
188
+ sort: [{ property: 'receivedAt', isAscending: false }],
189
+ };
190
+ if (typeof limit === 'number') {
191
+ queryArgs.limit = limit;
192
+ }
193
+ const responses = await this.request([['Email/query', queryArgs, 'q0']]);
194
+ const ids = responses[0][1].ids ?? [];
195
+ if (!ids.length) {
196
+ return [];
197
+ }
198
+ const emails = await this.getEmailObjects(ids);
199
+ return emails.map((email) => this.toMessage(email));
200
+ }
201
+ /** Fetches a single email with all body values resolved (RFC 8621 §4.2, fetchAllBodyValues). */
202
+ async getEmail(id) {
203
+ const [email] = await this.getEmailObjects([id]);
204
+ if (!email) {
205
+ throw new Error(`Email "${id}" not found.`);
206
+ }
207
+ return this.toMessage(email);
208
+ }
209
+ /** Replaces the full keywords object of an email via Email/set. */
210
+ async setKeywords(emailId, keywords) {
211
+ await this.updateEmail(emailId, { keywords });
212
+ }
213
+ /** Convenience: sets the $seen keyword via an Email/set keywords patch. */
214
+ async markSeen(emailId) {
215
+ await this.updateEmail(emailId, { 'keywords/$seen': true });
216
+ }
217
+ /**
218
+ * Sends an email: Identity/get lookup, Email/set create (into the mailbox
219
+ * with role 'sent', falling back to 'drafts', then the watched mailbox) and
220
+ * EmailSubmission/set referencing the created email.
221
+ */
222
+ async sendEmail(outgoing) {
223
+ const identityResponses = await this.request([
224
+ ['Identity/get', { accountId: this.accountId }, 'i0'],
225
+ ]);
226
+ const identities = identityResponses[0][1].list ?? [];
227
+ const identity = (outgoing.from
228
+ ? identities.find((candidate) => candidate.email === outgoing.from.email)
229
+ : undefined) ?? identities[0];
230
+ if (!identity) {
231
+ throw new Error('No JMAP identity available for sending.');
232
+ }
233
+ const from = outgoing.from ?? { name: identity.name ?? null, email: identity.email };
234
+ const mailboxes = await this.getMailboxes();
235
+ const targetMailbox = mailboxes.find((mb) => mb.role === 'sent') ??
236
+ mailboxes.find((mb) => mb.role === 'drafts') ??
237
+ this.mailbox;
238
+ if (!targetMailbox) {
239
+ throw new Error('No mailbox available to store the outgoing email in.');
240
+ }
241
+ const bodyValues = {};
242
+ const textBodyParts = [];
243
+ const htmlBodyParts = [];
244
+ if (typeof outgoing.textBody === 'string') {
245
+ bodyValues.text = { value: outgoing.textBody };
246
+ textBodyParts.push({ partId: 'text', type: 'text/plain' });
247
+ }
248
+ if (typeof outgoing.htmlBody === 'string') {
249
+ bodyValues.html = { value: outgoing.htmlBody };
250
+ htmlBodyParts.push({ partId: 'html', type: 'text/html' });
251
+ }
252
+ if (!textBodyParts.length && !htmlBodyParts.length) {
253
+ throw new Error('sendEmail requires textBody and/or htmlBody.');
254
+ }
255
+ const emailCreate = {
256
+ mailboxIds: { [targetMailbox.id]: true },
257
+ keywords: { $seen: true },
258
+ from: [from],
259
+ to: outgoing.to,
260
+ subject: outgoing.subject,
261
+ bodyValues,
262
+ };
263
+ if (outgoing.cc) {
264
+ emailCreate.cc = outgoing.cc;
265
+ }
266
+ if (outgoing.bcc) {
267
+ emailCreate.bcc = outgoing.bcc;
268
+ }
269
+ if (textBodyParts.length) {
270
+ emailCreate.textBody = textBodyParts;
271
+ }
272
+ if (htmlBodyParts.length) {
273
+ emailCreate.htmlBody = htmlBodyParts;
274
+ }
275
+ const responses = await this.request([
276
+ ['Email/set', { accountId: this.accountId, create: { newEmail: emailCreate } }, 'c0'],
277
+ [
278
+ 'EmailSubmission/set',
279
+ {
280
+ accountId: this.accountId,
281
+ create: { newSubmission: { emailId: '#newEmail', identityId: identity.id } },
282
+ },
283
+ 'c1',
284
+ ],
285
+ ]);
286
+ const emailSetResult = responses.find((entry) => entry[2] === 'c0')?.[1] ?? {};
287
+ const createdEmail = emailSetResult.created?.newEmail;
288
+ if (!createdEmail) {
289
+ const notCreated = emailSetResult.notCreated?.newEmail;
290
+ throw new JmapError(`Email/set create failed${notCreated ? `: ${notCreated.type}${notCreated.description ? ` — ${notCreated.description}` : ''}` : ''}`, { jmapErrorType: notCreated?.type, jmapErrorDescription: notCreated?.description });
291
+ }
292
+ const submissionSetResult = responses.find((entry) => entry[2] === 'c1')?.[1] ?? {};
293
+ const createdSubmission = submissionSetResult.created?.newSubmission;
294
+ if (!createdSubmission) {
295
+ const notCreated = submissionSetResult.notCreated?.newSubmission;
296
+ throw new JmapError(`EmailSubmission/set create failed${notCreated ? `: ${notCreated.type}${notCreated.description ? ` — ${notCreated.description}` : ''}` : ''}`, { jmapErrorType: notCreated?.type, jmapErrorDescription: notCreated?.description });
297
+ }
298
+ return { emailId: createdEmail.id, submissionId: createdSubmission.id };
299
+ }
300
+ /**
301
+ * Downloads a blob's raw bytes using the session downloadUrl template
302
+ * (RFC 8620 §6.2: {accountId}, {blobId}, {type}, {name}).
303
+ */
304
+ async downloadBlob(blobId, type = 'application/octet-stream', name = 'blob') {
305
+ const template = this.session?.downloadUrl;
306
+ if (!template) {
307
+ throw new Error('JMAP session provides no downloadUrl — call connect() first.');
308
+ }
309
+ const expanded = template
310
+ .replace('{accountId}', encodeURIComponent(this.accountId))
311
+ .replace('{blobId}', encodeURIComponent(blobId))
312
+ .replace('{type}', encodeURIComponent(type))
313
+ .replace('{name}', encodeURIComponent(name));
314
+ const url = new URL(expanded, this.config.sessionUrl).toString();
315
+ const response = await fetch(url, {
316
+ headers: { authorization: this.getAuthHeader() },
317
+ });
318
+ if (!response.ok) {
319
+ throw await this.createHttpError(response, `Failed to download blob "${blobId}"`);
320
+ }
321
+ return new Uint8Array(await response.arrayBuffer());
322
+ }
323
+ // ======================
324
+ // internal helpers
325
+ // ======================
326
+ getAuthHeader() {
327
+ const auth = this.config.auth;
328
+ if (typeof auth.accessToken === 'string') {
329
+ return `Bearer ${auth.accessToken}`;
330
+ }
331
+ return `Basic ${Buffer.from(`${auth.user}:${auth.pass}`).toString('base64')}`;
332
+ }
333
+ async createHttpError(response, messagePrefix) {
334
+ let problemType;
335
+ let problemDetail;
336
+ try {
337
+ const body = (await response.json());
338
+ if (body && typeof body === 'object') {
339
+ problemType = typeof body.type === 'string' ? body.type : undefined;
340
+ problemDetail = typeof body.detail === 'string' ? body.detail : undefined;
341
+ }
342
+ }
343
+ catch {
344
+ // non-JSON error body
345
+ }
346
+ return new JmapError(`${messagePrefix}: HTTP ${response.status}${problemDetail ? ` — ${problemDetail}` : ''}${problemType ? ` (${problemType})` : ''}`, { httpStatus: response.status, problemType, problemDetail });
347
+ }
348
+ async resolveMailbox() {
349
+ const responses = await this.request([
350
+ ['Mailbox/get', { accountId: this.accountId, ids: null }, 'mb0'],
351
+ ]);
352
+ const list = (responses[0][1].list ?? []);
353
+ const wanted = this.config.mailbox ?? 'INBOX';
354
+ const wantedLower = wanted.toLowerCase();
355
+ const byRole = list.find((mb) => (mb.role ?? '').toLowerCase() === wantedLower);
356
+ const byName = list.find((mb) => mb.name.toLowerCase() === wantedLower);
357
+ const mailbox = byRole ?? byName;
358
+ if (!mailbox) {
359
+ throw new Error(`JMAP mailbox "${wanted}" not found (no role or name match).`);
360
+ }
361
+ return mailbox;
362
+ }
363
+ async fetchEmailState() {
364
+ const responses = await this.request([
365
+ ['Email/get', { accountId: this.accountId, ids: [] }, 'st0'],
366
+ ]);
367
+ return String(responses[0][1].state ?? '');
368
+ }
369
+ async getEmailObjects(ids) {
370
+ const responses = await this.request([
371
+ [
372
+ 'Email/get',
373
+ {
374
+ accountId: this.accountId,
375
+ ids,
376
+ properties: EMAIL_PROPERTIES,
377
+ fetchAllBodyValues: true,
378
+ },
379
+ 'g0',
380
+ ],
381
+ ]);
382
+ return (responses[0][1].list ?? []);
383
+ }
384
+ async updateEmail(emailId, patch) {
385
+ const responses = await this.request([
386
+ ['Email/set', { accountId: this.accountId, update: { [emailId]: patch } }, 'u0'],
387
+ ]);
388
+ const result = responses[0][1];
389
+ const notUpdated = result.notUpdated?.[emailId];
390
+ if (notUpdated) {
391
+ throw new JmapError(`Email/set update of "${emailId}" failed: ${notUpdated.type}${notUpdated.description ? ` — ${notUpdated.description}` : ''}`, { jmapErrorType: notUpdated.type, jmapErrorDescription: notUpdated.description });
392
+ }
393
+ }
394
+ toMessage(email) {
395
+ const bodyValues = email.bodyValues ?? {};
396
+ const resolveParts = (parts) => parts
397
+ .map((part) => (part.partId != null ? bodyValues[part.partId]?.value : undefined))
398
+ .filter((value) => typeof value === 'string')
399
+ .join('\n');
400
+ const htmlParts = (email.htmlBody ?? []).filter((part) => part.type === 'text/html');
401
+ const attachments = (email.attachments ?? [])
402
+ .filter((part) => typeof part.blobId === 'string')
403
+ .map((part) => ({
404
+ blobId: part.blobId,
405
+ name: part.name ?? undefined,
406
+ type: part.type,
407
+ size: part.size,
408
+ }));
409
+ return {
410
+ id: email.id,
411
+ blobId: email.blobId,
412
+ threadId: email.threadId,
413
+ mailboxIds: email.mailboxIds ?? {},
414
+ keywords: email.keywords ?? {},
415
+ from: email.from ?? [],
416
+ to: email.to ?? [],
417
+ cc: email.cc ?? [],
418
+ bcc: email.bcc ?? [],
419
+ replyTo: email.replyTo ?? [],
420
+ subject: email.subject ?? undefined,
421
+ receivedAt: email.receivedAt,
422
+ textBody: resolveParts(email.textBody ?? []),
423
+ htmlBody: htmlParts.length ? resolveParts(htmlParts) : undefined,
424
+ attachments,
425
+ raw: email,
426
+ };
427
+ }
428
+ emitMessage(message) {
429
+ if (this.seenEmailIds.has(message.id)) {
430
+ return;
431
+ }
432
+ this.seenEmailIds.add(message.id);
433
+ this.emit('message', message);
434
+ }
435
+ async emitInitialEmails() {
436
+ const messages = await this.queryEmails();
437
+ // queryEmails sorts newest first; emit oldest first for natural ordering
438
+ for (const message of messages.reverse()) {
439
+ this.emitMessage(message);
440
+ }
441
+ }
442
+ startWatching() {
443
+ if (this.stopped) {
444
+ return;
445
+ }
446
+ const eventSourceUrl = this.session?.eventSourceUrl;
447
+ if (eventSourceUrl) {
448
+ this.startEventStream(eventSourceUrl);
449
+ }
450
+ else {
451
+ this.startPolling();
452
+ }
453
+ }
454
+ /**
455
+ * Watches the JMAP event source (RFC 8620 §7.3) by parsing SSE frames from
456
+ * a fetch body stream. A hand-rolled parser is used instead of the global
457
+ * EventSource because JMAP requires an Authorization header, which the
458
+ * WHATWG EventSource API cannot send.
459
+ */
460
+ startEventStream(templateUrl) {
461
+ const expanded = templateUrl
462
+ .replace('{types}', '*')
463
+ .replace('{closeafter}', 'no')
464
+ .replace('{ping}', '30');
465
+ const url = new URL(expanded, this.config.sessionUrl).toString();
466
+ // Last stream wins under any interleaving: abort a previous stream before
467
+ // installing the new controller.
468
+ if (this.sseAbortController) {
469
+ this.sseAbortController.abort();
470
+ }
471
+ const abortController = new AbortController();
472
+ this.sseAbortController = abortController;
473
+ void this.runEventStream(url, abortController);
474
+ }
475
+ async runEventStream(url, abortController) {
476
+ try {
477
+ const response = await fetch(url, {
478
+ headers: {
479
+ authorization: this.getAuthHeader(),
480
+ accept: 'text/event-stream',
481
+ },
482
+ signal: abortController.signal,
483
+ });
484
+ if (!response.ok || !response.body) {
485
+ throw new Error(`JMAP event source unavailable (HTTP ${response.status}).`);
486
+ }
487
+ // The stream is live; catch up on anything that changed between the
488
+ // initial state snapshot and the stream being established.
489
+ void this.fetchDeltas();
490
+ const reader = response.body.getReader();
491
+ const decoder = new TextDecoder();
492
+ let buffer = '';
493
+ let eventName = 'message';
494
+ let dataLines = [];
495
+ while (true) {
496
+ const { done, value } = await reader.read();
497
+ if (done) {
498
+ break;
499
+ }
500
+ buffer += decoder.decode(value, { stream: true });
501
+ let newlineIndex;
502
+ while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
503
+ const line = buffer.slice(0, newlineIndex).replace(/\r$/, '');
504
+ buffer = buffer.slice(newlineIndex + 1);
505
+ if (line === '') {
506
+ if (dataLines.length) {
507
+ this.handleEventStreamEvent(eventName, dataLines.join('\n'));
508
+ }
509
+ eventName = 'message';
510
+ dataLines = [];
511
+ }
512
+ else if (line.startsWith(':')) {
513
+ // comment / keepalive
514
+ }
515
+ else if (line.startsWith('event:')) {
516
+ eventName = line.slice(6).trim();
517
+ }
518
+ else if (line.startsWith('data:')) {
519
+ dataLines.push(line.slice(5).replace(/^ /, ''));
520
+ }
521
+ // id: and retry: fields are irrelevant here
522
+ }
523
+ }
524
+ // Stream ended server-side: fall back to polling (mirroring the catch
525
+ // guards so a superseded stream's continuation stays inert).
526
+ if (!this.stopped && !abortController.signal.aborted) {
527
+ if (this.sseAbortController === abortController) {
528
+ this.sseAbortController = null;
529
+ }
530
+ this.startPolling();
531
+ }
532
+ }
533
+ catch (error) {
534
+ if (this.stopped || abortController.signal.aborted) {
535
+ return;
536
+ }
537
+ // Event stream unavailable or broken: abort so any held response body
538
+ // (e.g. an unconsumed non-OK response) releases its connection, then
539
+ // fall back to polling.
540
+ abortController.abort();
541
+ if (this.sseAbortController === abortController) {
542
+ this.sseAbortController = null;
543
+ }
544
+ this.startPolling();
545
+ }
546
+ }
547
+ handleEventStreamEvent(eventName, data) {
548
+ let parsed;
549
+ try {
550
+ parsed = JSON.parse(data);
551
+ }
552
+ catch {
553
+ return;
554
+ }
555
+ if (eventName !== 'state' && parsed?.['@type'] !== 'StateChange') {
556
+ return;
557
+ }
558
+ const changed = parsed?.changed?.[this.accountId];
559
+ const emailState = changed?.Email;
560
+ if (typeof emailState === 'string' && emailState !== this.lastEmailState) {
561
+ void this.fetchDeltas();
562
+ }
563
+ }
564
+ startPolling() {
565
+ if (this.pollTimer || this.stopped) {
566
+ return;
567
+ }
568
+ const interval = this.config.pollIntervalMs ?? 30000;
569
+ this.pollTimer = setInterval(() => {
570
+ void this.fetchDeltas();
571
+ }, interval);
572
+ }
573
+ async fetchDeltas() {
574
+ if (this.stopped) {
575
+ return;
576
+ }
577
+ if (this.fetchingDeltas) {
578
+ this.deltaQueued = true;
579
+ return;
580
+ }
581
+ this.fetchingDeltas = true;
582
+ try {
583
+ do {
584
+ this.deltaQueued = false;
585
+ await this.fetchDeltasOnce();
586
+ } while (this.deltaQueued && !this.stopped);
587
+ }
588
+ finally {
589
+ this.fetchingDeltas = false;
590
+ }
591
+ }
592
+ async fetchDeltasOnce() {
593
+ try {
594
+ let hasMore = true;
595
+ while (hasMore && !this.stopped) {
596
+ const sinceState = this.lastEmailState;
597
+ const responses = await this.request([
598
+ ['Email/changes', { accountId: this.accountId, sinceState }, 'ch0'],
599
+ ]);
600
+ const changes = responses[0][1];
601
+ this.lastEmailState = String(changes.newState ?? sinceState);
602
+ hasMore = changes.hasMoreChanges === true && this.lastEmailState !== sinceState;
603
+ const createdIds = changes.created ?? [];
604
+ if (createdIds.length) {
605
+ const emails = await this.getEmailObjects(createdIds);
606
+ for (const email of emails) {
607
+ if (this.mailbox && email.mailboxIds?.[this.mailbox.id]) {
608
+ this.emitMessage(this.toMessage(email));
609
+ }
610
+ }
611
+ }
612
+ }
613
+ }
614
+ catch (error) {
615
+ if (this.stopped) {
616
+ return;
617
+ }
618
+ if (error?.jmapErrorType === 'cannotCalculateChanges') {
619
+ try {
620
+ await this.resyncViaQuery();
621
+ }
622
+ catch (resyncError) {
623
+ this.emit('error', resyncError);
624
+ }
625
+ }
626
+ else {
627
+ this.emit('error', error);
628
+ }
629
+ }
630
+ }
631
+ /** Full resync fallback when the server cannot calculate changes. */
632
+ async resyncViaQuery() {
633
+ this.lastEmailState = await this.fetchEmailState();
634
+ const messages = await this.queryEmails();
635
+ for (const message of messages.reverse()) {
636
+ this.emitMessage(message);
637
+ }
638
+ }
639
+ teardownWatchers() {
640
+ if (this.sseAbortController) {
641
+ this.sseAbortController.abort();
642
+ this.sseAbortController = null;
643
+ }
644
+ if (this.pollTimer) {
645
+ clearInterval(this.pollTimer);
646
+ this.pollTimer = null;
647
+ }
648
+ }
649
+ }
650
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5qbWFwY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5qbWFwY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFFbEQsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsMkJBQTJCLENBQUM7QUFDaEUsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsMkJBQTJCLENBQUM7QUFDaEUsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsaUNBQWlDLENBQUM7QUEwSjVFLDJGQUEyRjtBQUMzRixNQUFNLE9BQU8sU0FBVSxTQUFRLEtBQUs7SUFRbEMsWUFBWSxPQUFlLEVBQUUsU0FBNkIsRUFBRTtRQUMxRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLFdBQVcsQ0FBQztRQUN4QixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUM5QixDQUFDO0NBQ0Y7QUFFRCxNQUFNLGdCQUFnQixHQUFHO0lBQ3ZCLElBQUk7SUFDSixRQUFRO0lBQ1IsVUFBVTtJQUNWLFlBQVk7SUFDWixVQUFVO0lBQ1YsTUFBTTtJQUNOLFlBQVk7SUFDWixRQUFRO0lBQ1IsU0FBUztJQUNULE1BQU07SUFDTixJQUFJO0lBQ0osSUFBSTtJQUNKLEtBQUs7SUFDTCxTQUFTO0lBQ1QsZUFBZTtJQUNmLFNBQVM7SUFDVCxZQUFZO0lBQ1osVUFBVTtJQUNWLFVBQVU7SUFDVixhQUFhO0NBQ2QsQ0FBQztBQUVGLE1BQU0sT0FBTyxVQUFXLFNBQVEsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZO0lBZXpELFlBQVksTUFBeUI7UUFDbkMsS0FBSyxFQUFFLENBQUM7UUFkRixZQUFPLEdBQXdCLElBQUksQ0FBQztRQUNwQyxjQUFTLEdBQVcsRUFBRSxDQUFDO1FBQ3ZCLFdBQU0sR0FBVyxFQUFF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