@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,283 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build client/icon.ico from client/icon.png with proper format coverage:
|
|
4
|
+
* - 16, 32, 48, 64, 128 px entries: BMP-DIB (BI_RGB) — required by the
|
|
5
|
+
* Windows Shell taskbar/AUMID code path. PNG-in-ICO at small sizes is
|
|
6
|
+
* silently rejected, leaving the taskbar showing the generic "document"
|
|
7
|
+
* icon (the bug behind "icon shows as a piece of paper").
|
|
8
|
+
* - 256 px entry: PNG (Vista+ accepts it; smaller file than the 256 KB
|
|
9
|
+
* a 256x256 BMP DIB would be).
|
|
10
|
+
*
|
|
11
|
+
* Run: node bin/build-icon-ico.js
|
|
12
|
+
*
|
|
13
|
+
* Source: client/icon.png. Re-run whenever the source PNG changes.
|
|
14
|
+
*
|
|
15
|
+
* Hand-rolled — no image deps available in the workspace. Decodes 8-bit
|
|
16
|
+
* RGBA / RGB non-interlaced PNG (which is what every standard tool emits),
|
|
17
|
+
* downsamples by box-averaging, encodes BMP DIBs with the trailing AND mask
|
|
18
|
+
* the ICO format requires.
|
|
19
|
+
*/
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import zlib from "node:zlib";
|
|
23
|
+
|
|
24
|
+
const root = path.resolve(import.meta.dirname, "..");
|
|
25
|
+
const src = path.join(root, "client", "icon.png");
|
|
26
|
+
const dst = path.join(root, "client", "icon.ico");
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(src)) {
|
|
29
|
+
console.error(`build-icon-ico: source not found: ${src}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pngBuf = fs.readFileSync(src);
|
|
34
|
+
|
|
35
|
+
// ── PNG decoder (8-bit RGBA / RGB, no interlace) ─────────────────────────
|
|
36
|
+
function decodePNG(buf) {
|
|
37
|
+
const sigExpected = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
|
|
38
|
+
if (buf.length < 8 || sigExpected.some((b, i) => buf[i] !== b)) {
|
|
39
|
+
throw new Error("not a PNG (bad signature)");
|
|
40
|
+
}
|
|
41
|
+
let pos = 8;
|
|
42
|
+
let width = 0, height = 0, bitDepth = 0, colorType = 0;
|
|
43
|
+
const idat = [];
|
|
44
|
+
while (pos < buf.length) {
|
|
45
|
+
const len = buf.readUInt32BE(pos); pos += 4;
|
|
46
|
+
const type = buf.toString("ascii", pos, pos + 4); pos += 4;
|
|
47
|
+
const data = buf.subarray(pos, pos + len); pos += len + 4; // skip CRC
|
|
48
|
+
if (type === "IHDR") {
|
|
49
|
+
width = data.readUInt32BE(0);
|
|
50
|
+
height = data.readUInt32BE(4);
|
|
51
|
+
bitDepth = data.readUInt8(8);
|
|
52
|
+
colorType = data.readUInt8(9);
|
|
53
|
+
if (data.readUInt8(12) !== 0) {
|
|
54
|
+
throw new Error("interlaced PNG not supported");
|
|
55
|
+
}
|
|
56
|
+
} else if (type === "IDAT") {
|
|
57
|
+
idat.push(data);
|
|
58
|
+
} else if (type === "IEND") {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (bitDepth !== 8 && bitDepth !== 16) {
|
|
63
|
+
throw new Error(`bit depth ${bitDepth} not supported (need 8 or 16)`);
|
|
64
|
+
}
|
|
65
|
+
if (colorType !== 6 && colorType !== 2) {
|
|
66
|
+
throw new Error(`color type ${colorType} not supported (need 2=RGB or 6=RGBA)`);
|
|
67
|
+
}
|
|
68
|
+
const samplesPerPixel = colorType === 6 ? 4 : 3;
|
|
69
|
+
const bytesPerSample = bitDepth / 8; // 1 or 2
|
|
70
|
+
const bpp = samplesPerPixel * bytesPerSample;
|
|
71
|
+
const inflated = zlib.inflateSync(Buffer.concat(idat));
|
|
72
|
+
const stride = width * bpp;
|
|
73
|
+
const rgba = Buffer.alloc(width * height * 4);
|
|
74
|
+
let inPos = 0;
|
|
75
|
+
let prev = Buffer.alloc(stride);
|
|
76
|
+
let cur = Buffer.alloc(stride);
|
|
77
|
+
for (let y = 0; y < height; y++) {
|
|
78
|
+
const filter = inflated.readUInt8(inPos); inPos += 1;
|
|
79
|
+
inflated.copy(cur, 0, inPos, inPos + stride); inPos += stride;
|
|
80
|
+
switch (filter) {
|
|
81
|
+
case 0: break; // None
|
|
82
|
+
case 1: // Sub
|
|
83
|
+
for (let x = bpp; x < stride; x++) cur[x] = (cur[x] + cur[x - bpp]) & 0xFF;
|
|
84
|
+
break;
|
|
85
|
+
case 2: // Up
|
|
86
|
+
for (let x = 0; x < stride; x++) cur[x] = (cur[x] + prev[x]) & 0xFF;
|
|
87
|
+
break;
|
|
88
|
+
case 3: // Avg
|
|
89
|
+
for (let x = 0; x < stride; x++) {
|
|
90
|
+
const left = x >= bpp ? cur[x - bpp] : 0;
|
|
91
|
+
cur[x] = (cur[x] + ((left + prev[x]) >> 1)) & 0xFF;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case 4: { // Paeth
|
|
95
|
+
for (let x = 0; x < stride; x++) {
|
|
96
|
+
const a = x >= bpp ? cur[x - bpp] : 0;
|
|
97
|
+
const b = prev[x];
|
|
98
|
+
const c = x >= bpp ? prev[x - bpp] : 0;
|
|
99
|
+
const p = a + b - c;
|
|
100
|
+
const pa = Math.abs(p - a);
|
|
101
|
+
const pb = Math.abs(p - b);
|
|
102
|
+
const pc = Math.abs(p - c);
|
|
103
|
+
const pred = pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
|
|
104
|
+
cur[x] = (cur[x] + pred) & 0xFF;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
default: throw new Error(`unknown PNG filter ${filter}`);
|
|
109
|
+
}
|
|
110
|
+
// 16-bit samples are big-endian; we keep only the high byte (eyeball-
|
|
111
|
+
// identical to dividing by 257 for icon use).
|
|
112
|
+
for (let x = 0; x < width; x++) {
|
|
113
|
+
const di = (y * width + x) * 4;
|
|
114
|
+
const si = x * bpp;
|
|
115
|
+
if (bitDepth === 8) {
|
|
116
|
+
rgba[di + 0] = cur[si + 0];
|
|
117
|
+
rgba[di + 1] = cur[si + 1];
|
|
118
|
+
rgba[di + 2] = cur[si + 2];
|
|
119
|
+
rgba[di + 3] = samplesPerPixel === 4 ? cur[si + 3] : 255;
|
|
120
|
+
} else {
|
|
121
|
+
rgba[di + 0] = cur[si + 0]; // hi byte of R
|
|
122
|
+
rgba[di + 1] = cur[si + 2]; // hi byte of G
|
|
123
|
+
rgba[di + 2] = cur[si + 4]; // hi byte of B
|
|
124
|
+
rgba[di + 3] = samplesPerPixel === 4 ? cur[si + 6] : 255;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const swap = prev; prev = cur; cur = swap;
|
|
128
|
+
}
|
|
129
|
+
return { width, height, rgba };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Box-filter downsample (good enough for icon sizes) ───────────────────
|
|
133
|
+
function downsample(src, srcW, srcH, dstW, dstH) {
|
|
134
|
+
if (srcW === dstW && srcH === dstH) return Buffer.from(src);
|
|
135
|
+
const dst = Buffer.alloc(dstW * dstH * 4);
|
|
136
|
+
const sx = srcW / dstW;
|
|
137
|
+
const sy = srcH / dstH;
|
|
138
|
+
for (let y = 0; y < dstH; y++) {
|
|
139
|
+
const y0 = Math.floor(y * sy);
|
|
140
|
+
const y1 = Math.min(srcH, Math.ceil((y + 1) * sy));
|
|
141
|
+
for (let x = 0; x < dstW; x++) {
|
|
142
|
+
const x0 = Math.floor(x * sx);
|
|
143
|
+
const x1 = Math.min(srcW, Math.ceil((x + 1) * sx));
|
|
144
|
+
let r = 0, g = 0, b = 0, a = 0, n = 0;
|
|
145
|
+
for (let yy = y0; yy < y1; yy++) {
|
|
146
|
+
for (let xx = x0; xx < x1; xx++) {
|
|
147
|
+
const i = (yy * srcW + xx) * 4;
|
|
148
|
+
r += src[i]; g += src[i + 1]; b += src[i + 2]; a += src[i + 3];
|
|
149
|
+
n++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const di = (y * dstW + x) * 4;
|
|
153
|
+
dst[di] = (r / n) | 0;
|
|
154
|
+
dst[di + 1] = (g / n) | 0;
|
|
155
|
+
dst[di + 2] = (b / n) | 0;
|
|
156
|
+
dst[di + 3] = (a / n) | 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return dst;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── BMP DIB encoder for ICO entries (32bpp BGRA + AND mask) ──────────────
|
|
163
|
+
function encodeDIB(rgba, w, h) {
|
|
164
|
+
const colorBytes = w * h * 4;
|
|
165
|
+
const maskRowSize = ((w + 31) >> 5) << 2; // 1bpp, 4-byte aligned
|
|
166
|
+
const maskBytes = maskRowSize * h;
|
|
167
|
+
const out = Buffer.alloc(40 + colorBytes + maskBytes);
|
|
168
|
+
// BITMAPINFOHEADER
|
|
169
|
+
out.writeUInt32LE(40, 0); // biSize
|
|
170
|
+
out.writeInt32LE(w, 4); // biWidth
|
|
171
|
+
out.writeInt32LE(h * 2, 8); // biHeight = 2*h (color + mask)
|
|
172
|
+
out.writeUInt16LE(1, 12); // biPlanes
|
|
173
|
+
out.writeUInt16LE(32, 14); // biBitCount
|
|
174
|
+
out.writeUInt32LE(0, 16); // biCompression (BI_RGB)
|
|
175
|
+
// remaining BITMAPINFOHEADER fields stay zero
|
|
176
|
+
// Color: 32bpp BGRA, bottom-up
|
|
177
|
+
let off = 40;
|
|
178
|
+
for (let y = h - 1; y >= 0; y--) {
|
|
179
|
+
for (let x = 0; x < w; x++) {
|
|
180
|
+
const i = (y * w + x) * 4;
|
|
181
|
+
out[off++] = rgba[i + 2]; // B
|
|
182
|
+
out[off++] = rgba[i + 1]; // G
|
|
183
|
+
out[off++] = rgba[i + 0]; // R
|
|
184
|
+
out[off++] = rgba[i + 3]; // A
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// AND mask stays all-zero — alpha channel handles transparency. Required
|
|
188
|
+
// by ICO format though, so we allocate the bytes (already zeroed).
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── ICO container ────────────────────────────────────────────────────────
|
|
193
|
+
function buildICO(entries) {
|
|
194
|
+
const dirSize = 6 + 16 * entries.length;
|
|
195
|
+
const dir = Buffer.alloc(dirSize);
|
|
196
|
+
dir.writeUInt16LE(0, 0); // reserved
|
|
197
|
+
dir.writeUInt16LE(1, 2); // type = icon
|
|
198
|
+
dir.writeUInt16LE(entries.length, 4); // count
|
|
199
|
+
let dataOff = dirSize;
|
|
200
|
+
for (let i = 0; i < entries.length; i++) {
|
|
201
|
+
const e = entries[i];
|
|
202
|
+
const o = 6 + i * 16;
|
|
203
|
+
dir.writeUInt8(e.size === 256 ? 0 : e.size, o);
|
|
204
|
+
dir.writeUInt8(e.size === 256 ? 0 : e.size, o + 1);
|
|
205
|
+
dir.writeUInt8(0, o + 2); // ncolors
|
|
206
|
+
dir.writeUInt8(0, o + 3); // reserved
|
|
207
|
+
dir.writeUInt16LE(1, o + 4); // planes
|
|
208
|
+
dir.writeUInt16LE(32, o + 6); // bpp
|
|
209
|
+
dir.writeUInt32LE(e.data.length, o + 8);
|
|
210
|
+
dir.writeUInt32LE(dataOff, o + 12);
|
|
211
|
+
dataOff += e.data.length;
|
|
212
|
+
}
|
|
213
|
+
return Buffer.concat([dir, ...entries.map(e => e.data)]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ── Main ─────────────────────────────────────────────────────────────────
|
|
217
|
+
const decoded = decodePNG(pngBuf);
|
|
218
|
+
console.log(`build-icon-ico: source ${decoded.width}x${decoded.height} ${decoded.rgba.length} bytes RGBA`);
|
|
219
|
+
|
|
220
|
+
const sizes = [16, 32, 48, 64, 128, 256];
|
|
221
|
+
const entries = [];
|
|
222
|
+
for (const sz of sizes) {
|
|
223
|
+
const scaled = downsample(decoded.rgba, decoded.width, decoded.height, sz, sz);
|
|
224
|
+
if (sz === 256) {
|
|
225
|
+
// 256x256 BMP would be 256KB — store as PNG instead. Vista+ Shell
|
|
226
|
+
// accepts PNG entries at >=96px; <96px still has to be BMP for the
|
|
227
|
+
// taskbar code path on older configs.
|
|
228
|
+
const pngEntry = encodePNGEntry(scaled, sz);
|
|
229
|
+
entries.push({ size: sz, data: pngEntry });
|
|
230
|
+
} else {
|
|
231
|
+
entries.push({ size: sz, data: encodeDIB(scaled, sz, sz) });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Re-encode an RGBA buffer back to a PNG (used only for the 256x256 entry).
|
|
236
|
+
function encodePNGEntry(rgba, sz) {
|
|
237
|
+
function chunk(type, data) {
|
|
238
|
+
const len = Buffer.alloc(4);
|
|
239
|
+
len.writeUInt32BE(data.length, 0);
|
|
240
|
+
const head = Buffer.concat([Buffer.from(type, "ascii"), data]);
|
|
241
|
+
const crc = Buffer.alloc(4);
|
|
242
|
+
crc.writeInt32BE(crc32(head), 0);
|
|
243
|
+
return Buffer.concat([len, head, crc]);
|
|
244
|
+
}
|
|
245
|
+
const sig = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
|
|
246
|
+
const ihdr = Buffer.alloc(13);
|
|
247
|
+
ihdr.writeUInt32BE(sz, 0);
|
|
248
|
+
ihdr.writeUInt32BE(sz, 4);
|
|
249
|
+
ihdr[8] = 8; // bit depth
|
|
250
|
+
ihdr[9] = 6; // RGBA
|
|
251
|
+
ihdr[10] = 0; // compression
|
|
252
|
+
ihdr[11] = 0; // filter
|
|
253
|
+
ihdr[12] = 0; // interlace
|
|
254
|
+
// Filter byte 0 (None) per scanline + RGBA pixels
|
|
255
|
+
const stride = sz * 4;
|
|
256
|
+
const filtered = Buffer.alloc(sz * (stride + 1));
|
|
257
|
+
for (let y = 0; y < sz; y++) {
|
|
258
|
+
filtered[y * (stride + 1)] = 0;
|
|
259
|
+
rgba.copy(filtered, y * (stride + 1) + 1, y * stride, y * stride + stride);
|
|
260
|
+
}
|
|
261
|
+
const idat = zlib.deflateSync(filtered, { level: 9 });
|
|
262
|
+
return Buffer.concat([sig, chunk("IHDR", ihdr), chunk("IDAT", idat), chunk("IEND", Buffer.alloc(0))]);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Standard PNG-spec CRC32.
|
|
266
|
+
function crc32(buf) {
|
|
267
|
+
let c, table = crc32.table;
|
|
268
|
+
if (!table) {
|
|
269
|
+
table = crc32.table = new Int32Array(256);
|
|
270
|
+
for (let n = 0; n < 256; n++) {
|
|
271
|
+
c = n;
|
|
272
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
273
|
+
table[n] = c;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
c = -1;
|
|
277
|
+
for (let i = 0; i < buf.length; i++) c = table[(c ^ buf[i]) & 0xFF] ^ (c >>> 8);
|
|
278
|
+
return c ^ -1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const ico = buildICO(entries);
|
|
282
|
+
fs.writeFileSync(dst, ico);
|
|
283
|
+
console.log(`build-icon-ico: wrote ${dst} (${ico.length} bytes, sizes: ${sizes.join(", ")})`);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lean-accounts.js — strip default-valued fields from an accounts.jsonc.
|
|
4
|
+
*
|
|
5
|
+
* Reads any accounts.jsonc (the one mailx writes when it bloats it with
|
|
6
|
+
* port: 993, tls: true, auth: "password", enabled: true, sig.html: false,
|
|
7
|
+
* etc.) and emits a compact form. Same logic as the Lean button in the
|
|
8
|
+
* config editor, but standalone so it works without mailx running.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node lean-accounts.js <path> prints lean output to stdout
|
|
12
|
+
* node lean-accounts.js <path> --inplace overwrites the file
|
|
13
|
+
*
|
|
14
|
+
* Drops:
|
|
15
|
+
* - imap/smtp host/port/tls/auth that match the email's provider defaults
|
|
16
|
+
* - imap/smtp user when it equals the email
|
|
17
|
+
* - enabled: true (default)
|
|
18
|
+
* - sig.html: false (default)
|
|
19
|
+
* - per-account name when it matches the file-level "name"
|
|
20
|
+
*
|
|
21
|
+
* Promotes a shared "name" to file-level when every account has the same.
|
|
22
|
+
*
|
|
23
|
+
* Requires: jsonc-parser (any version that exports `parse` with comment+
|
|
24
|
+
* trailing-comma tolerance). The mailx repo's node_modules has it.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import fs from "node:fs";
|
|
28
|
+
import path from "node:path";
|
|
29
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
30
|
+
|
|
31
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
|
|
33
|
+
// ── Provider defaults: same set mailx-settings uses ────────────────────────
|
|
34
|
+
const PROVIDERS = {
|
|
35
|
+
"gmail.com": {
|
|
36
|
+
label: "Gmail",
|
|
37
|
+
imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
|
|
38
|
+
smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
|
|
39
|
+
},
|
|
40
|
+
"googlemail.com": {
|
|
41
|
+
label: "Gmail",
|
|
42
|
+
imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
|
|
43
|
+
smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
|
|
44
|
+
},
|
|
45
|
+
"outlook.com": {
|
|
46
|
+
label: "Outlook",
|
|
47
|
+
imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
|
|
48
|
+
smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
|
|
49
|
+
},
|
|
50
|
+
"hotmail.com": {
|
|
51
|
+
label: "Outlook",
|
|
52
|
+
imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
|
|
53
|
+
smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
|
|
54
|
+
},
|
|
55
|
+
"yahoo.com": {
|
|
56
|
+
label: "Yahoo",
|
|
57
|
+
imap: { host: "imap.mail.yahoo.com", port: 993, tls: true, auth: "oauth2" },
|
|
58
|
+
smtp: { host: "smtp.mail.yahoo.com", port: 587, tls: true, auth: "oauth2" },
|
|
59
|
+
},
|
|
60
|
+
"icloud.com": {
|
|
61
|
+
label: "iCloud",
|
|
62
|
+
imap: { host: "imap.mail.me.com", port: 993, tls: true, auth: "oauth2" },
|
|
63
|
+
smtp: { host: "smtp.mail.me.com", port: 587, tls: true, auth: "oauth2" },
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
function denormalizeAccount(acct, globalName) {
|
|
68
|
+
const domain = (acct.email || "").split("@")[1]?.toLowerCase() || "";
|
|
69
|
+
const provider = PROVIDERS[domain];
|
|
70
|
+
const out = {};
|
|
71
|
+
out.id = acct.id;
|
|
72
|
+
if (acct.label && acct.label !== provider?.label && acct.label !== acct.id) out.label = acct.label;
|
|
73
|
+
out.email = acct.email;
|
|
74
|
+
if (acct.name && acct.name !== globalName) out.name = acct.name;
|
|
75
|
+
if (acct.primary) out.primary = true;
|
|
76
|
+
if (acct.primaryCalendar !== undefined) out.primaryCalendar = acct.primaryCalendar;
|
|
77
|
+
if (acct.primaryTasks !== undefined) out.primaryTasks = acct.primaryTasks;
|
|
78
|
+
if (acct.primaryContacts !== undefined) out.primaryContacts = acct.primaryContacts;
|
|
79
|
+
|
|
80
|
+
const imapOut = {};
|
|
81
|
+
if (acct.imap?.host && acct.imap.host !== provider?.imap.host) imapOut.host = acct.imap.host;
|
|
82
|
+
if (acct.imap?.user && acct.imap.user !== acct.email) imapOut.user = acct.imap.user;
|
|
83
|
+
if (acct.imap?.password) imapOut.password = acct.imap.password;
|
|
84
|
+
if (acct.imap?.port && acct.imap.port !== (provider?.imap.port ?? 993)) imapOut.port = acct.imap.port;
|
|
85
|
+
if (acct.imap?.tls !== undefined && acct.imap.tls !== (provider?.imap.tls ?? true)) imapOut.tls = acct.imap.tls;
|
|
86
|
+
if (acct.imap?.auth && acct.imap.auth !== (provider?.imap.auth ?? "password")) imapOut.auth = acct.imap.auth;
|
|
87
|
+
if (Object.keys(imapOut).length > 0) out.imap = imapOut;
|
|
88
|
+
|
|
89
|
+
const smtpOut = {};
|
|
90
|
+
if (acct.smtp?.host && acct.smtp.host !== provider?.smtp.host) smtpOut.host = acct.smtp.host;
|
|
91
|
+
if (acct.smtp?.user && acct.smtp.user !== acct.email && acct.smtp.user !== acct.imap?.user) smtpOut.user = acct.smtp.user;
|
|
92
|
+
if (acct.smtp?.password) smtpOut.password = acct.smtp.password;
|
|
93
|
+
if (acct.smtp?.port && acct.smtp.port !== (provider?.smtp.port ?? 587)) smtpOut.port = acct.smtp.port;
|
|
94
|
+
if (acct.smtp?.tls !== undefined && acct.smtp.tls !== (provider?.smtp.tls ?? true)) smtpOut.tls = acct.smtp.tls;
|
|
95
|
+
if (acct.smtp?.auth && acct.smtp.auth !== (provider?.smtp.auth ?? "password")) smtpOut.auth = acct.smtp.auth;
|
|
96
|
+
if (Object.keys(smtpOut).length > 0) out.smtp = smtpOut;
|
|
97
|
+
|
|
98
|
+
if (acct.defaultSend) out.defaultSend = true;
|
|
99
|
+
if (acct.enabled === false) out.enabled = false;
|
|
100
|
+
if (acct.relayDomains?.length > 0) out.relayDomains = acct.relayDomains;
|
|
101
|
+
if (acct.deliveredToPrefix?.length > 0) out.deliveredToPrefix = acct.deliveredToPrefix;
|
|
102
|
+
if (acct.identityDomains?.length > 0) out.identityDomains = acct.identityDomains;
|
|
103
|
+
|
|
104
|
+
const syncContactsDefault = provider?.imap.auth === "oauth2";
|
|
105
|
+
if (acct.syncContacts !== undefined && acct.syncContacts !== syncContactsDefault) {
|
|
106
|
+
out.syncContacts = acct.syncContacts;
|
|
107
|
+
}
|
|
108
|
+
if (acct.signature) out.signature = acct.signature;
|
|
109
|
+
if (acct.sig?.text) {
|
|
110
|
+
out.sig = acct.sig.html ? { text: acct.sig.text, html: true } : { text: acct.sig.text };
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const args = process.argv.slice(2);
|
|
117
|
+
const inputPath = args.find(a => !a.startsWith("--"));
|
|
118
|
+
const inplace = args.includes("--inplace");
|
|
119
|
+
if (!inputPath) {
|
|
120
|
+
console.error("Usage: node lean-accounts.js <path-to-accounts.jsonc> [--inplace]");
|
|
121
|
+
process.exit(2);
|
|
122
|
+
}
|
|
123
|
+
if (!fs.existsSync(inputPath)) {
|
|
124
|
+
console.error(`File not found: ${inputPath}`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Resolve jsonc-parser from the local mailx repo's node_modules so the
|
|
129
|
+
// script doesn't require a global install. The repo root is two levels
|
|
130
|
+
// up from bin/ — and we walk up further if invoked from elsewhere.
|
|
131
|
+
let parseJsonc;
|
|
132
|
+
for (const dir of [
|
|
133
|
+
path.join(__dirname, "..", "node_modules", "jsonc-parser"),
|
|
134
|
+
path.join(__dirname, "..", "..", "node_modules", "jsonc-parser"),
|
|
135
|
+
path.join(process.cwd(), "node_modules", "jsonc-parser"),
|
|
136
|
+
]) {
|
|
137
|
+
if (fs.existsSync(path.join(dir, "package.json"))) {
|
|
138
|
+
const mod = await import(pathToFileURL(path.join(dir, "lib", "esm", "main.js")).href).catch(() => null) ||
|
|
139
|
+
await import("jsonc-parser").catch(() => null);
|
|
140
|
+
if (mod) { parseJsonc = mod.parse; break; }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!parseJsonc) {
|
|
144
|
+
try { parseJsonc = (await import("jsonc-parser")).parse; }
|
|
145
|
+
catch { console.error("jsonc-parser not found. Install or run from inside the mailx repo."); process.exit(1); }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const raw = fs.readFileSync(inputPath, "utf-8");
|
|
149
|
+
const errors = [];
|
|
150
|
+
const cfg = parseJsonc(raw, errors, { allowTrailingComma: true });
|
|
151
|
+
if (errors.length) {
|
|
152
|
+
console.error(`JSONC parse error: ${errors.map(e => JSON.stringify(e)).join(", ")}`);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const accounts = cfg?.accounts || (Array.isArray(cfg) ? cfg : []);
|
|
157
|
+
// Promote shared name to file-level when every entry has the same.
|
|
158
|
+
const names = new Set(accounts.map(a => a.name).filter(Boolean));
|
|
159
|
+
const sharedName = names.size === 1 ? [...names][0] : cfg?.name;
|
|
160
|
+
const lean = accounts.map(a => denormalizeAccount(a, sharedName));
|
|
161
|
+
const payload = sharedName ? { name: sharedName, accounts: lean } : { accounts: lean };
|
|
162
|
+
const output = JSON.stringify(payload, null, 2) + "\n";
|
|
163
|
+
|
|
164
|
+
if (inplace) {
|
|
165
|
+
fs.writeFileSync(inputPath, output);
|
|
166
|
+
console.error(`Wrote lean ${inputPath}`);
|
|
167
|
+
} else {
|
|
168
|
+
process.stdout.write(output);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main().catch(e => { console.error(e); process.exit(1); });
|