@bobfrankston/mailx-types 0.1.49 → 0.1.53

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.
Files changed (3) hide show
  1. package/index.d.ts +51 -0
  2. package/index.js +72 -0
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -439,4 +439,55 @@ export declare function parseSearchQuery(query: string): {
439
439
  conditions: string[];
440
440
  params: (string | number)[];
441
441
  };
442
+ /**
443
+ * Is this text a JS "missing value" that leaked into a message body?
444
+ *
445
+ * Marketing mail whose `text/plain` alternative is generated in JavaScript
446
+ * sometimes stringifies an absent value straight into the part, so the entire
447
+ * plain-text body is the word `undefined`. Adobe Firefly / Creative Cloud and
448
+ * Xfinity do this — 40 messages in Bob's bobma store on 2026-08-19, every one
449
+ * with a perfectly good HTML part sitting next to the junk text part.
450
+ *
451
+ * Used in two places that must agree:
452
+ * - `extractPreview` (mailx-imap) — skip the text part and summarize the
453
+ * HTML instead, so newly-synced mail never indexes the junk.
454
+ * - the message-list row renderer — suppress the snippet for rows that were
455
+ * already indexed with it, so old rows heal without a re-sync.
456
+ *
457
+ * Deliberately narrow: only values that mean "a value was missing". `false`,
458
+ * `0` and `no` are excluded — those are things a human might actually write.
459
+ */
460
+ export declare function isJunkPreviewText(s: string | null | undefined): boolean;
461
+ /**
462
+ * Does a display name assert an email address other than the real one?
463
+ *
464
+ * Display-name spoofing is the cheapest phish there is: put
465
+ * `security@paypal.com` in the From *name* and point the real address at
466
+ * anywhere. The message list shows only the display name, so nothing on
467
+ * screen contradicts the claim.
468
+ *
469
+ * Returns the claimed address when the name contains an email-like token that
470
+ * differs from `address`, otherwise null. A name that merely repeats the real
471
+ * address is not spoofing — see formatSender, which collapses that case.
472
+ */
473
+ export declare function displayNameClaimsOtherAddress(name: string, address: string): string | null;
474
+ /**
475
+ * How a sender should read in the UI.
476
+ *
477
+ * `text` is what to show. `claimed` is set when the display name asserts a
478
+ * different address than the envelope's — callers must make the real address
479
+ * visible in that case rather than trusting `text` alone.
480
+ *
481
+ * Collapses the redundant `"x@y.com" <x@y.com>` form that Microsoft 365
482
+ * quarantine notices and plenty of bulk senders emit — showing the same
483
+ * address twice reads as if two different parties were involved
484
+ * (Bob 2026-08-19).
485
+ */
486
+ export declare function formatSender(addr: {
487
+ name?: string;
488
+ address: string;
489
+ } | null | undefined): {
490
+ text: string;
491
+ claimed: string | null;
492
+ };
442
493
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -434,4 +434,76 @@ export function parseSearchQuery(query) {
434
434
  }
435
435
  return { conditions, params };
436
436
  }
437
+ /**
438
+ * Is this text a JS "missing value" that leaked into a message body?
439
+ *
440
+ * Marketing mail whose `text/plain` alternative is generated in JavaScript
441
+ * sometimes stringifies an absent value straight into the part, so the entire
442
+ * plain-text body is the word `undefined`. Adobe Firefly / Creative Cloud and
443
+ * Xfinity do this — 40 messages in Bob's bobma store on 2026-08-19, every one
444
+ * with a perfectly good HTML part sitting next to the junk text part.
445
+ *
446
+ * Used in two places that must agree:
447
+ * - `extractPreview` (mailx-imap) — skip the text part and summarize the
448
+ * HTML instead, so newly-synced mail never indexes the junk.
449
+ * - the message-list row renderer — suppress the snippet for rows that were
450
+ * already indexed with it, so old rows heal without a re-sync.
451
+ *
452
+ * Deliberately narrow: only values that mean "a value was missing". `false`,
453
+ * `0` and `no` are excluded — those are things a human might actually write.
454
+ */
455
+ export function isJunkPreviewText(s) {
456
+ const t = (s || "").replace(/\s+/g, " ").trim().toLowerCase();
457
+ if (!t)
458
+ return true;
459
+ return t === "undefined" || t === "null" || t === "nan" || t === "[object object]";
460
+ }
461
+ /**
462
+ * Does a display name assert an email address other than the real one?
463
+ *
464
+ * Display-name spoofing is the cheapest phish there is: put
465
+ * `security@paypal.com` in the From *name* and point the real address at
466
+ * anywhere. The message list shows only the display name, so nothing on
467
+ * screen contradicts the claim.
468
+ *
469
+ * Returns the claimed address when the name contains an email-like token that
470
+ * differs from `address`, otherwise null. A name that merely repeats the real
471
+ * address is not spoofing — see formatSender, which collapses that case.
472
+ */
473
+ export function displayNameClaimsOtherAddress(name, address) {
474
+ const n = (name || "").trim();
475
+ if (!n)
476
+ return null;
477
+ const real = (address || "").trim().toLowerCase();
478
+ // Deliberately loose: anything shaped like local@domain.tld inside the name.
479
+ const m = n.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g);
480
+ if (!m)
481
+ return null;
482
+ for (const claimed of m) {
483
+ if (claimed.toLowerCase() !== real)
484
+ return claimed;
485
+ }
486
+ return null;
487
+ }
488
+ /**
489
+ * How a sender should read in the UI.
490
+ *
491
+ * `text` is what to show. `claimed` is set when the display name asserts a
492
+ * different address than the envelope's — callers must make the real address
493
+ * visible in that case rather than trusting `text` alone.
494
+ *
495
+ * Collapses the redundant `"x@y.com" <x@y.com>` form that Microsoft 365
496
+ * quarantine notices and plenty of bulk senders emit — showing the same
497
+ * address twice reads as if two different parties were involved
498
+ * (Bob 2026-08-19).
499
+ */
500
+ export function formatSender(addr) {
501
+ const address = (addr?.address || "").trim();
502
+ const name = (addr?.name || "").trim();
503
+ if (!name)
504
+ return { text: address, claimed: null };
505
+ if (name.toLowerCase() === address.toLowerCase())
506
+ return { text: address, claimed: null };
507
+ return { text: `${name} <${address}>`, claimed: displayNameClaimsOtherAddress(name, address) };
508
+ }
437
509
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-types",
3
- "version": "0.1.49",
3
+ "version": "0.1.53",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",