@bobfrankston/mailx-imap 0.1.112 → 0.1.114
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/index.d.ts +4 -1
- package/index.js +76 -8
- package/package.json +5 -5
package/index.d.ts
CHANGED
|
@@ -701,7 +701,10 @@ export declare class ImapManager extends EventEmitter {
|
|
|
701
701
|
* contacts added or removed in this run. */
|
|
702
702
|
syncGoogleContacts(accountId: string): Promise<number>;
|
|
703
703
|
private syncGoogleContactsImpl;
|
|
704
|
-
/** Sync contacts for all OAuth accounts
|
|
704
|
+
/** Sync contacts for all GOOGLE OAuth accounts. The People API only
|
|
705
|
+
* accepts Google tokens — feeding it an Outlook/AOL OAuth token just
|
|
706
|
+
* logged `API error for outlook: 401` on every periodic tick. Outlook
|
|
707
|
+
* contacts belong to the Graph provider (blocked on Azure app reg). */
|
|
705
708
|
syncAllContacts(): Promise<void>;
|
|
706
709
|
/** Shut down all watchers and timers */
|
|
707
710
|
shutdown(): Promise<void>;
|
package/index.js
CHANGED
|
@@ -906,7 +906,54 @@ export class ImapManager extends EventEmitter {
|
|
|
906
906
|
// to re-enable for a debugging session. Default is quiet.
|
|
907
907
|
const imapTrace = process.env.RMFMAIL_IMAP_TRACE === "1";
|
|
908
908
|
const cfgWithVerbose = (imapTrace && (purpose === "ops" || purpose === "fast")) ? { ...config, verbose: true } : config;
|
|
909
|
-
|
|
909
|
+
// C121: connect-phase progress. Wrap the injected transport so the
|
|
910
|
+
// socket phase (DNS+TCP+TLS inside transport.connect) is visibly
|
|
911
|
+
// distinct from the IMAP handshake (greeting + LOGIN, which run
|
|
912
|
+
// inside client.connect after the socket is up). The client shows
|
|
913
|
+
// "Connecting to <host> (<phase>, N.Ns)" from these events, so
|
|
914
|
+
// "DNS/TCP/TLS hung" vs "greeting missing" vs "LOGIN slow" are
|
|
915
|
+
// distinguishable at a glance instead of one opaque long wait.
|
|
916
|
+
let connT0 = Date.now();
|
|
917
|
+
const phaseT = {};
|
|
918
|
+
const emitPhase = (phase, detail) => {
|
|
919
|
+
phaseT[phase] = Date.now();
|
|
920
|
+
this.emit("connectProgress", accountId, {
|
|
921
|
+
host, purpose, phase, detail,
|
|
922
|
+
elapsedMs: Date.now() - connT0,
|
|
923
|
+
});
|
|
924
|
+
};
|
|
925
|
+
const phaseTimings = () => Object.entries(phaseT).map(([p, t]) => `${p}@${t - connT0}ms`).join(" ");
|
|
926
|
+
const wrappedFactory = () => {
|
|
927
|
+
const t = this.transportFactory();
|
|
928
|
+
const origTransportConnect = t.connect.bind(t);
|
|
929
|
+
t.connect = async (h, p, tls, sni) => {
|
|
930
|
+
emitPhase("socket");
|
|
931
|
+
await origTransportConnect(h, p, tls, sni);
|
|
932
|
+
emitPhase("handshake");
|
|
933
|
+
};
|
|
934
|
+
return t;
|
|
935
|
+
};
|
|
936
|
+
client = new CompatImapClient(cfgWithVerbose, wrappedFactory);
|
|
937
|
+
const origClientConnect = client.connect?.bind(client);
|
|
938
|
+
if (origClientConnect) {
|
|
939
|
+
client.connect = async (...a) => {
|
|
940
|
+
// Clock starts when the connect actually begins — clients
|
|
941
|
+
// are constructed eagerly but connect lazily on first use.
|
|
942
|
+
connT0 = Date.now();
|
|
943
|
+
try {
|
|
944
|
+
const r = await origClientConnect(...a);
|
|
945
|
+
emitPhase("done");
|
|
946
|
+
const total = Date.now() - connT0;
|
|
947
|
+
if (total > 3000)
|
|
948
|
+
console.log(` [conn-slow] ${accountId} (${purpose}): connect took ${total}ms — ${phaseTimings()}`);
|
|
949
|
+
return r;
|
|
950
|
+
}
|
|
951
|
+
catch (e) {
|
|
952
|
+
emitPhase("failed", e?.message || String(e));
|
|
953
|
+
throw e;
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
}
|
|
910
957
|
}
|
|
911
958
|
catch (e) {
|
|
912
959
|
releaseHostSlot();
|
|
@@ -5728,10 +5775,11 @@ export class ImapManager extends EventEmitter {
|
|
|
5728
5775
|
// Compare after the debounce window and only emit on a real change.
|
|
5729
5776
|
const normalize = (s) => s.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").replace(/[ \t\r\n]+$/, "");
|
|
5730
5777
|
const lastContent = new Map();
|
|
5731
|
-
|
|
5778
|
+
const watched = new Set();
|
|
5779
|
+
const watchOne = (filename) => {
|
|
5732
5780
|
const full = path.join(configDir, filename);
|
|
5733
5781
|
if (!fs.existsSync(full))
|
|
5734
|
-
|
|
5782
|
+
return false;
|
|
5735
5783
|
try {
|
|
5736
5784
|
lastContent.set(filename, normalize(fs.readFileSync(full, "utf-8")));
|
|
5737
5785
|
}
|
|
@@ -5773,11 +5821,16 @@ export class ImapManager extends EventEmitter {
|
|
|
5773
5821
|
}, 500));
|
|
5774
5822
|
});
|
|
5775
5823
|
this.configWatchers.push(watcher);
|
|
5824
|
+
watched.add(filename);
|
|
5825
|
+
return true;
|
|
5776
5826
|
}
|
|
5777
5827
|
catch (e) {
|
|
5778
5828
|
console.error(` [watch] Failed to watch ${filename}: ${e.message}`);
|
|
5829
|
+
return false;
|
|
5779
5830
|
}
|
|
5780
|
-
}
|
|
5831
|
+
};
|
|
5832
|
+
for (const filename of files)
|
|
5833
|
+
watchOne(filename);
|
|
5781
5834
|
// GDrive has no push/watch for arbitrary Drive files, so edits on
|
|
5782
5835
|
// another device (or via Drive web) never fire fs.watch locally.
|
|
5783
5836
|
// Poll the cloud copies of the replicated-to-cloud config files
|
|
@@ -5828,6 +5881,14 @@ export class ImapManager extends EventEmitter {
|
|
|
5828
5881
|
}
|
|
5829
5882
|
fs.writeFileSync(localPath, cloudContent);
|
|
5830
5883
|
console.log(` [cloud-poll] ${filename} updated from cloud copy`);
|
|
5884
|
+
// A file that didn't exist at startup never got an
|
|
5885
|
+
// fs.watch (watchOne skipped it), so the write above
|
|
5886
|
+
// fires nothing and the cloud edit would be applied to
|
|
5887
|
+
// disk but never loaded. Register the watcher now and
|
|
5888
|
+
// emit configChanged directly for this first change.
|
|
5889
|
+
if (!watched.has(filename) && watchOne(filename)) {
|
|
5890
|
+
this.emit("configChanged", filename);
|
|
5891
|
+
}
|
|
5831
5892
|
}
|
|
5832
5893
|
catch (e) {
|
|
5833
5894
|
console.log(` [cloud-poll] ${filename} check skipped: ${e?.message || e}`);
|
|
@@ -5982,13 +6043,20 @@ export class ImapManager extends EventEmitter {
|
|
|
5982
6043
|
}
|
|
5983
6044
|
return changed;
|
|
5984
6045
|
}
|
|
5985
|
-
/** Sync contacts for all OAuth accounts
|
|
6046
|
+
/** Sync contacts for all GOOGLE OAuth accounts. The People API only
|
|
6047
|
+
* accepts Google tokens — feeding it an Outlook/AOL OAuth token just
|
|
6048
|
+
* logged `API error for outlook: 401` on every periodic tick. Outlook
|
|
6049
|
+
* contacts belong to the Graph provider (blocked on Azure app reg). */
|
|
5986
6050
|
async syncAllContacts() {
|
|
5987
6051
|
const settings = loadSettings();
|
|
5988
6052
|
for (const account of settings.accounts) {
|
|
5989
|
-
if (account.imap.auth
|
|
5990
|
-
|
|
5991
|
-
|
|
6053
|
+
if (account.imap.auth !== "oauth2")
|
|
6054
|
+
continue;
|
|
6055
|
+
if (!(account.enabled || account.syncContacts))
|
|
6056
|
+
continue;
|
|
6057
|
+
if (!this.isGmailAccount(account.id))
|
|
6058
|
+
continue;
|
|
6059
|
+
await this.syncGoogleContacts(account.id);
|
|
5992
6060
|
}
|
|
5993
6061
|
}
|
|
5994
6062
|
/** Shut down all watchers and timers */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.114",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.22",
|
|
13
|
-
"@bobfrankston/mailx-settings": "^0.1.
|
|
14
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
13
|
+
"@bobfrankston/mailx-settings": "^0.1.34",
|
|
14
|
+
"@bobfrankston/mailx-store": "^0.1.58",
|
|
15
15
|
"@bobfrankston/iflow-direct": "^0.1.56",
|
|
16
16
|
"@bobfrankston/tcp-transport": "^0.1.7",
|
|
17
17
|
"@bobfrankston/smtp-direct": "^0.1.9",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
".transformedSnapshot": {
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.22",
|
|
41
|
-
"@bobfrankston/mailx-settings": "^0.1.
|
|
42
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
41
|
+
"@bobfrankston/mailx-settings": "^0.1.34",
|
|
42
|
+
"@bobfrankston/mailx-store": "^0.1.58",
|
|
43
43
|
"@bobfrankston/iflow-direct": "^0.1.56",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.7",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.9",
|