aamp-sdk 0.1.5

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,634 @@
1
+ /**
2
+ * JMAP WebSocket Push Client
3
+ *
4
+ * Connects to Stalwart's JMAP WebSocket endpoint and subscribes to
5
+ * Email StateChange events. When a new email arrives in the agent's
6
+ * mailbox, fetches it via JMAP and emits the parsed AAMP headers.
7
+ *
8
+ * Protocol: RFC 8887 (JMAP over WebSocket)
9
+ * Ref: https://www.rfc-editor.org/rfc/rfc8887
10
+ */
11
+ import WebSocket from 'ws';
12
+ import { EventEmitter } from 'events';
13
+ import { parseAampHeaders } from './parser.js';
14
+ export class JmapPushClient extends EventEmitter {
15
+ ws = null;
16
+ session = null;
17
+ reconnectTimer = null;
18
+ pollTimer = null;
19
+ pingTimer = null;
20
+ seenMessageIds = new Set();
21
+ connected = false;
22
+ pollingActive = false;
23
+ running = false;
24
+ connecting = false;
25
+ /** JMAP Email state — tracks processed position; null = not yet initialized */
26
+ emailState = null;
27
+ startedAtMs = Date.now();
28
+ email;
29
+ password;
30
+ jmapUrl;
31
+ reconnectInterval;
32
+ rejectUnauthorized;
33
+ pingIntervalMs = 5000;
34
+ constructor(opts) {
35
+ super();
36
+ this.email = opts.email;
37
+ this.password = opts.password;
38
+ this.jmapUrl = opts.jmapUrl.replace(/\/$/, '');
39
+ this.reconnectInterval = opts.reconnectInterval ?? 5000;
40
+ this.rejectUnauthorized = opts.rejectUnauthorized ?? true;
41
+ }
42
+ /**
43
+ * Start the JMAP Push listener
44
+ */
45
+ async start() {
46
+ this.running = true;
47
+ await this.connect();
48
+ }
49
+ /**
50
+ * Stop the JMAP Push listener
51
+ */
52
+ stop() {
53
+ this.running = false;
54
+ if (this.reconnectTimer) {
55
+ clearTimeout(this.reconnectTimer);
56
+ this.reconnectTimer = null;
57
+ }
58
+ if (this.pollTimer) {
59
+ clearTimeout(this.pollTimer);
60
+ this.pollTimer = null;
61
+ }
62
+ if (this.pingTimer) {
63
+ clearInterval(this.pingTimer);
64
+ this.pingTimer = null;
65
+ }
66
+ if (this.ws) {
67
+ this.ws.close();
68
+ this.ws = null;
69
+ }
70
+ this.connected = false;
71
+ this.pollingActive = false;
72
+ this.connecting = false;
73
+ }
74
+ getAuthHeader() {
75
+ const creds = `${this.email}:${this.password}`;
76
+ return `Basic ${Buffer.from(creds).toString('base64')}`;
77
+ }
78
+ /**
79
+ * Fetch the JMAP session object
80
+ */
81
+ async fetchSession() {
82
+ const url = `${this.jmapUrl}/.well-known/jmap`;
83
+ const res = await fetch(url, {
84
+ headers: { Authorization: this.getAuthHeader() },
85
+ });
86
+ if (!res.ok) {
87
+ throw new Error(`Failed to fetch JMAP session: ${res.status} ${res.statusText}`);
88
+ }
89
+ return res.json();
90
+ }
91
+ /**
92
+ * Perform a JMAP API call
93
+ */
94
+ async jmapCall(methods) {
95
+ if (!this.session)
96
+ throw new Error('No JMAP session');
97
+ // Use the configured jmapUrl (external hostname) rather than session.apiUrl
98
+ // which Stalwart populates with its own internal URL (e.g. http://aamp.local:8080/jmap)
99
+ // and is unreachable when running behind a proxy.
100
+ const apiUrl = `${this.jmapUrl}/jmap/`;
101
+ const res = await fetch(apiUrl, {
102
+ method: 'POST',
103
+ headers: {
104
+ Authorization: this.getAuthHeader(),
105
+ 'Content-Type': 'application/json',
106
+ },
107
+ body: JSON.stringify({
108
+ using: [
109
+ 'urn:ietf:params:jmap:core',
110
+ 'urn:ietf:params:jmap:mail',
111
+ ],
112
+ methodCalls: methods,
113
+ }),
114
+ });
115
+ if (!res.ok) {
116
+ throw new Error(`JMAP API call failed: ${res.status}`);
117
+ }
118
+ return res.json();
119
+ }
120
+ /**
121
+ * Initialize emailState by fetching the current state without loading any emails.
122
+ * Called on first connect so we only process emails that arrive AFTER this point.
123
+ */
124
+ async initEmailState(accountId) {
125
+ const response = await this.jmapCall([
126
+ ['Email/get', { accountId, ids: [] }, 'g0'],
127
+ ]);
128
+ const getResp = response.methodResponses.find(([name]) => name === 'Email/get');
129
+ if (getResp) {
130
+ this.emailState = getResp[1].state ?? null;
131
+ }
132
+ }
133
+ /**
134
+ * Fetch only emails created since `sinceState` using Email/changes.
135
+ * Updates `this.emailState` to the new state after fetching.
136
+ * Returns [] and resets state if the server cannot calculate changes (state too old).
137
+ */
138
+ async fetchEmailsSince(accountId, sinceState) {
139
+ const changesResp = await this.jmapCall([
140
+ ['Email/changes', { accountId, sinceState, maxChanges: 50 }, 'c1'],
141
+ ]);
142
+ const changesResult = changesResp.methodResponses.find(([name]) => name === 'Email/changes');
143
+ // Handle server error — e.g. "cannotCalculateChanges" when state is too old
144
+ if (!changesResult || changesResult[0] === 'error') {
145
+ await this.initEmailState(accountId);
146
+ return [];
147
+ }
148
+ const changes = changesResult[1];
149
+ if (changes.newState) {
150
+ this.emailState = changes.newState;
151
+ }
152
+ const newIds = changes.created ?? [];
153
+ if (newIds.length === 0)
154
+ return [];
155
+ const emailResp = await this.jmapCall([
156
+ [
157
+ 'Email/get',
158
+ {
159
+ accountId,
160
+ ids: newIds,
161
+ properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],
162
+ fetchTextBodyValues: true,
163
+ maxBodyValueBytes: 262144,
164
+ },
165
+ 'g1',
166
+ ],
167
+ ]);
168
+ const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get');
169
+ if (!getResult)
170
+ return [];
171
+ const data = getResult[1];
172
+ return data.list ?? [];
173
+ }
174
+ /**
175
+ * Process a received email.
176
+ *
177
+ * Priority:
178
+ * 1. If X-AAMP-Intent is present → emit typed AAMP event (task.dispatch / task.result / task.help)
179
+ * 2. If In-Reply-To is present → emit 'reply' event so the application layer can
180
+ * resolve the thread (inReplyTo → taskId via Redis/DB) and handle human replies.
181
+ * 3. Otherwise → ignore (not an AAMP-related email)
182
+ */
183
+ processEmail(email) {
184
+ // Build lowercase header map from JMAP header array
185
+ const headerMap = {};
186
+ for (const h of email.headers ?? []) {
187
+ headerMap[h.name.toLowerCase()] = h.value.trim();
188
+ }
189
+ const fromAddr = email.from?.[0]?.email ?? '';
190
+ const toAddr = email.to?.[0]?.email ?? '';
191
+ const messageId = email.messageId?.[0] ?? email.id;
192
+ if (this.seenMessageIds.has(messageId))
193
+ return;
194
+ this.seenMessageIds.add(messageId);
195
+ // ── Path 1: AAMP-tagged email ─────────────────────────────────────────────
196
+ const msg = parseAampHeaders({
197
+ from: fromAddr,
198
+ to: toAddr,
199
+ messageId,
200
+ subject: email.subject ?? '',
201
+ headers: headerMap,
202
+ });
203
+ if (msg && 'intent' in msg) {
204
+ // Attach email body text (task description) to all AAMP messages
205
+ const aampTextPartId = email.textBody?.[0]?.partId;
206
+ const aampBodyText = aampTextPartId ? (email.bodyValues?.[aampTextPartId]?.value ?? '').trim() : '';
207
+ msg.bodyText = aampBodyText;
208
+ // Attach received attachment metadata (blobId-based, downloadable via downloadBlob)
209
+ const receivedAttachments = (email.attachments ?? []).map(a => ({
210
+ filename: a.name ?? 'attachment',
211
+ contentType: a.type,
212
+ size: a.size,
213
+ blobId: a.blobId,
214
+ }));
215
+ if (receivedAttachments.length > 0) {
216
+ ;
217
+ msg.attachments = receivedAttachments;
218
+ }
219
+ // Auto-ACK for dispatches — AampClient handles the actual sending
220
+ if (msg.intent === 'task.dispatch') {
221
+ this.emit('_autoAck', { to: fromAddr, taskId: msg.taskId, messageId });
222
+ }
223
+ this.emit(msg.intent, msg);
224
+ return;
225
+ }
226
+ // ── Path 2: standard email reply — In-Reply-To fallback ───────────────────
227
+ // Standard email clients automatically set In-Reply-To when replying.
228
+ // We strip angle brackets (<msgid@host>) to get the bare Message-ID.
229
+ const rawInReplyTo = headerMap['in-reply-to'] ?? '';
230
+ if (!rawInReplyTo)
231
+ return; // unrelated email, ignore
232
+ // Handle "References" chain: prefer the last (most recent) Message-ID
233
+ // so multi-turn threads still resolve to the correct task.
234
+ const rawReferences = headerMap['references'] ?? '';
235
+ const referencesIds = rawReferences
236
+ .split(/\s+/)
237
+ .map((s) => s.replace(/[<>]/g, '').trim())
238
+ .filter(Boolean);
239
+ const inReplyTo = rawInReplyTo.replace(/[<>]/g, '').trim();
240
+ // Extract plain-text body if available (fetched via fetchTextBodyValues)
241
+ const textPartId = email.textBody?.[0]?.partId;
242
+ const bodyText = textPartId ? (email.bodyValues?.[textPartId]?.value ?? '').trim() : '';
243
+ const reply = {
244
+ inReplyTo,
245
+ messageId,
246
+ from: fromAddr,
247
+ to: toAddr,
248
+ subject: email.subject ?? '',
249
+ bodyText,
250
+ };
251
+ // Also expose the full References chain so callers can walk the thread if needed
252
+ if (referencesIds.length > 0) {
253
+ Object.assign(reply, { references: referencesIds });
254
+ }
255
+ this.emit('reply', reply);
256
+ }
257
+ async fetchRecentEmails(accountId) {
258
+ const queryResp = await this.jmapCall([
259
+ [
260
+ 'Email/query',
261
+ {
262
+ accountId,
263
+ sort: [{ property: 'receivedAt', isAscending: false }],
264
+ limit: 20,
265
+ },
266
+ 'q1',
267
+ ],
268
+ ]);
269
+ const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query');
270
+ if (!queryResult)
271
+ return [];
272
+ const ids = (queryResult[1].ids ?? []).slice(0, 20);
273
+ if (ids.length === 0)
274
+ return [];
275
+ const emailResp = await this.jmapCall([
276
+ [
277
+ 'Email/get',
278
+ {
279
+ accountId,
280
+ ids,
281
+ properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],
282
+ fetchTextBodyValues: true,
283
+ maxBodyValueBytes: 262144,
284
+ },
285
+ 'gRecent',
286
+ ],
287
+ ]);
288
+ const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get');
289
+ if (!getResult)
290
+ return [];
291
+ return getResult[1].list ?? [];
292
+ }
293
+ shouldProcessBootstrapEmail(email) {
294
+ const receivedAtMs = new Date(email.receivedAt).getTime();
295
+ // Keep a small grace window for mail that arrived during startup / reconnect races,
296
+ // but do not replay older historical mailbox contents as fresh tasks.
297
+ return Number.isFinite(receivedAtMs) && receivedAtMs >= this.startedAtMs - 15_000;
298
+ }
299
+ /**
300
+ * Connect to JMAP WebSocket
301
+ */
302
+ async connect() {
303
+ if (this.connecting || !this.running)
304
+ return;
305
+ this.connecting = true;
306
+ try {
307
+ this.session = await this.fetchSession();
308
+ }
309
+ catch (err) {
310
+ this.connecting = false;
311
+ this.emit('error', new Error(`Failed to get JMAP session: ${err.message}`));
312
+ this.startPolling('session fetch failed');
313
+ this.scheduleReconnect();
314
+ return;
315
+ }
316
+ // Build WebSocket URL from the configured jmapUrl (the management-service proxy).
317
+ // The management service exposes a dedicated external WebSocket path /_jmap_ws
318
+ // and rewrites it to Stalwart's internal /jmap/ws endpoint. Keeping the
319
+ // external WS path separate avoids overlap with the normal HTTP /jmap proxy.
320
+ // The management service proxies WebSocket upgrades on /_jmap_ws to Stalwart
321
+ // using node-http-proxy, which forwards Upgrade headers verbatim (including
322
+ // Sec-WebSocket-Protocol: jmap) so Stalwart accepts the connection.
323
+ // We never use session.capabilities URL directly because Stalwart populates it
324
+ // with its own internal hostname (e.g. ws://aamp.local:8080/jmap/ws) which is
325
+ // unreachable from outside the Docker network.
326
+ const stalwartWsUrl = `${this.jmapUrl}/_jmap_ws`
327
+ .replace(/^https:\/\//, 'wss://')
328
+ .replace(/^http:\/\//, 'ws://');
329
+ this.ws = new WebSocket(stalwartWsUrl, 'jmap', {
330
+ headers: {
331
+ Authorization: this.getAuthHeader(),
332
+ },
333
+ perMessageDeflate: false,
334
+ rejectUnauthorized: this.rejectUnauthorized,
335
+ });
336
+ this.ws.on('unexpected-response', (_req, res) => {
337
+ this.connecting = false;
338
+ const headerSummary = Object.entries(res.headers)
339
+ .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(', ') : (value ?? '')}`)
340
+ .join('; ');
341
+ this.startPolling(`websocket handshake failed: ${res.statusCode ?? 'unknown'}`);
342
+ this.emit('error', new Error(`JMAP WebSocket handshake failed: ${res.statusCode ?? 'unknown'} ${res.statusMessage ?? ''}${headerSummary ? ` | headers: ${headerSummary}` : ''}`));
343
+ this.scheduleReconnect();
344
+ });
345
+ this.ws.on('open', async () => {
346
+ this.connecting = false;
347
+ this.connected = true;
348
+ this.stopPolling();
349
+ this.startPingHeartbeat();
350
+ // On first connect (emailState is null), initialize state so we only
351
+ // process emails arriving AFTER this point.
352
+ // On reconnect, emailState is already set — Email/changes will catch up.
353
+ const accountId = this.session?.primaryAccounts['urn:ietf:params:jmap:mail'];
354
+ if (accountId && this.emailState === null) {
355
+ await this.initEmailState(accountId);
356
+ }
357
+ // Subscribe to Email state changes AFTER state is initialized
358
+ this.ws.send(JSON.stringify({
359
+ '@type': 'WebSocketPushEnable',
360
+ dataTypes: ['Email'],
361
+ pushState: null,
362
+ }));
363
+ this.emit('connected');
364
+ });
365
+ this.ws.on('pong', () => {
366
+ // Receiving pong confirms the upstream and LB path are still alive.
367
+ });
368
+ this.ws.on('message', async (rawData) => {
369
+ try {
370
+ const msg = JSON.parse(rawData.toString());
371
+ if (msg['@type'] === 'StateChange') {
372
+ await this.handleStateChange(msg);
373
+ }
374
+ }
375
+ catch (err) {
376
+ this.emit('error', new Error(`Failed to process JMAP push message: ${err.message}`));
377
+ }
378
+ });
379
+ this.ws.on('close', (code, reason) => {
380
+ this.connecting = false;
381
+ this.connected = false;
382
+ this.stopPingHeartbeat();
383
+ const reasonStr = reason?.toString() ?? 'connection closed';
384
+ this.startPolling(reasonStr);
385
+ this.emit('disconnected', reasonStr);
386
+ if (this.running) {
387
+ this.scheduleReconnect();
388
+ }
389
+ });
390
+ this.ws.on('error', (err) => {
391
+ this.connecting = false;
392
+ this.stopPingHeartbeat();
393
+ this.startPolling(err.message);
394
+ this.emit('error', err);
395
+ });
396
+ }
397
+ startPingHeartbeat() {
398
+ if (this.pingTimer) {
399
+ clearInterval(this.pingTimer);
400
+ this.pingTimer = null;
401
+ }
402
+ this.pingTimer = setInterval(() => {
403
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
404
+ return;
405
+ try {
406
+ this.ws.ping();
407
+ }
408
+ catch (err) {
409
+ this.emit('error', new Error(`Failed to send WebSocket ping: ${err.message}`));
410
+ }
411
+ }, this.pingIntervalMs);
412
+ }
413
+ stopPingHeartbeat() {
414
+ if (this.pingTimer) {
415
+ clearInterval(this.pingTimer);
416
+ this.pingTimer = null;
417
+ }
418
+ }
419
+ async handleStateChange(stateChange) {
420
+ if (!this.session)
421
+ return;
422
+ const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail'];
423
+ if (!accountId)
424
+ return;
425
+ const changedAccount = stateChange.changed[accountId];
426
+ if (!changedAccount?.Email)
427
+ return;
428
+ try {
429
+ if (this.emailState === null) {
430
+ // State not yet initialized (race between open handler and first StateChange)
431
+ // Just initialize and skip — next StateChange will use Email/changes properly
432
+ await this.initEmailState(accountId);
433
+ return;
434
+ }
435
+ const emails = await this.fetchEmailsSince(accountId, this.emailState);
436
+ for (const email of emails) {
437
+ this.processEmail(email);
438
+ }
439
+ }
440
+ catch (err) {
441
+ this.emit('error', new Error(`Failed to fetch emails: ${err.message}`));
442
+ }
443
+ }
444
+ scheduleReconnect() {
445
+ if (this.reconnectTimer)
446
+ return;
447
+ this.reconnectTimer = setTimeout(async () => {
448
+ this.reconnectTimer = null;
449
+ if (this.running) {
450
+ await this.connect();
451
+ }
452
+ }, this.reconnectInterval);
453
+ }
454
+ isConnected() {
455
+ return this.connected || this.pollingActive;
456
+ }
457
+ isUsingPollingFallback() {
458
+ return this.pollingActive && !this.connected;
459
+ }
460
+ stopPolling() {
461
+ if (this.pollTimer) {
462
+ clearTimeout(this.pollTimer);
463
+ this.pollTimer = null;
464
+ }
465
+ this.pollingActive = false;
466
+ }
467
+ startPolling(reason) {
468
+ if (!this.running || this.pollingActive)
469
+ return;
470
+ this.pollingActive = true;
471
+ this.emit('error', new Error(`JMAP WebSocket unavailable, falling back to polling: ${reason}`));
472
+ this.emit('connected');
473
+ const poll = async () => {
474
+ if (!this.running || this.connected) {
475
+ this.stopPolling();
476
+ return;
477
+ }
478
+ try {
479
+ if (!this.session) {
480
+ this.session = await this.fetchSession();
481
+ }
482
+ const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']
483
+ ?? Object.keys(this.session.accounts)[0];
484
+ if (!accountId) {
485
+ throw new Error('No mail account available in JMAP session');
486
+ }
487
+ if (this.emailState === null) {
488
+ const recentEmails = await this.fetchRecentEmails(accountId);
489
+ for (const email of recentEmails.sort((a, b) => {
490
+ const aTs = new Date(a.receivedAt).getTime();
491
+ const bTs = new Date(b.receivedAt).getTime();
492
+ return aTs - bTs;
493
+ })) {
494
+ if (!this.shouldProcessBootstrapEmail(email))
495
+ continue;
496
+ this.processEmail(email);
497
+ }
498
+ await this.initEmailState(accountId);
499
+ }
500
+ else {
501
+ const emails = await this.fetchEmailsSince(accountId, this.emailState);
502
+ for (const email of emails) {
503
+ this.processEmail(email);
504
+ }
505
+ }
506
+ }
507
+ catch (err) {
508
+ this.emit('error', new Error(`Polling fallback failed: ${err.message}`));
509
+ }
510
+ finally {
511
+ if (this.running && !this.connected) {
512
+ this.pollTimer = setTimeout(poll, this.reconnectInterval);
513
+ }
514
+ }
515
+ };
516
+ this.pollTimer = setTimeout(poll, 0);
517
+ }
518
+ /**
519
+ * Download a blob (attachment) by its JMAP blobId.
520
+ * Returns the raw binary content as a Buffer.
521
+ */
522
+ async downloadBlob(blobId, filename) {
523
+ if (!this.session) {
524
+ // Fetch session on demand if not yet connected
525
+ this.session = await this.fetchSession();
526
+ }
527
+ const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']
528
+ ?? Object.keys(this.session.accounts)[0];
529
+ // Build download URL from session template or fall back to standard JMAP path
530
+ let downloadUrl = this.session.downloadUrl
531
+ ?? `${this.jmapUrl}/jmap/download/{accountId}/{blobId}/{name}`;
532
+ // Replace session.downloadUrl host with our configured jmapUrl
533
+ // (Stalwart may report an internal hostname unreachable from outside Docker)
534
+ try {
535
+ const parsed = new URL(downloadUrl);
536
+ const configured = new URL(this.jmapUrl);
537
+ parsed.protocol = configured.protocol;
538
+ parsed.host = configured.host;
539
+ downloadUrl = parsed.toString();
540
+ }
541
+ catch {
542
+ // If URL parsing fails, use the template as-is
543
+ }
544
+ const safeFilename = filename ?? 'attachment';
545
+ downloadUrl = downloadUrl
546
+ .replace(/\{accountId\}|%7BaccountId%7D/gi, encodeURIComponent(accountId))
547
+ .replace(/\{blobId\}|%7BblobId%7D/gi, encodeURIComponent(blobId))
548
+ .replace(/\{name\}|%7Bname%7D/gi, encodeURIComponent(safeFilename))
549
+ .replace(/\{type\}|%7Btype%7D/gi, 'application/octet-stream');
550
+ // Retry with exponential backoff — the blob may not be immediately available
551
+ // after the result email is observed (store/index write delay).
552
+ const maxAttempts = 8;
553
+ let lastStatus = null;
554
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
555
+ const res = await fetch(downloadUrl, {
556
+ headers: { Authorization: this.getAuthHeader() },
557
+ });
558
+ lastStatus = res.status;
559
+ if (res.ok) {
560
+ const arrayBuffer = await res.arrayBuffer();
561
+ return Buffer.from(arrayBuffer);
562
+ }
563
+ if (attempt < maxAttempts && (res.status === 404 || res.status === 429 || res.status === 503)) {
564
+ console.warn(`[AAMP-SDK] blob download retry status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`);
565
+ const delay = Math.min(1000 * Math.pow(2, attempt - 1), 15000); // 1s, 2s, 4s, 8s, 15s...
566
+ await new Promise(r => setTimeout(r, delay));
567
+ continue;
568
+ }
569
+ console.error(`[AAMP-SDK] blob download failed status=${res.status} attempt=${attempt}/${maxAttempts} url=${downloadUrl}`);
570
+ throw new Error(`Blob download failed: status=${res.status} attempt=${attempt}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`);
571
+ }
572
+ throw new Error(`Blob download failed after retries: status=${lastStatus ?? 'unknown'} attempt=${maxAttempts}/${maxAttempts} blobId=${blobId} filename=${filename ?? 'attachment'} url=${downloadUrl}`);
573
+ }
574
+ /**
575
+ * Actively reconcile recent mailbox contents via JMAP HTTP.
576
+ * Useful as a safety net when the WebSocket stays "connected"
577
+ * but a notification is missed by an intermediate layer.
578
+ */
579
+ async reconcileRecentEmails(limit = 20) {
580
+ if (!this.session) {
581
+ this.session = await this.fetchSession();
582
+ }
583
+ const accountId = this.session.primaryAccounts['urn:ietf:params:jmap:mail']
584
+ ?? Object.keys(this.session.accounts)[0];
585
+ if (!accountId) {
586
+ throw new Error('No mail account available in JMAP session');
587
+ }
588
+ const queryResp = await this.jmapCall([
589
+ [
590
+ 'Email/query',
591
+ {
592
+ accountId,
593
+ sort: [{ property: 'receivedAt', isAscending: false }],
594
+ limit,
595
+ },
596
+ 'qReconcile',
597
+ ],
598
+ ]);
599
+ const queryResult = queryResp.methodResponses.find(([name]) => name === 'Email/query');
600
+ if (!queryResult)
601
+ return 0;
602
+ const ids = (queryResult[1].ids ?? []).slice(0, limit);
603
+ if (ids.length === 0)
604
+ return 0;
605
+ const emailResp = await this.jmapCall([
606
+ [
607
+ 'Email/get',
608
+ {
609
+ accountId,
610
+ ids,
611
+ properties: ['id', 'subject', 'from', 'to', 'headers', 'messageId', 'receivedAt', 'textBody', 'bodyValues', 'attachments'],
612
+ fetchTextBodyValues: true,
613
+ maxBodyValueBytes: 262144,
614
+ },
615
+ 'gReconcile',
616
+ ],
617
+ ]);
618
+ const getResult = emailResp.methodResponses.find(([name]) => name === 'Email/get');
619
+ if (!getResult)
620
+ return 0;
621
+ const emails = getResult[1].list ?? [];
622
+ for (const email of emails.sort((a, b) => {
623
+ const aTs = new Date(a.receivedAt).getTime();
624
+ const bTs = new Date(b.receivedAt).getTime();
625
+ return aTs - bTs;
626
+ })) {
627
+ if (!this.shouldProcessBootstrapEmail(email))
628
+ continue;
629
+ this.processEmail(email);
630
+ }
631
+ return emails.length;
632
+ }
633
+ }
634
+ //# sourceMappingURL=jmap-push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jmap-push.js","sourceRoot":"","sources":["../src/jmap-push.ts"],"names":[],"mappings":"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"}