@bobfrankston/rmfmail 1.0.467
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 +429 -0
- package/bin/build-icon-ico.js +283 -0
- package/bin/lean-accounts.js +172 -0
- package/bin/mailx.js +1580 -0
- package/bin/mailx.js.map +1 -0
- package/bin/mailx.ts +1549 -0
- package/bin/postinstall.js +39 -0
- package/bin/postinstall.js.map +1 -0
- package/bin/postinstall.ts +41 -0
- package/bin/tsconfig.json +10 -0
- package/client/.gitattributes +10 -0
- package/client/.msger-window.json +1 -0
- package/client/android.html +226 -0
- package/client/app.js +3400 -0
- package/client/app.js.map +1 -0
- package/client/app.ts +3190 -0
- package/client/components/address-book.js +199 -0
- package/client/components/address-book.js.map +1 -0
- package/client/components/address-book.ts +204 -0
- package/client/components/alarms.js +299 -0
- package/client/components/alarms.js.map +1 -0
- package/client/components/alarms.ts +276 -0
- package/client/components/calendar-sidebar.js +508 -0
- package/client/components/calendar-sidebar.js.map +1 -0
- package/client/components/calendar-sidebar.ts +474 -0
- package/client/components/calendar.js +217 -0
- package/client/components/calendar.js.map +1 -0
- package/client/components/calendar.ts +211 -0
- package/client/components/context-menu.js +80 -0
- package/client/components/context-menu.js.map +1 -0
- package/client/components/context-menu.ts +95 -0
- package/client/components/folder-picker.js +119 -0
- package/client/components/folder-picker.js.map +1 -0
- package/client/components/folder-picker.ts +127 -0
- package/client/components/folder-tree.js +1093 -0
- package/client/components/folder-tree.js.map +1 -0
- package/client/components/folder-tree.ts +1069 -0
- package/client/components/message-list.js +1140 -0
- package/client/components/message-list.js.map +1 -0
- package/client/components/message-list.ts +1129 -0
- package/client/components/message-viewer.js +1291 -0
- package/client/components/message-viewer.js.map +1 -0
- package/client/components/message-viewer.ts +1257 -0
- package/client/components/outbox-view.js +104 -0
- package/client/components/outbox-view.js.map +1 -0
- package/client/components/outbox-view.ts +102 -0
- package/client/components/tasks.js +261 -0
- package/client/components/tasks.js.map +1 -0
- package/client/components/tasks.ts +234 -0
- package/client/compose/compose.css +560 -0
- package/client/compose/compose.html +52 -0
- package/client/compose/compose.js +1289 -0
- package/client/compose/compose.js.map +1 -0
- package/client/compose/compose.ts +1231 -0
- package/client/compose/editor.js +616 -0
- package/client/compose/editor.js.map +1 -0
- package/client/compose/editor.ts +599 -0
- package/client/compose/ghost-text.js +122 -0
- package/client/compose/ghost-text.js.map +1 -0
- package/client/compose/ghost-text.ts +140 -0
- package/client/favicon.svg +11 -0
- package/client/icon.ico +0 -0
- package/client/icon.png +0 -0
- package/client/index.html +230 -0
- package/client/lib/android-bootstrap.js +9 -0
- package/client/lib/android-bootstrap.js.map +1 -0
- package/client/lib/android-bootstrap.ts +9 -0
- package/client/lib/api-client.js +378 -0
- package/client/lib/api-client.js.map +1 -0
- package/client/lib/api-client.ts +439 -0
- package/client/lib/local-service.js +603 -0
- package/client/lib/local-service.js.map +1 -0
- package/client/lib/local-service.ts +646 -0
- package/client/lib/local-store.js +214 -0
- package/client/lib/local-store.js.map +1 -0
- package/client/lib/local-store.ts +283 -0
- package/client/lib/mailxapi.js +304 -0
- package/client/lib/message-state.js +132 -0
- package/client/lib/message-state.js.map +1 -0
- package/client/lib/message-state.ts +160 -0
- package/client/package.json +16 -0
- package/client/styles/components.css +2049 -0
- package/client/styles/layout.css +332 -0
- package/client/styles/variables.css +85 -0
- package/client/tsconfig.json +19 -0
- package/package.json +124 -0
- package/packages/mailx-api/.gitattributes +10 -0
- package/packages/mailx-api/index.d.ts +10 -0
- package/packages/mailx-api/index.d.ts.map +1 -0
- package/packages/mailx-api/index.js +322 -0
- package/packages/mailx-api/index.js.map +1 -0
- package/packages/mailx-api/index.ts +283 -0
- package/packages/mailx-api/package.json +27 -0
- package/packages/mailx-api/tsconfig.json +9 -0
- package/packages/mailx-api/tsconfig.tsbuildinfo +1 -0
- package/packages/mailx-compose/.gitattributes +10 -0
- package/packages/mailx-compose/index.d.ts +21 -0
- package/packages/mailx-compose/index.d.ts.map +1 -0
- package/packages/mailx-compose/index.js +61 -0
- package/packages/mailx-compose/index.js.map +1 -0
- package/packages/mailx-compose/index.ts +85 -0
- package/packages/mailx-compose/package.json +18 -0
- package/packages/mailx-compose/tsconfig.json +9 -0
- package/packages/mailx-core/index.d.ts +139 -0
- package/packages/mailx-core/index.d.ts.map +1 -0
- package/packages/mailx-core/index.js +403 -0
- package/packages/mailx-core/index.js.map +1 -0
- package/packages/mailx-core/index.ts +424 -0
- package/packages/mailx-core/ipc.d.ts +13 -0
- package/packages/mailx-core/ipc.d.ts.map +1 -0
- package/packages/mailx-core/ipc.js +56 -0
- package/packages/mailx-core/ipc.js.map +1 -0
- package/packages/mailx-core/ipc.ts +62 -0
- package/packages/mailx-core/package.json +18 -0
- package/packages/mailx-core/tsconfig.json +9 -0
- package/packages/mailx-host/.gitattributes +10 -0
- package/packages/mailx-host/index.d.ts +21 -0
- package/packages/mailx-host/index.d.ts.map +1 -0
- package/packages/mailx-host/index.js +29 -0
- package/packages/mailx-host/index.js.map +1 -0
- package/packages/mailx-host/index.ts +38 -0
- package/packages/mailx-host/package.json +23 -0
- package/packages/mailx-host/tsconfig.json +9 -0
- package/packages/mailx-host/types-shim.d.ts +14 -0
- package/packages/mailx-imap/.gitattributes +10 -0
- package/packages/mailx-imap/index.d.ts +442 -0
- package/packages/mailx-imap/index.d.ts.map +1 -0
- package/packages/mailx-imap/index.js +3684 -0
- package/packages/mailx-imap/index.js.map +1 -0
- package/packages/mailx-imap/index.ts +3652 -0
- package/packages/mailx-imap/package-lock.json +131 -0
- package/packages/mailx-imap/package.json +28 -0
- package/packages/mailx-imap/providers/gmail-api.d.ts +8 -0
- package/packages/mailx-imap/providers/gmail-api.d.ts.map +1 -0
- package/packages/mailx-imap/providers/gmail-api.js +8 -0
- package/packages/mailx-imap/providers/gmail-api.js.map +1 -0
- package/packages/mailx-imap/providers/gmail-api.ts +8 -0
- package/packages/mailx-imap/providers/outlook-api.ts +7 -0
- package/packages/mailx-imap/providers/types.d.ts +9 -0
- package/packages/mailx-imap/providers/types.d.ts.map +1 -0
- package/packages/mailx-imap/providers/types.js +9 -0
- package/packages/mailx-imap/providers/types.js.map +1 -0
- package/packages/mailx-imap/providers/types.ts +9 -0
- package/packages/mailx-imap/tsconfig.json +9 -0
- package/packages/mailx-imap/tsconfig.tsbuildinfo +1 -0
- package/packages/mailx-send/.gitattributes +10 -0
- package/packages/mailx-send/README.md +217 -0
- package/packages/mailx-send/cli-queue.d.ts +11 -0
- package/packages/mailx-send/cli-queue.d.ts.map +1 -0
- package/packages/mailx-send/cli-queue.js +59 -0
- package/packages/mailx-send/cli-queue.js.map +1 -0
- package/packages/mailx-send/cli-queue.ts +62 -0
- package/packages/mailx-send/cli-send.d.ts +17 -0
- package/packages/mailx-send/cli-send.d.ts.map +1 -0
- package/packages/mailx-send/cli-send.js +75 -0
- package/packages/mailx-send/cli-send.js.map +1 -0
- package/packages/mailx-send/cli-send.ts +83 -0
- package/packages/mailx-send/cli.d.ts +22 -0
- package/packages/mailx-send/cli.d.ts.map +1 -0
- package/packages/mailx-send/cli.js +115 -0
- package/packages/mailx-send/cli.js.map +1 -0
- package/packages/mailx-send/cli.ts +126 -0
- package/packages/mailx-send/index.d.ts +77 -0
- package/packages/mailx-send/index.d.ts.map +1 -0
- package/packages/mailx-send/index.js +264 -0
- package/packages/mailx-send/index.js.map +1 -0
- package/packages/mailx-send/index.ts +333 -0
- package/packages/mailx-send/mailsend/README.md +133 -0
- package/packages/mailx-send/mailsend/cli.d.ts +12 -0
- package/packages/mailx-send/mailsend/cli.d.ts.map +1 -0
- package/packages/mailx-send/mailsend/cli.js +70 -0
- package/packages/mailx-send/mailsend/cli.js.map +1 -0
- package/packages/mailx-send/mailsend/cli.ts +81 -0
- package/packages/mailx-send/mailsend/index.d.ts +77 -0
- package/packages/mailx-send/mailsend/index.d.ts.map +1 -0
- package/packages/mailx-send/mailsend/index.js +264 -0
- package/packages/mailx-send/mailsend/index.js.map +1 -0
- package/packages/mailx-send/mailsend/index.ts +333 -0
- package/packages/mailx-send/mailsend/package-lock.json +65 -0
- package/packages/mailx-send/mailsend/package.json +26 -0
- package/packages/mailx-send/mailsend/tsconfig.json +21 -0
- package/packages/mailx-send/package-lock.json +65 -0
- package/packages/mailx-send/package.json +37 -0
- package/packages/mailx-send/tsconfig.json +21 -0
- package/packages/mailx-server/.gitattributes +10 -0
- package/packages/mailx-server/index.d.ts +8 -0
- package/packages/mailx-server/index.d.ts.map +1 -0
- package/packages/mailx-server/index.js +397 -0
- package/packages/mailx-server/index.js.map +1 -0
- package/packages/mailx-server/index.ts +429 -0
- package/packages/mailx-server/package.json +28 -0
- package/packages/mailx-server/tsconfig.json +9 -0
- package/packages/mailx-server/tsconfig.tsbuildinfo +1 -0
- package/packages/mailx-service/google-sync.d.ts +96 -0
- package/packages/mailx-service/google-sync.d.ts.map +1 -0
- package/packages/mailx-service/google-sync.js +153 -0
- package/packages/mailx-service/google-sync.js.map +1 -0
- package/packages/mailx-service/google-sync.ts +238 -0
- package/packages/mailx-service/index.d.ts +366 -0
- package/packages/mailx-service/index.d.ts.map +1 -0
- package/packages/mailx-service/index.js +2589 -0
- package/packages/mailx-service/index.js.map +1 -0
- package/packages/mailx-service/index.ts +2512 -0
- package/packages/mailx-service/jsonrpc.d.ts +25 -0
- package/packages/mailx-service/jsonrpc.d.ts.map +1 -0
- package/packages/mailx-service/jsonrpc.js +238 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -0
- package/packages/mailx-service/jsonrpc.ts +268 -0
- package/packages/mailx-service/package.json +22 -0
- package/packages/mailx-service/tsconfig.json +9 -0
- package/packages/mailx-settings/.gitattributes +10 -0
- package/packages/mailx-settings/cloud.d.ts +47 -0
- package/packages/mailx-settings/cloud.d.ts.map +1 -0
- package/packages/mailx-settings/cloud.js +408 -0
- package/packages/mailx-settings/cloud.js.map +1 -0
- package/packages/mailx-settings/cloud.ts +393 -0
- package/packages/mailx-settings/index.d.ts +140 -0
- package/packages/mailx-settings/index.d.ts.map +1 -0
- package/packages/mailx-settings/index.js +872 -0
- package/packages/mailx-settings/index.js.map +1 -0
- package/packages/mailx-settings/index.ts +908 -0
- package/packages/mailx-settings/package.json +20 -0
- package/packages/mailx-settings/tsconfig.json +9 -0
- package/packages/mailx-settings/tsconfig.tsbuildinfo +1 -0
- package/packages/mailx-store/.gitattributes +10 -0
- package/packages/mailx-store/db.d.ts +346 -0
- package/packages/mailx-store/db.d.ts.map +1 -0
- package/packages/mailx-store/db.js +1796 -0
- package/packages/mailx-store/db.js.map +1 -0
- package/packages/mailx-store/db.ts +2007 -0
- package/packages/mailx-store/file-store.d.ts +36 -0
- package/packages/mailx-store/file-store.d.ts.map +1 -0
- package/packages/mailx-store/file-store.js +80 -0
- package/packages/mailx-store/file-store.js.map +1 -0
- package/packages/mailx-store/file-store.ts +82 -0
- package/packages/mailx-store/index.d.ts +7 -0
- package/packages/mailx-store/index.d.ts.map +1 -0
- package/packages/mailx-store/index.js +7 -0
- package/packages/mailx-store/index.js.map +1 -0
- package/packages/mailx-store/index.ts +7 -0
- package/packages/mailx-store/package.json +19 -0
- package/packages/mailx-store/tsconfig.json +9 -0
- package/packages/mailx-store/tsconfig.tsbuildinfo +1 -0
- package/packages/mailx-store-web/android-bootstrap.d.ts +16 -0
- package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -0
- package/packages/mailx-store-web/android-bootstrap.js +1247 -0
- package/packages/mailx-store-web/android-bootstrap.js.map +1 -0
- package/packages/mailx-store-web/android-bootstrap.ts +1262 -0
- package/packages/mailx-store-web/db.d.ts +132 -0
- package/packages/mailx-store-web/db.d.ts.map +1 -0
- package/packages/mailx-store-web/db.js +642 -0
- package/packages/mailx-store-web/db.js.map +1 -0
- package/packages/mailx-store-web/db.ts +756 -0
- package/packages/mailx-store-web/gmail-api-web.d.ts +11 -0
- package/packages/mailx-store-web/gmail-api-web.d.ts.map +1 -0
- package/packages/mailx-store-web/gmail-api-web.js +11 -0
- package/packages/mailx-store-web/gmail-api-web.js.map +1 -0
- package/packages/mailx-store-web/gmail-api-web.ts +11 -0
- package/packages/mailx-store-web/imap-web-provider.d.ts +33 -0
- package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -0
- package/packages/mailx-store-web/imap-web-provider.js +140 -0
- package/packages/mailx-store-web/imap-web-provider.js.map +1 -0
- package/packages/mailx-store-web/imap-web-provider.ts +156 -0
- package/packages/mailx-store-web/index.d.ts +10 -0
- package/packages/mailx-store-web/index.d.ts.map +1 -0
- package/packages/mailx-store-web/index.js +10 -0
- package/packages/mailx-store-web/index.js.map +1 -0
- package/packages/mailx-store-web/index.ts +10 -0
- package/packages/mailx-store-web/main-thread-host.d.ts +15 -0
- package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -0
- package/packages/mailx-store-web/main-thread-host.js +292 -0
- package/packages/mailx-store-web/main-thread-host.js.map +1 -0
- package/packages/mailx-store-web/main-thread-host.ts +322 -0
- package/packages/mailx-store-web/package.json +23 -0
- package/packages/mailx-store-web/provider-types.d.ts +7 -0
- package/packages/mailx-store-web/provider-types.d.ts.map +1 -0
- package/packages/mailx-store-web/provider-types.js +7 -0
- package/packages/mailx-store-web/provider-types.js.map +1 -0
- package/packages/mailx-store-web/provider-types.ts +7 -0
- package/packages/mailx-store-web/sql-wasm-esm.js +10 -0
- package/packages/mailx-store-web/sql.js.d.ts +29 -0
- package/packages/mailx-store-web/sync-manager.d.ts +68 -0
- package/packages/mailx-store-web/sync-manager.d.ts.map +1 -0
- package/packages/mailx-store-web/sync-manager.js +506 -0
- package/packages/mailx-store-web/sync-manager.js.map +1 -0
- package/packages/mailx-store-web/sync-manager.ts +508 -0
- package/packages/mailx-store-web/tsconfig.json +10 -0
- package/packages/mailx-store-web/web-jsonrpc.d.ts +20 -0
- package/packages/mailx-store-web/web-jsonrpc.d.ts.map +1 -0
- package/packages/mailx-store-web/web-jsonrpc.js +102 -0
- package/packages/mailx-store-web/web-jsonrpc.js.map +1 -0
- package/packages/mailx-store-web/web-jsonrpc.ts +116 -0
- package/packages/mailx-store-web/web-message-store.d.ts +16 -0
- package/packages/mailx-store-web/web-message-store.d.ts.map +1 -0
- package/packages/mailx-store-web/web-message-store.js +89 -0
- package/packages/mailx-store-web/web-message-store.js.map +1 -0
- package/packages/mailx-store-web/web-message-store.ts +97 -0
- package/packages/mailx-store-web/web-service.d.ts +111 -0
- package/packages/mailx-store-web/web-service.d.ts.map +1 -0
- package/packages/mailx-store-web/web-service.js +542 -0
- package/packages/mailx-store-web/web-service.js.map +1 -0
- package/packages/mailx-store-web/web-service.ts +616 -0
- package/packages/mailx-store-web/web-settings.d.ts +83 -0
- package/packages/mailx-store-web/web-settings.d.ts.map +1 -0
- package/packages/mailx-store-web/web-settings.js +491 -0
- package/packages/mailx-store-web/web-settings.js.map +1 -0
- package/packages/mailx-store-web/web-settings.ts +522 -0
- package/packages/mailx-store-web/worker-bundle.js +6838 -0
- package/packages/mailx-store-web/worker-entry.d.ts +8 -0
- package/packages/mailx-store-web/worker-entry.d.ts.map +1 -0
- package/packages/mailx-store-web/worker-entry.js +187 -0
- package/packages/mailx-store-web/worker-entry.js.map +1 -0
- package/packages/mailx-store-web/worker-entry.ts +215 -0
- package/packages/mailx-store-web/worker-tcp-transport.d.ts +28 -0
- package/packages/mailx-store-web/worker-tcp-transport.d.ts.map +1 -0
- package/packages/mailx-store-web/worker-tcp-transport.js +98 -0
- package/packages/mailx-store-web/worker-tcp-transport.js.map +1 -0
- package/packages/mailx-store-web/worker-tcp-transport.ts +101 -0
- package/packages/mailx-types/.gitattributes +10 -0
- package/packages/mailx-types/index.d.ts +319 -0
- package/packages/mailx-types/index.d.ts.map +1 -0
- package/packages/mailx-types/index.js +243 -0
- package/packages/mailx-types/index.js.map +1 -0
- package/packages/mailx-types/index.ts +498 -0
- package/packages/mailx-types/package.json +16 -0
- package/packages/mailx-types/tsconfig.json +9 -0
- package/packages/mailx-types/tsconfig.tsbuildinfo +1 -0
- package/todo.json +13 -0
- package/tsconfig.base.json +31 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bobfrankston/mailx-server
|
|
3
|
+
* Express server: serves client, mounts API, manages WebSocket push.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import express from "express";
|
|
7
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import { MailxDB } from "@bobfrankston/mailx-store";
|
|
11
|
+
import { ImapManager } from "@bobfrankston/mailx-imap";
|
|
12
|
+
import { createApiRouter } from "@bobfrankston/mailx-api";
|
|
13
|
+
import { loadSettings, loadAccountsAsync, getConfigDir, getStorePath, getSharedDir, getStorageInfo } from "@bobfrankston/mailx-settings";
|
|
14
|
+
import type { WsEvent } from "@bobfrankston/mailx-types";
|
|
15
|
+
import { ports } from "@bobfrankston/miscinfo";
|
|
16
|
+
import { createServer } from "node:http";
|
|
17
|
+
|
|
18
|
+
const PORT = ports.mailx;
|
|
19
|
+
|
|
20
|
+
// ── File logging ──
|
|
21
|
+
const logDir = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".rmfmail", "logs");
|
|
22
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
23
|
+
// Rotate: delete logs older than 7 days
|
|
24
|
+
try {
|
|
25
|
+
for (const f of fs.readdirSync(logDir).filter(f => f.startsWith("mailx-") && f.endsWith(".log"))) {
|
|
26
|
+
const stat = fs.statSync(path.join(logDir, f));
|
|
27
|
+
if (Date.now() - stat.mtimeMs > 7 * 86400000) fs.unlinkSync(path.join(logDir, f));
|
|
28
|
+
}
|
|
29
|
+
} catch { /* ignore cleanup errors */ }
|
|
30
|
+
const logDate = new Date().toISOString().slice(0, 10);
|
|
31
|
+
const logPath = path.join(logDir, `mailx-${logDate}.log`);
|
|
32
|
+
const logStream = fs.createWriteStream(logPath, { flags: "a" });
|
|
33
|
+
const origLog = console.log;
|
|
34
|
+
const origErr = console.error;
|
|
35
|
+
function logTs(): string { return new Date().toLocaleString("se", { hour12: false }); }
|
|
36
|
+
console.log = (...args: any[]) => {
|
|
37
|
+
const msg = `${logTs()} ${args.join(" ")}`;
|
|
38
|
+
origLog(msg);
|
|
39
|
+
logStream.write(msg + "\n");
|
|
40
|
+
};
|
|
41
|
+
console.error = (...args: any[]) => {
|
|
42
|
+
const msg = `${logTs()} ERROR ${args.join(" ")}`;
|
|
43
|
+
origErr(msg);
|
|
44
|
+
logStream.write(msg + "\n");
|
|
45
|
+
};
|
|
46
|
+
// Read version from root package.json (the published version)
|
|
47
|
+
const rootPkg = JSON.parse(fs.readFileSync(path.join(import.meta.dirname, "..", "..", "package.json"), "utf-8"));
|
|
48
|
+
const SERVER_VERSION = rootPkg.version;
|
|
49
|
+
|
|
50
|
+
// ── Initialize ──
|
|
51
|
+
// No initLocalConfig() here — config is created when user adds an account (initCloudConfig).
|
|
52
|
+
// On fresh install, loadSettings() returns defaults and the setup form handles configuration.
|
|
53
|
+
|
|
54
|
+
let settings = loadSettings();
|
|
55
|
+
if (settings.accounts.length === 0) {
|
|
56
|
+
// Try cloud API fallback (Google Drive, OneDrive) if filesystem mount not available
|
|
57
|
+
const cloudAccounts = await loadAccountsAsync();
|
|
58
|
+
if (cloudAccounts.length > 0) {
|
|
59
|
+
settings = { ...settings, accounts: cloudAccounts };
|
|
60
|
+
console.log(` Loaded ${cloudAccounts.length} account(s) from cloud API`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log(" No accounts configured. Open http://127.0.0.1:9333 to add your email account.");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const dbDir = getConfigDir();
|
|
66
|
+
const db = new MailxDB(dbDir);
|
|
67
|
+
import { NodeTransport } from "@bobfrankston/iflow-node";
|
|
68
|
+
const imapManager = new ImapManager(db, () => new NodeTransport());
|
|
69
|
+
|
|
70
|
+
// ── Express App ──
|
|
71
|
+
|
|
72
|
+
const app = express();
|
|
73
|
+
app.use(express.json({ limit: "Infinity" }));
|
|
74
|
+
|
|
75
|
+
// Optional token gate — required whenever the server binds to anything other
|
|
76
|
+
// than a loopback address. Set via `MAILX_SERVER_TOKEN=<secret>` (or the
|
|
77
|
+
// shorter `MAILX_TOKEN`). When the server is loopback-only (the default), the
|
|
78
|
+
// gate is a no-op since nothing outside the machine can reach it. When bound
|
|
79
|
+
// externally (`MAILX_SERVER_HOST=0.0.0.0` or `--external`), connections must
|
|
80
|
+
// present the token in either `?t=<token>` or the `x-mailx-token` header. No
|
|
81
|
+
// token configured + external bind → server refuses to start (safer than
|
|
82
|
+
// serving open).
|
|
83
|
+
const SERVER_TOKEN = process.env.MAILX_SERVER_TOKEN || process.env.MAILX_TOKEN || "";
|
|
84
|
+
const SERVER_HOST = process.env.MAILX_SERVER_HOST || "";
|
|
85
|
+
const IS_EXTERNAL_BIND = SERVER_HOST && SERVER_HOST !== "127.0.0.1" && SERVER_HOST !== "localhost" && SERVER_HOST !== "::1";
|
|
86
|
+
if (IS_EXTERNAL_BIND && !SERVER_TOKEN) {
|
|
87
|
+
console.error("[server] Refusing to bind externally without MAILX_SERVER_TOKEN. Set the env var or drop the external host.");
|
|
88
|
+
process.exit(2);
|
|
89
|
+
}
|
|
90
|
+
app.use((req, res, next) => {
|
|
91
|
+
if (!IS_EXTERNAL_BIND) return next();
|
|
92
|
+
// Allow the bare static file fetch so the login page can render; every
|
|
93
|
+
// /api/* path requires the token.
|
|
94
|
+
if (!req.path.startsWith("/api/")) return next();
|
|
95
|
+
const provided = (req.query.t as string) || req.header("x-mailx-token") || "";
|
|
96
|
+
if (provided !== SERVER_TOKEN) {
|
|
97
|
+
res.status(401).json({ error: "missing or invalid token" });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
next();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Request logging
|
|
104
|
+
app.use((req, res, next) => {
|
|
105
|
+
const start = Date.now();
|
|
106
|
+
res.on("finish", () => {
|
|
107
|
+
const ms = Date.now() - start;
|
|
108
|
+
// Skip noisy polling endpoints
|
|
109
|
+
if (req.path.endsWith("/sync/pending")) return;
|
|
110
|
+
console.log(` ${req.method} ${req.path} ${res.statusCode} ${ms}ms`);
|
|
111
|
+
});
|
|
112
|
+
next();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Serve client static files
|
|
116
|
+
const clientDir = path.join(import.meta.dirname, "..", "..", "client");
|
|
117
|
+
const rootDir = path.join(import.meta.dirname, "..", "..");
|
|
118
|
+
app.use(express.static(clientDir, { etag: false, lastModified: false, maxAge: 0 }));
|
|
119
|
+
app.use("/node_modules", express.static(path.join(rootDir, "node_modules"), { etag: false, lastModified: false, maxAge: 0 }));
|
|
120
|
+
|
|
121
|
+
// Mount API
|
|
122
|
+
const apiRouter = createApiRouter(db, imapManager);
|
|
123
|
+
app.use("/api", apiRouter);
|
|
124
|
+
|
|
125
|
+
app.get("/api/version", (req, res) => {
|
|
126
|
+
const storage = getStorageInfo();
|
|
127
|
+
const imapAccounts = imapManager.getAccountCount();
|
|
128
|
+
const dbAccounts = db.getAccounts().length;
|
|
129
|
+
// Warn if DB has accounts but IMAP has none — stale DB, settings missing
|
|
130
|
+
const settingsError = (dbAccounts > 0 && imapAccounts === 0)
|
|
131
|
+
? "No accounts loaded from settings — showing stale data. Check accounts.jsonc on your cloud drive."
|
|
132
|
+
: undefined;
|
|
133
|
+
res.json({ version: SERVER_VERSION, theme: settings.ui?.theme || "system", storage, imapAccounts, hasAccounts: imapAccounts > 0 || dbAccounts > 0, settingsError });
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
app.all("/info", (req, res) => {
|
|
137
|
+
res.json({ version: SERVER_VERSION, uptime: Math.round(process.uptime()), port: PORT, imap: imapManager.useNativeClient ? "native" : "imapflow" });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
app.get("/status", (req, res) => {
|
|
141
|
+
const accounts = db.getAccounts();
|
|
142
|
+
const pendingSync = db.getTotalPendingSyncCount();
|
|
143
|
+
const uptime = process.uptime();
|
|
144
|
+
const mem = process.memoryUsage();
|
|
145
|
+
|
|
146
|
+
const accountInfo = accounts.map((a: any) => {
|
|
147
|
+
const folders = db.getFolders(a.id);
|
|
148
|
+
const inbox = folders.find((f: any) => f.specialUse === "inbox");
|
|
149
|
+
return {
|
|
150
|
+
id: a.id, name: a.name, folders: folders.length,
|
|
151
|
+
inboxTotal: inbox?.totalCount || 0,
|
|
152
|
+
inboxUnread: inbox?.unreadCount || 0,
|
|
153
|
+
lastSync: a.lastSync ? new Date(a.lastSync).toLocaleString() : "never",
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
res.type("html").send(`<!DOCTYPE html>
|
|
158
|
+
<html><head><meta charset="UTF-8"><title>mailx status</title>
|
|
159
|
+
<meta http-equiv="refresh" content="10">
|
|
160
|
+
<style>body{font-family:system-ui;padding:2rem;max-width:600px;color:#cdd6f4;background:#1e1e2e}
|
|
161
|
+
table{border-collapse:collapse;width:100%}td,th{text-align:left;padding:4px 12px;border-bottom:1px solid #333}
|
|
162
|
+
h1{font-size:1.2rem}h2{font-size:1rem;margin-top:1.5rem}.ok{color:#a6e3a1}.warn{color:#f9e2af}
|
|
163
|
+
a{color:#89b4fa}</style></head>
|
|
164
|
+
<body>
|
|
165
|
+
<h1>mailx status</h1>
|
|
166
|
+
<p>mailx v${SERVER_VERSION}</p>
|
|
167
|
+
<p>Uptime: ${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m | Memory: ${Math.round(mem.rss / 1048576)} MB</p>
|
|
168
|
+
<p>Pending sync: <span class="${pendingSync > 0 ? "warn" : "ok"}">${pendingSync}</span></p>
|
|
169
|
+
<h2>Accounts</h2>
|
|
170
|
+
<table><tr><th>Account</th><th>Folders</th><th>Inbox</th><th>Unread</th><th>Last Sync</th></tr>
|
|
171
|
+
${accountInfo.map((a: any) => `<tr><td>${a.name}</td><td>${a.folders}</td><td>${a.inboxTotal}</td><td>${a.inboxUnread}</td><td>${a.lastSync}</td></tr>`).join("")}
|
|
172
|
+
</table>
|
|
173
|
+
<p style="margin-top:2rem;font-size:0.8rem"><a href="/">Open mailx</a> | Auto-refreshes every 10s</p>
|
|
174
|
+
</body></html>`);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Graceful exit — close IMAP, DB, HTTP then exit
|
|
178
|
+
app.all("/api/exit", (req, res) => {
|
|
179
|
+
res.json({ ok: true });
|
|
180
|
+
setTimeout(() => shutdown(), 100);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Restart server + reload clients
|
|
184
|
+
app.post("/api/restart", (req, res) => {
|
|
185
|
+
res.json({ ok: true });
|
|
186
|
+
broadcast({ type: "reload" });
|
|
187
|
+
setTimeout(async () => {
|
|
188
|
+
console.log(" Restart requested via API");
|
|
189
|
+
await shutdown();
|
|
190
|
+
}, 500);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Rebuild: wipe DB + message store, keep accounts/settings, restart
|
|
194
|
+
app.post("/api/rebuild", (req, res) => {
|
|
195
|
+
res.json({ ok: true });
|
|
196
|
+
broadcast({ type: "reload" });
|
|
197
|
+
setTimeout(async () => {
|
|
198
|
+
console.log(" Rebuild requested — wiping DB and message store...");
|
|
199
|
+
imapManager.stopPeriodicSync();
|
|
200
|
+
try { await imapManager.shutdown(); } catch { /* proceed */ }
|
|
201
|
+
db.close();
|
|
202
|
+
|
|
203
|
+
// Remove DB files
|
|
204
|
+
const dbDir = getConfigDir();
|
|
205
|
+
for (const f of ["mailx.db", "mailx.db-wal", "mailx.db-shm"]) {
|
|
206
|
+
const p = path.join(dbDir, f);
|
|
207
|
+
if (fs.existsSync(p)) { fs.unlinkSync(p); console.log(` Deleted ${f}`); }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Remove message store
|
|
211
|
+
const storePath = getStorePath();
|
|
212
|
+
if (fs.existsSync(storePath)) {
|
|
213
|
+
fs.rmSync(storePath, { recursive: true });
|
|
214
|
+
console.log(` Deleted ${storePath}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
console.log(" Rebuild complete — restarting...");
|
|
218
|
+
server?.close();
|
|
219
|
+
process.exit(0);
|
|
220
|
+
}, 500);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// SPA fallback
|
|
224
|
+
app.get("*", (req, res) => {
|
|
225
|
+
if (!req.path.startsWith("/api"))
|
|
226
|
+
res.sendFile(path.join(clientDir, "index.html"));
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// JSON error handler — all errors return JSON, never HTML
|
|
230
|
+
app.use((err: any, _req: any, res: any, _next: any) => {
|
|
231
|
+
console.error(`ERROR ${err.message}`);
|
|
232
|
+
const status = err.status || err.statusCode || 500;
|
|
233
|
+
res.status(status).json({ error: err.message || "Internal server error" });
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// ── HTTP Server ──
|
|
237
|
+
|
|
238
|
+
let server: ReturnType<typeof createServer>;
|
|
239
|
+
let wss: WebSocketServer;
|
|
240
|
+
|
|
241
|
+
const clients = new Set<WebSocket>();
|
|
242
|
+
|
|
243
|
+
function wireWebSocket(): void {
|
|
244
|
+
wss.on("connection", (ws) => {
|
|
245
|
+
clients.add(ws);
|
|
246
|
+
(ws as any).__alive = true;
|
|
247
|
+
const connected: WsEvent = { type: "connected" };
|
|
248
|
+
ws.send(JSON.stringify(connected));
|
|
249
|
+
|
|
250
|
+
ws.on("pong", () => { (ws as any).__alive = true; });
|
|
251
|
+
ws.on("close", () => clients.delete(ws));
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Heartbeat — detect dead connections, prevent CLOSE_WAIT zombie accumulation
|
|
255
|
+
setInterval(() => {
|
|
256
|
+
for (const ws of clients) {
|
|
257
|
+
if ((ws as any).__alive === false) {
|
|
258
|
+
clients.delete(ws);
|
|
259
|
+
ws.terminate();
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
(ws as any).__alive = false;
|
|
263
|
+
ws.ping();
|
|
264
|
+
}
|
|
265
|
+
}, 30000);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function broadcast(event: WsEvent): void {
|
|
269
|
+
const data = JSON.stringify(event);
|
|
270
|
+
for (const ws of clients) {
|
|
271
|
+
if (ws.readyState === WebSocket.OPEN)
|
|
272
|
+
ws.send(data);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Wire IMAP events to WebSocket broadcasts
|
|
277
|
+
imapManager.on("syncProgress", (accountId: string, phase: string, progress: number) => {
|
|
278
|
+
broadcast({ type: "syncProgress", accountId, phase, progress });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
imapManager.on("folderCountsChanged", (accountId: string, counts: Record<number, { total: number; unread: number }>) => {
|
|
282
|
+
broadcast({ type: "folderCountsChanged", accountId, counts });
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
imapManager.on("folderSynced", (accountId: string, folderId: number, syncedAt: number) => {
|
|
286
|
+
broadcast({ type: "folderSynced", accountId, entries: [{ folderId, syncedAt }] });
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
imapManager.on("syncError", (accountId: string, error: string) => {
|
|
290
|
+
broadcast({ type: "error", message: `${accountId}: ${error}` });
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
imapManager.on("accountError", (accountId: string, error: string, hint: string, isOAuth: boolean) => {
|
|
294
|
+
broadcast({ type: "accountError", accountId, error, hint, isOAuth });
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// ── Startup ──
|
|
298
|
+
|
|
299
|
+
async function start(): Promise<void> {
|
|
300
|
+
console.log("mailx server starting...");
|
|
301
|
+
|
|
302
|
+
// Start HTTP server FIRST so UI is always reachable (even during IMAP startup)
|
|
303
|
+
const externalAccess = process.argv.includes("--external");
|
|
304
|
+
const hostname = externalAccess ? "0.0.0.0" : "127.0.0.1";
|
|
305
|
+
|
|
306
|
+
// Retry listen with backoff — Windows CLOSE_WAIT zombies can hold the port for minutes after a crash
|
|
307
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
308
|
+
server = createServer(app);
|
|
309
|
+
// Prevent CLOSE_WAIT accumulation: short keepAlive timeout + connection close headers
|
|
310
|
+
server.keepAliveTimeout = 5000; // close idle keep-alive connections after 5s
|
|
311
|
+
server.headersTimeout = 10000; // kill connections with no headers after 10s
|
|
312
|
+
// Track connections for clean shutdown (prevents CLOSE_WAIT zombies on Windows)
|
|
313
|
+
server.on("connection", (conn) => {
|
|
314
|
+
openConnections.add(conn);
|
|
315
|
+
conn.on("close", () => openConnections.delete(conn));
|
|
316
|
+
});
|
|
317
|
+
// Suppress EADDRINUSE from bubbling to uncaughtException — we handle it here
|
|
318
|
+
server.on("error", () => {}); // will be replaced by listen handler below
|
|
319
|
+
wss = new WebSocketServer({ server });
|
|
320
|
+
wireWebSocket();
|
|
321
|
+
|
|
322
|
+
const listenResult = await new Promise<"ok" | string>((resolve) => {
|
|
323
|
+
server.removeAllListeners("error");
|
|
324
|
+
server.once("error", (e: any) => { resolve(e.code || e.message); });
|
|
325
|
+
server.listen({ port: PORT, host: hostname, exclusive: false }, () => {
|
|
326
|
+
server.removeAllListeners("error");
|
|
327
|
+
resolve("ok");
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
if (listenResult === "ok") break;
|
|
331
|
+
if (listenResult === "EADDRINUSE" && attempt < 29) {
|
|
332
|
+
const wait = Math.min(2000 + attempt * 1000, 10000);
|
|
333
|
+
console.log(` Port ${PORT} in use (CLOSE_WAIT zombies?) — retry ${attempt + 1}/30 in ${wait / 1000}s...`);
|
|
334
|
+
server.close();
|
|
335
|
+
await new Promise(r => setTimeout(r, wait));
|
|
336
|
+
} else {
|
|
337
|
+
throw new Error(`Cannot bind port ${PORT}: ${listenResult}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
console.log(`mailx server running on http://${hostname}:${PORT}`);
|
|
341
|
+
|
|
342
|
+
// Seed contacts (fast — skips existing)
|
|
343
|
+
const seeded = db.seedContactsFromMessages();
|
|
344
|
+
if (seeded > 0) console.log(` Seeded ${seeded} contacts`);
|
|
345
|
+
|
|
346
|
+
// Search index — rebuild in background (non-blocking)
|
|
347
|
+
setTimeout(() => {
|
|
348
|
+
let ftsCount = 0;
|
|
349
|
+
try { ftsCount = ((db as any).db.prepare("SELECT COUNT(*) as cnt FROM messages_fts").get() as any)?.cnt || 0; } catch { /* */ }
|
|
350
|
+
if (ftsCount === 0) {
|
|
351
|
+
const indexed = db.rebuildSearchIndex();
|
|
352
|
+
if (indexed > 0) console.log(` Search index: ${indexed} messages`);
|
|
353
|
+
}
|
|
354
|
+
}, 5000);
|
|
355
|
+
|
|
356
|
+
// Add configured accounts
|
|
357
|
+
for (const account of settings.accounts) {
|
|
358
|
+
if (!account.enabled && !(account as any).syncContacts) continue;
|
|
359
|
+
try {
|
|
360
|
+
await imapManager.addAccount(account);
|
|
361
|
+
console.log(` Account added: ${account.name} (${account.id})${!account.enabled ? " [contacts only]" : ""}`);
|
|
362
|
+
} catch (e: any) {
|
|
363
|
+
console.error(` Failed to add account ${account.id}: ${e.message}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Initial sync, then start IDLE watchers
|
|
368
|
+
if (settings.accounts.some(a => a.enabled)) {
|
|
369
|
+
console.log(" Starting initial sync...");
|
|
370
|
+
imapManager.syncAll().then(async () => {
|
|
371
|
+
console.log(" Initial sync complete");
|
|
372
|
+
// Start IDLE watchers for instant new-mail notifications
|
|
373
|
+
await imapManager.startWatching();
|
|
374
|
+
// Sync Google Contacts for OAuth accounts
|
|
375
|
+
imapManager.syncAllContacts().catch(e =>
|
|
376
|
+
console.error(` Google Contacts sync error: ${e.message}`)
|
|
377
|
+
);
|
|
378
|
+
}).catch(e => {
|
|
379
|
+
console.error(` Initial sync error: ${e.message}`);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Periodic sync as fallback (IDLE handles most updates)
|
|
384
|
+
imapManager.startPeriodicSync(settings.sync.intervalMinutes);
|
|
385
|
+
|
|
386
|
+
// Outbox worker — processes queued outgoing messages
|
|
387
|
+
imapManager.startOutboxWorker();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ── Graceful Shutdown ──
|
|
391
|
+
|
|
392
|
+
/** Track all open connections so we can destroy them on shutdown (prevents CLOSE_WAIT zombies) */
|
|
393
|
+
const openConnections = new Set<import("node:net").Socket>();
|
|
394
|
+
|
|
395
|
+
async function shutdown(): Promise<void> {
|
|
396
|
+
console.log("\nShutting down...");
|
|
397
|
+
const forceExit = setTimeout(() => { console.log("Force exit"); process.exit(1); }, 3000);
|
|
398
|
+
imapManager.stopPeriodicSync();
|
|
399
|
+
try { await imapManager.shutdown(); } catch { /* proceed */ }
|
|
400
|
+
db.close();
|
|
401
|
+
// Destroy all open connections immediately — prevents CLOSE_WAIT zombies on Windows
|
|
402
|
+
for (const conn of openConnections) {
|
|
403
|
+
conn.destroy();
|
|
404
|
+
}
|
|
405
|
+
openConnections.clear();
|
|
406
|
+
server?.close();
|
|
407
|
+
clearTimeout(forceExit);
|
|
408
|
+
process.exit(0);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
process.on("SIGINT", shutdown);
|
|
412
|
+
process.on("SIGTERM", shutdown);
|
|
413
|
+
process.on("unhandledRejection", (err: any) => {
|
|
414
|
+
console.error("Unhandled rejection:", err?.message || err);
|
|
415
|
+
});
|
|
416
|
+
process.on("uncaughtException", (err) => {
|
|
417
|
+
console.error("FATAL uncaught exception:", err.message);
|
|
418
|
+
console.error(err.stack);
|
|
419
|
+
// Other exceptions: stay alive, let node --watch handle file-change restarts
|
|
420
|
+
});
|
|
421
|
+
process.on("exit", (code) => {
|
|
422
|
+
console.log(`Process exiting with code ${code}`);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// ── Entry Point ──
|
|
426
|
+
|
|
427
|
+
await start();
|
|
428
|
+
|
|
429
|
+
export { app, start };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bobfrankston/mailx-server",
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@bobfrankston/mailx-types": "file:../mailx-types",
|
|
13
|
+
"@bobfrankston/mailx-store": "file:../mailx-store",
|
|
14
|
+
"@bobfrankston/mailx-imap": "file:../mailx-imap",
|
|
15
|
+
"@bobfrankston/mailx-api": "file:../mailx-api",
|
|
16
|
+
"@bobfrankston/mailx-settings": "file:../mailx-settings",
|
|
17
|
+
"express": "^4.21.0",
|
|
18
|
+
"ws": "^8.18.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/express": "^5.0.0",
|
|
22
|
+
"@types/ws": "^8.5.13"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/BobFrankston/mailx-server.git"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./index.ts"],"version":"5.9.2"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Calendar / Tasks / People (Contacts) two-way sync helpers.
|
|
3
|
+
*
|
|
4
|
+
* Used by MailxService to push local edits to Google and pull server
|
|
5
|
+
* changes into the local cache. All functions take a `getToken` function
|
|
6
|
+
* and a fetch implementation so they stay platform-agnostic (Node uses
|
|
7
|
+
* global `fetch` on Node 18+; browsers use window.fetch).
|
|
8
|
+
*
|
|
9
|
+
* Error handling: throws on network / HTTP errors. Caller catches and
|
|
10
|
+
* either retries via the store_sync drainer or surfaces to the UI.
|
|
11
|
+
*/
|
|
12
|
+
type TokenProvider = () => Promise<string>;
|
|
13
|
+
export declare class GoogleHttpError extends Error {
|
|
14
|
+
status: number;
|
|
15
|
+
statusText: string;
|
|
16
|
+
body: string;
|
|
17
|
+
constructor(status: number, statusText: string, body: string);
|
|
18
|
+
}
|
|
19
|
+
export interface GCalEvent {
|
|
20
|
+
id: string;
|
|
21
|
+
summary: string;
|
|
22
|
+
start: {
|
|
23
|
+
dateTime?: string;
|
|
24
|
+
date?: string;
|
|
25
|
+
};
|
|
26
|
+
end: {
|
|
27
|
+
dateTime?: string;
|
|
28
|
+
date?: string;
|
|
29
|
+
};
|
|
30
|
+
location?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
etag?: string;
|
|
33
|
+
/** Set on instances expanded from a recurring series (singleEvents=true).
|
|
34
|
+
* Absent for singletons. Lets the UI filter out recurring expansions. */
|
|
35
|
+
recurringEventId?: string;
|
|
36
|
+
/** Link to open the event in Google Calendar web. */
|
|
37
|
+
htmlLink?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function listCalendarEvents(tokenProvider: TokenProvider, fromMs: number, toMs: number, calendarId?: string): Promise<GCalEvent[]>;
|
|
40
|
+
export declare function createCalendarEvent(tokenProvider: TokenProvider, event: any, calendarId?: string): Promise<GCalEvent>;
|
|
41
|
+
export declare function updateCalendarEvent(tokenProvider: TokenProvider, eventId: string, event: any, calendarId?: string): Promise<GCalEvent>;
|
|
42
|
+
export declare function deleteCalendarEvent(tokenProvider: TokenProvider, eventId: string, calendarId?: string): Promise<void>;
|
|
43
|
+
export interface GTask {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
notes?: string;
|
|
47
|
+
due?: string;
|
|
48
|
+
completed?: string;
|
|
49
|
+
status?: "needsAction" | "completed";
|
|
50
|
+
etag?: string;
|
|
51
|
+
}
|
|
52
|
+
export declare function listTasks(tokenProvider: TokenProvider, listId?: string, showCompleted?: boolean): Promise<GTask[]>;
|
|
53
|
+
export declare function createTask(tokenProvider: TokenProvider, task: any, listId?: string): Promise<GTask>;
|
|
54
|
+
export declare function updateTask(tokenProvider: TokenProvider, taskId: string, task: any, listId?: string): Promise<GTask>;
|
|
55
|
+
export declare function deleteTask(tokenProvider: TokenProvider, taskId: string, listId?: string): Promise<void>;
|
|
56
|
+
export declare function createContact(tokenProvider: TokenProvider, person: any): Promise<any>;
|
|
57
|
+
export declare function updateContact(tokenProvider: TokenProvider, resourceName: string, updatePersonFields: string, person: any): Promise<any>;
|
|
58
|
+
export declare function deleteContact(tokenProvider: TokenProvider, resourceName: string): Promise<void>;
|
|
59
|
+
export declare function calendarEventToLocal(ev: GCalEvent, accountId: string): {
|
|
60
|
+
providerId: string;
|
|
61
|
+
accountId: string;
|
|
62
|
+
title: string;
|
|
63
|
+
startMs: number;
|
|
64
|
+
endMs: number;
|
|
65
|
+
allDay: boolean;
|
|
66
|
+
location: string;
|
|
67
|
+
notes: string;
|
|
68
|
+
etag: string;
|
|
69
|
+
recurringEventId: string | undefined;
|
|
70
|
+
htmlLink: string | undefined;
|
|
71
|
+
};
|
|
72
|
+
export declare function localToCalendarEvent(local: {
|
|
73
|
+
title: string;
|
|
74
|
+
startMs: number;
|
|
75
|
+
endMs: number;
|
|
76
|
+
allDay?: boolean;
|
|
77
|
+
location?: string;
|
|
78
|
+
notes?: string;
|
|
79
|
+
}): any;
|
|
80
|
+
export declare function taskToLocal(t: GTask, accountId: string): {
|
|
81
|
+
providerId: string;
|
|
82
|
+
accountId: string;
|
|
83
|
+
title: string;
|
|
84
|
+
notes: string;
|
|
85
|
+
dueMs: number | undefined;
|
|
86
|
+
completedMs: number | undefined;
|
|
87
|
+
etag: string;
|
|
88
|
+
};
|
|
89
|
+
export declare function localToTask(local: {
|
|
90
|
+
title: string;
|
|
91
|
+
notes?: string;
|
|
92
|
+
dueMs?: number;
|
|
93
|
+
completedMs?: number;
|
|
94
|
+
}): any;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=google-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-sync.d.ts","sourceRoot":"","sources":["google-sync.ts"],"names":[],"mappings":"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"}
|