@framers/agentos-ext-gmail-source 0.5.2 → 0.6.1

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/dist/index.js CHANGED
@@ -13,7 +13,7 @@ export { GmailOAuthFlow } from './GmailOAuthFlow.js';
13
13
  export { GMAIL_READONLY_SCOPE, GmailOAuthFault, } from './types.js';
14
14
  export { GmailTextFault, sanitizeMailText, sanitizeMailMetadata, sanitizeMailHeaders, } from './mailSanitize.js';
15
15
  export { messageText } from './messageText.js';
16
- export { GmailThreadMapper } from './mapThread.js';
16
+ export { GmailThreadMapper, GMAIL_CATEGORIES } from './mapThread.js';
17
17
  export { GmailMappingFault } from './mime.js';
18
18
  export { GmailApi, GmailApiFault, } from './gmail.js';
19
19
  export { classifyGmailHttp, gmailOAuthFault } from './retry.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAAE,eAAe,GAEtC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,GAG5E,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAyB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAA8B,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAA2B,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,QAAQ,EAAE,aAAa,GAExB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAA6B,MAAM,YAAY,CAAC;AAC3F,OAAO,EACL,oBAAoB,EAAE,mBAAmB,GAE1C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,EAAE,iBAAiB,GAEtC,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAAE,eAAe,GAEtC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,GAG5E,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAyB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAkD,MAAM,gBAAgB,CAAC;AACrH,OAAO,EAAE,iBAAiB,EAA2B,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,QAAQ,EAAE,aAAa,GAExB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAA6B,MAAM,YAAY,CAAC;AAC3F,OAAO,EACL,oBAAoB,EAAE,mBAAmB,GAE1C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,kBAAkB,EAAE,iBAAiB,GAEtC,MAAM,WAAW,CAAC"}
@@ -2,8 +2,8 @@
2
2
  * @fileoverview Deterministic pre-storage sanitization of mail text: once percent and character references are decoded
3
3
  * and padding collapsed, address tokens, credential assignments, known credential shapes, private-key blocks and long
4
4
  * mixed tokens are replaced with fixed marks, and a final gate suppresses any line that still carries a credential
5
- * cue. Every count is a number; no matched value, offset or reverse mapping is kept, nothing is logged and no model or
6
- * network is called.
5
+ * cue, with the value after a line that introduces one. Every mark keeps its line's quote markers. Every count is a
6
+ * number; no matched value, offset or reverse mapping is kept, nothing is logged and no model or network is called.
7
7
  * @module agentos-ext-gmail-source/mailSanitize
8
8
  */
9
9
  /**
@@ -69,9 +69,18 @@ export declare class GmailTextFault extends Error {
69
69
  * than ASCII spaces and tabs, such as the no-break spaces and zero-width non-joiners mail templates repeat after a
70
70
  * preheader: it becomes one space, or nothing when it holds no space at all, so zero-width characters between letters
71
71
  * join them, and nothing when it holds an invisible character and ends a line. A run of ASCII spaces and tabs alone
72
- * stays as written. An assignment with an empty value, a block scalar
73
- * or an unclosed quote also suppresses the rest of the text. A replaced assignment and a line the final gate
74
- * suppresses keep their quote markers (`>`). The complete input is checked before the output cap clips the result.
72
+ * stays as written. An assignment with an empty value, a block scalar or an unclosed quote also suppresses the rest of
73
+ * the text. A line the final gate suppresses that introduces a value, ending with `:` or `=`, or with `is`, `are`,
74
+ * `was`, `were`, `be`, `below`, `follows` or `set`, `reset`, `changed` or `updated` followed by `to` (`below` and
75
+ * `follows` also with a full stop), also suppresses the value: the next line that holds text at the introduction's
76
+ * quote depth, past any blank lines, and the lines after it in its paragraph, which a blank line or a change of quote
77
+ * depth ends. One that ends with its cue, or with its cue and a full stop, as a label above its value does, also
78
+ * suppresses the next line that holds text when that line is one word at the label's quote depth. A line that holds
79
+ * text at another depth ends either and stays. A gated line that ends any other way, such as `Reset your password from
80
+ * Settings.` or `Your password was changed.`, leaves the next line alone. Every mark keeps its line's quote markers
81
+ * (`>`), each run of spaces and tabs among them shortened to one character, so trimming still reads removed history
82
+ * as quoted and a mark holds none of the padding of the line it replaces. The complete input is checked before the
83
+ * output cap clips the result.
75
84
  *
76
85
  * @param input Decoded text: a body or one display field.
77
86
  * @param policy The input, line and output bounds.
@@ -80,7 +89,20 @@ export declare class GmailTextFault extends Error {
80
89
  */
81
90
  export declare function sanitizeMailText(input: string, policy: GmailTextPolicy): GmailSanitizedText;
82
91
  /**
83
- * Use for every filename, label name and display field, after MIME decoding. Applies the same rules as
92
+ * Whether decoded text holds nothing but whitespace once its percent and character references are decoded, its
93
+ * padding collapsed and its format and control characters removed, the steps `sanitizeMailText` takes before any
94
+ * other. A MIME reader uses it to pass over an alternative whose text would sanitize away, such as a plain part of
95
+ * ` ` and `​` beside the HTML that holds the message.
96
+ *
97
+ * @param input Decoded text: one MIME part's body.
98
+ * @param maxInputCharacters The sanitizer's input cap. Text above it, before or after decoding, is not blank: the
99
+ * sanitizer refuses it rather than emptying it.
100
+ * @returns True when nothing but whitespace is left.
101
+ */
102
+ export declare function blankMailText(input: string, maxInputCharacters: number): boolean;
103
+ /**
104
+ * Use for every filename, label name and display field: a header value or filename after MIME decoding, and a label
105
+ * name as the labels response gives it, since that JSON text is never MIME encoded. Applies the same rules as
84
106
  * `sanitizeMailText` to the complete value, folds each whitespace run to one space and trims, then applies the
85
107
  * output cap.
86
108
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mailSanitize.d.ts","sourceRoot":"","sources":["../src/mailSanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,sHAAsH;IACtH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,iGAAiG;IACjG,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AACD,iHAAiH;AACjH,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,6GAA6G;IAC7G,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AACD,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACnF,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AACD,sGAAsG;AACtG,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AACnE,yGAAyG;AACzG,qBAAa,cAAe,SAAQ,KAAK;IAE3B,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IAD7C,sDAAsD;gBACjC,MAAM,EAAE,gBAAgB;CAG9C;AAgFD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,kBAAkB,CA2C3F;AACD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAM/F;AACD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,qBAAqB,CAsBxH"}
1
+ {"version":3,"file":"mailSanitize.d.ts","sourceRoot":"","sources":["../src/mailSanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,sHAAsH;IACtH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,iGAAiG;IACjG,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AACD,iHAAiH;AACjH,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,6GAA6G;IAC7G,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AACD,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACnF,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AACD,sGAAsG;AACtG,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AACnE,yGAAyG;AACzG,qBAAa,cAAe,SAAQ,KAAK;IAE3B,QAAQ,CAAC,MAAM,EAAE,gBAAgB;IAD7C,sDAAsD;gBACjC,MAAM,EAAE,gBAAgB;CAG9C;AAoGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAkE3F;AACD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAGhF;AACD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAM/F;AACD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,qBAAqB,CAsBxH"}
@@ -2,8 +2,8 @@
2
2
  * @fileoverview Deterministic pre-storage sanitization of mail text: once percent and character references are decoded
3
3
  * and padding collapsed, address tokens, credential assignments, known credential shapes, private-key blocks and long
4
4
  * mixed tokens are replaced with fixed marks, and a final gate suppresses any line that still carries a credential
5
- * cue. Every count is a number; no matched value, offset or reverse mapping is kept, nothing is logged and no model or
6
- * network is called.
5
+ * cue, with the value after a line that introduces one. Every mark keeps its line's quote markers. Every count is a
6
+ * number; no matched value, offset or reverse mapping is kept, nothing is logged and no model or network is called.
7
7
  * @module agentos-ext-gmail-source/mailSanitize
8
8
  */
9
9
  import { collapsePadding, decodeCharacterReferences, holdsNamedReference } from './characters.js';
@@ -41,6 +41,15 @@ const assignment = /(?:(?<![a-z0-9])(?:pass|pwd|pw|authorization|cookie|set-cook
41
41
  // plural) and the compound cues count at the end of any identifier (`DB_PASSWORD`, `rsaPrivateKey`); `bearer` and the
42
42
  // SSH cues need a character other than a letter or digit before them. No cue continues into a letter or digit.
43
43
  const residual = /(?:(?<![a-z0-9])(?:bearer|ssh-(?:rsa|ed25519)|sshpass)|pass(?:word|wd|phrase)s?|api[ _-]?(?:key|token)|access[ _-]?token|refresh[ _-]?token|client[ _-]?secret|private[ _-]?key)(?![a-z0-9])/i;
44
+ // How a line the final gate suppresses ends when it introduces a value on the lines after it ("Your password is:",
45
+ // "Your new password is", "changed to", "is below."): with `:` or `=`, or with one of these words after its cue, `below`
46
+ // and `follows` also with a full stop. A line ending any other way, such as "was changed.", introduces nothing.
47
+ const introduction = /(?:[:=]|(?<![a-z0-9])(?:is|are|was|were|be|(?:below|follows)\.?|(?:set|reset|changed|updated)[ \t]+to))$/i;
48
+ // A gated line that ends with its cue, or with its cue and a full stop, as a label above its value does ("Temporary
49
+ // password", "Here is your new password.").
50
+ const labelled = new RegExp(`(?:${residual.source})\\.?$`, 'i');
51
+ // A line's quote prefix: its `>` markers and the spaces and tabs around them.
52
+ const quotePrefix = /^[ \t]*(?:>[ \t]*)+/;
44
53
  const beginKey = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/;
45
54
  const endKey = /-----END [A-Z0-9 ]*PRIVATE KEY-----/;
46
55
  // Encoded bytes still present after the bounded decoding passes. A named reference the decoder knows, still present
@@ -83,6 +92,19 @@ function canonical(input, limit) {
83
92
  }
84
93
  return text;
85
94
  }
95
+ // The prefix a mark keeps: the quote's `>` markers, each run of spaces and tabs among them shortened to its first
96
+ // character, so a mark keeps its line's depth and none of the padding of the line it replaces.
97
+ function markPrefix(quote) {
98
+ return quote.replace(/[ \t]+/g, (run) => run.charAt(0));
99
+ }
100
+ // The number of `>` markers in a quote prefix.
101
+ function quoteDepth(quote) {
102
+ let depth = 0;
103
+ for (let i = 0; i < quote.length; i++)
104
+ if (quote.charCodeAt(i) === 0x3e)
105
+ depth++;
106
+ return depth;
107
+ }
86
108
  // Clips without leaving the high half of a surrogate pair at the end.
87
109
  function clipped(text, maximum) {
88
110
  let end = Math.min(text.length, maximum);
@@ -120,9 +142,18 @@ function containsAuthenticatedUrl(line) {
120
142
  * than ASCII spaces and tabs, such as the no-break spaces and zero-width non-joiners mail templates repeat after a
121
143
  * preheader: it becomes one space, or nothing when it holds no space at all, so zero-width characters between letters
122
144
  * join them, and nothing when it holds an invisible character and ends a line. A run of ASCII spaces and tabs alone
123
- * stays as written. An assignment with an empty value, a block scalar
124
- * or an unclosed quote also suppresses the rest of the text. A replaced assignment and a line the final gate
125
- * suppresses keep their quote markers (`>`). The complete input is checked before the output cap clips the result.
145
+ * stays as written. An assignment with an empty value, a block scalar or an unclosed quote also suppresses the rest of
146
+ * the text. A line the final gate suppresses that introduces a value, ending with `:` or `=`, or with `is`, `are`,
147
+ * `was`, `were`, `be`, `below`, `follows` or `set`, `reset`, `changed` or `updated` followed by `to` (`below` and
148
+ * `follows` also with a full stop), also suppresses the value: the next line that holds text at the introduction's
149
+ * quote depth, past any blank lines, and the lines after it in its paragraph, which a blank line or a change of quote
150
+ * depth ends. One that ends with its cue, or with its cue and a full stop, as a label above its value does, also
151
+ * suppresses the next line that holds text when that line is one word at the label's quote depth. A line that holds
152
+ * text at another depth ends either and stays. A gated line that ends any other way, such as `Reset your password from
153
+ * Settings.` or `Your password was changed.`, leaves the next line alone. Every mark keeps its line's quote markers
154
+ * (`>`), each run of spaces and tabs among them shortened to one character, so trimming still reads removed history
155
+ * as quoted and a mark holds none of the padding of the line it replaces. The complete input is checked before the
156
+ * output cap clips the result.
126
157
  *
127
158
  * @param input Decoded text: a body or one display field.
128
159
  * @param policy The input, line and output bounds.
@@ -137,34 +168,60 @@ export function sanitizeMailText(input, policy) {
137
168
  let suppressedLines = 0;
138
169
  let insideKey = false;
139
170
  let credentialTail = false;
171
+ // After a gated line that introduces a value: `value` until the next line that holds text at the introduction's quote
172
+ // depth, which is the value, then `paragraph` while the lines after it hold text at that depth. After a gated line
173
+ // that ends with its cue: `label` until the next line that holds text, which is its value when it is one word at the
174
+ // label's depth. Blank lines before the value are passed over; a line that holds text at another depth ends either.
175
+ let introduced = 'none';
176
+ let valueDepth = 0;
140
177
  const lines = [];
141
178
  for (const raw of normalized.split('\n')) {
179
+ // Read before any branch: every mark keeps the line's quote markers, so removal cannot turn quoted history into
180
+ // fresh text and trimming still finds it.
181
+ const quote = raw.match(quotePrefix)?.[0] ?? '';
182
+ const marked = markPrefix(quote);
183
+ let line = raw.slice(quote.length);
184
+ let withinValue = false;
185
+ if (introduced !== 'none') {
186
+ const held = line.trim();
187
+ if (held === '') {
188
+ if (introduced === 'paragraph')
189
+ introduced = 'none';
190
+ }
191
+ else if (quoteDepth(quote) !== valueDepth)
192
+ introduced = 'none';
193
+ else if (introduced === 'label') {
194
+ introduced = 'none';
195
+ withinValue = !/\s/.test(held);
196
+ }
197
+ else {
198
+ introduced = 'paragraph';
199
+ withinValue = true;
200
+ }
201
+ }
142
202
  if (credentialTail) {
143
203
  suppressedLines++;
144
- lines.push(lineMark);
204
+ lines.push(marked + lineMark);
145
205
  continue;
146
206
  }
147
207
  if (insideKey || beginKey.test(raw)) {
148
208
  if (!insideKey)
149
209
  secretRedactions++;
150
210
  insideKey = !endKey.test(raw);
151
- lines.push(secretMark);
211
+ lines.push(marked + secretMark);
152
212
  continue;
153
213
  }
154
214
  if (raw.length > policy.maxLineCharacters || unresolved.test(raw) || holdsNamedReference(raw)) {
155
215
  suppressedLines++;
156
- lines.push(lineMark);
216
+ lines.push(marked + lineMark);
157
217
  continue;
158
218
  }
159
- // Preserve quote depth so removal cannot turn quoted history into fresh text.
160
- const quote = raw.match(/^([ \t]*(?:>[ \t]*)+)/)?.[0] ?? '';
161
- let line = raw.slice(quote.length);
162
219
  if (assignment.test(line) || containsAuthenticatedUrl(line) || /\bsshpass\s+-p\b/i.test(line)) {
163
220
  const found = assignment.exec(line);
164
221
  const value = found ? line.slice(found.index + found[0].length).trim() : null;
165
222
  credentialTail = value !== null && (value === '' || /^[|>][+-]?$/.test(value) || ((value[0] === '"' || value[0] === "'") && value.lastIndexOf(value[0]) === 0));
166
223
  secretRedactions++;
167
- lines.push(quote + secretMark);
224
+ lines.push(marked + secretMark);
168
225
  continue;
169
226
  }
170
227
  for (const source of shapeSources) {
@@ -182,8 +239,25 @@ export function sanitizeMailText(input, policy) {
182
239
  return token; addressRedactions++; return addressMark; });
183
240
  const inspected = line.split(secretMark).join('').split(lineMark).join('');
184
241
  if (residual.test(inspected) || endKey.test(inspected)) {
242
+ // "Your password is:" names no assignment, so the value it introduces is on a later line. A label inside a value's
243
+ // paragraph leaves the paragraph's removal in place; one that is the word a label above it took ("Password" under
244
+ // "Your Wi-Fi password") is a label of its own.
245
+ const end = line.trimEnd();
246
+ if (introduction.test(end)) {
247
+ introduced = 'value';
248
+ valueDepth = quoteDepth(quote);
249
+ }
250
+ else if (introduced !== 'paragraph' && labelled.test(end)) {
251
+ introduced = 'label';
252
+ valueDepth = quoteDepth(quote);
253
+ }
185
254
  suppressedLines++;
186
- lines.push(quote + lineMark);
255
+ lines.push(marked + lineMark);
256
+ continue;
257
+ }
258
+ if (withinValue) {
259
+ suppressedLines++;
260
+ lines.push(marked + lineMark);
187
261
  continue;
188
262
  }
189
263
  lines.push(quote + line);
@@ -193,7 +267,29 @@ export function sanitizeMailText(input, policy) {
193
267
  return { text, addressRedactions, secretRedactions, suppressedLines, truncated: text.length < complete.length };
194
268
  }
195
269
  /**
196
- * Use for every filename, label name and display field, after MIME decoding. Applies the same rules as
270
+ * Whether decoded text holds nothing but whitespace once its percent and character references are decoded, its
271
+ * padding collapsed and its format and control characters removed, the steps `sanitizeMailText` takes before any
272
+ * other. A MIME reader uses it to pass over an alternative whose text would sanitize away, such as a plain part of
273
+ * `&nbsp;` and `&#8203;` beside the HTML that holds the message.
274
+ *
275
+ * @param input Decoded text: one MIME part's body.
276
+ * @param maxInputCharacters The sanitizer's input cap. Text above it, before or after decoding, is not blank: the
277
+ * sanitizer refuses it rather than emptying it.
278
+ * @returns True when nothing but whitespace is left.
279
+ */
280
+ export function blankMailText(input, maxInputCharacters) {
281
+ try {
282
+ return canonical(input, maxInputCharacters).trim().length === 0;
283
+ }
284
+ catch (error) {
285
+ if (error instanceof GmailTextFault)
286
+ return false;
287
+ throw error;
288
+ }
289
+ }
290
+ /**
291
+ * Use for every filename, label name and display field: a header value or filename after MIME decoding, and a label
292
+ * name as the labels response gives it, since that JSON text is never MIME encoded. Applies the same rules as
197
293
  * `sanitizeMailText` to the complete value, folds each whitespace run to one space and trims, then applies the
198
294
  * output cap.
199
295
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mailSanitize.js","sourceRoot":"","sources":["../src/mailSanitize.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mailSanitize.js","sourceRoot":"","sources":["../src/mailSanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA4ClG,yGAAyG;AACzG,MAAM,OAAO,cAAe,SAAQ,KAAK;IAElB;IADrB,sDAAsD;IACtD,YAAqB,MAAwB;QAC3C,KAAK,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;QADX,WAAM,GAAN,MAAM,CAAkB;QACZ,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC9D,CAAC;CACF;AAED,MAAM,WAAW,GAAG,mBAAmB,CAAC;AACxC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACtC,MAAM,QAAQ,GAAG,mCAAmC,CAAC;AACrD,oHAAoH;AACpH,oHAAoH;AACpH,0GAA0G;AAC1G,MAAM,YAAY,GAAsB;IACtC,MAAM,CAAC,GAAG,CAAA,6HAA6H;IACvI,MAAM,CAAC,GAAG,CAAA,+BAA+B;IACzC,MAAM,CAAC,GAAG,CAAA,qBAAqB;IAC/B,MAAM,CAAC,GAAG,CAAA,0BAA0B;IACpC,MAAM,CAAC,GAAG,CAAA,wCAAwC;IAClD,MAAM,CAAC,GAAG,CAAA,wCAAwC;IAClD,MAAM,CAAC,GAAG,CAAA,gFAAgF;CAC3F,CAAC;AACF,oHAAoH;AACpH,oHAAoH;AACpH,uHAAuH;AACvH,4EAA4E;AAC5E,MAAM,UAAU,GAAG,8UAA8U,CAAC;AAClW,mHAAmH;AACnH,sHAAsH;AACtH,+GAA+G;AAC/G,MAAM,QAAQ,GAAG,+LAA+L,CAAC;AACjN,mHAAmH;AACnH,yHAAyH;AACzH,gHAAgH;AAChH,MAAM,YAAY,GAAG,2GAA2G,CAAC;AACjI,oHAAoH;AACpH,4CAA4C;AAC5C,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,MAAM,QAAQ,CAAC,MAAM,QAAQ,EAAE,GAAG,CAAC,CAAC;AAChE,8EAA8E;AAC9E,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAC1C,MAAM,QAAQ,GAAG,uCAAuC,CAAC;AACzD,MAAM,MAAM,GAAG,qCAAqC,CAAC;AACrD,oHAAoH;AACpH,iGAAiG;AACjG,MAAM,UAAU,GAAG,yCAAyC,CAAC;AAE7D,SAAS,QAAQ,CAAC,MAAuB;IACvC,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,MAAM,CAAC,kBAAkB,GAAG,SAAS,IAAI,MAAM,CAAC,iBAAiB,GAAG,MAAM;WACzE,MAAM,CAAC,mBAAmB,GAAG,MAAM,CAAC,kBAAkB;QAAE,MAAM,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC;AACzG,CAAC;AACD,oHAAoH;AACpH,kHAAkH;AAClH,mHAAmH;AACnH,sHAAsH;AACtH,qBAAqB;AACrB,SAAS,SAAS,CAAC,KAAa,EAAE,KAAa;IAC7C,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,MAAM,IAAI,cAAc,CAAC,iBAAiB,CAAC,CAAC;IACtE,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC;QACtB,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,GAAG,EAAE,EAAE;YAC3E,IAAI,CAAC;gBAAC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,GAAG,CAAC;YAAC,CAAC;QAC/D,CAAC,CAAC,CAAC,CAAC;QACJ,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC;aACpG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,wCAAwC,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK;YAAE,MAAM,IAAI,cAAc,CAAC,iBAAiB,CAAC,CAAC;QACrE,IAAI,IAAI,KAAK,QAAQ;YAAE,MAAM;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AACD,kHAAkH;AAClH,+FAA+F;AAC/F,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AACD,+CAA+C;AAC/C,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,KAAK,EAAE,CAAC;IACjF,OAAO,KAAK,CAAC;AACf,CAAC;AACD,sEAAsE;AACtE,SAAS,OAAO,CAAC,IAAY,EAAE,OAAe;IAC5C,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;WACrE,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAE,CAAC;QAAE,GAAG,EAAE,CAAC;IAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AACD,qHAAqH;AACrH,sHAAsH;AACtH,wBAAwB;AACxB,SAAS,wBAAwB,CAAC,IAAY;IAC5C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,2CAA2C,CAAC,EAAE,CAAC;QAC/E,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAuB;IACrE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjB,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC/D,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAAC,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAAC,IAAI,eAAe,GAAG,CAAC,CAAC;IAC7E,IAAI,SAAS,GAAG,KAAK,CAAC;IAAC,IAAI,cAAc,GAAG,KAAK,CAAC;IAClD,sHAAsH;IACtH,mHAAmH;IACnH,qHAAqH;IACrH,oHAAoH;IACpH,IAAI,UAAU,GAA6C,MAAM,CAAC;IAAC,IAAI,UAAU,GAAG,CAAC,CAAC;IACtF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,gHAAgH;QAChH,0CAA0C;QAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;gBAAC,IAAI,UAAU,KAAK,WAAW;oBAAE,UAAU,GAAG,MAAM,CAAC;YAAC,CAAC;iBACpE,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,UAAU;gBAAE,UAAU,GAAG,MAAM,CAAC;iBAC1D,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;gBAAC,UAAU,GAAG,MAAM,CAAC;gBAAC,WAAW,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;iBACpF,CAAC;gBAAC,UAAU,GAAG,WAAW,CAAC;gBAAC,WAAW,GAAG,IAAI,CAAC;YAAC,CAAC;QACxD,CAAC;QACD,IAAI,cAAc,EAAE,CAAC;YAAC,eAAe,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QACnF,IAAI,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,SAAS;gBAAE,gBAAgB,EAAE,CAAC;YACnC,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;YAAC,SAAS;QAC5C,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,iBAAiB,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9F,eAAe,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;YAAC,SAAS;QAC7D,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9F,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAAC,cAAc,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAC,gBAAgB,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;YAAC,SAAS;QACrV,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,KAAK,EAAE,EAAE;YACtD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpF,gBAAgB,EAAE,CAAC;gBAAC,OAAO,UAAU,CAAC;YACxC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,mCAAmC,EACrD,GAAG,EAAE,GAAG,iBAAiB,EAAE,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAsB,EACxC,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACnG,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACvD,mHAAmH;YACnH,kHAAkH;YAClH,gDAAgD;YAChD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC3B,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAC,UAAU,GAAG,OAAO,CAAC;gBAAC,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;iBAChF,IAAI,UAAU,KAAK,WAAW,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAC,UAAU,GAAG,OAAO,CAAC;gBAAC,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;YACpH,eAAe,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;YAAC,SAAS;QAC7D,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YAAC,eAAe,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QAChF,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;AAClH,CAAC;AACD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,kBAA0B;IACrE,IAAI,CAAC;QAAC,OAAO,SAAS,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;IAAC,CAAC;IACxE,OAAO,KAAK,EAAE,CAAC;QAAC,IAAI,KAAK,YAAY,cAAc;YAAE,OAAO,KAAK,CAAC;QAAC,MAAM,KAAK,CAAC;IAAC,CAAC;AACnF,CAAC;AACD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,MAAuB;IACzE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,mBAAmB,EAAE,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACpG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC3D,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;AACvF,CAAC;AACD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAoC,EAAE,MAAuB;IAC/F,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI;QAAE,MAAM,IAAI,cAAc,CAAC,iBAAiB,CAAC,CAAC;IACvE,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACvD,IAAI,UAAU,GAAG,MAAM,CAAC,kBAAkB;YAAE,MAAM,IAAI,cAAc,CAAC,iBAAiB,CAAC,CAAC;QACxF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QACtE,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,MAAe,EAAE,OAAe,EAAU,EAAE;QACvE,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,OAAO,oBAAoB,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;IAC3H,CAAC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;QACrE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;KAC7F,CAAC;AACJ,CAAC"}
@@ -1,5 +1,16 @@
1
1
  import { type SourceCachePermission, type SourceCacheHeaders, type SourceCacheDecision, type SourceSyncReadResult } from '@framers/agentos-ext-account-sources';
2
2
  import { type GmailMappingBounds } from './mime.js';
3
+ /** A Gmail inbox tab beside Primary, by its `category:` search name. */
4
+ export type GmailCategory = 'forums' | 'promotions' | 'social' | 'updates';
5
+ /** Every category a client or a mapper can leave out, in the order the scan query names them. */
6
+ export declare const GMAIL_CATEGORIES: readonly GmailCategory[];
7
+ /**
8
+ * The categories an `excludedCategories` option names, deduplicated and in `GMAIL_CATEGORIES` order: none for an
9
+ * undefined option, null when the value is not an array of category names.
10
+ */
11
+ export declare function gmailCategories(value: unknown): readonly GmailCategory[] | null;
12
+ /** The system labels of the given categories. */
13
+ export declare const categoryLabels: (categories: readonly GmailCategory[]) => ReadonlySet<string>;
3
14
  /** The per-read values of one `map` call. The host supplies every value; none comes from a browser request. */
4
15
  export interface GmailMapThreadOptions {
5
16
  /** The requested thread id; the response must carry the same id. */
@@ -24,12 +35,23 @@ export interface GmailMapThreadOptions {
24
35
  readonly permission: SourceCachePermission | null;
25
36
  /** The thread response's own cache headers. */
26
37
  readonly cacheHeaders: SourceCacheHeaders;
27
- /** Label names from the cycle's labels response, by label id. */
38
+ /**
39
+ * Label names from the cycle's labels response, by label id. They are text from a JSON body, not MIME header values:
40
+ * each is sanitized again and never decoded as RFC 2047 words, so a literal `=?` in a name stays as written. A run of
41
+ * encoded words in a name is decoded only to look inside, and one whose text holds an address or a credential is
42
+ * replaced by what the sanitizer leaves of it.
43
+ */
28
44
  readonly labelNames: Readonly<Record<string, string>>;
29
45
  /** The labels response's own cache decision. Null, a refusal or an expired decision keeps ids without names. */
30
46
  readonly labelCache: SourceCacheDecision | null;
31
47
  /** Cancels the call between steps. */
32
48
  readonly signal?: AbortSignal;
49
+ /**
50
+ * The inbox tabs whose messages are left out of the copy, by their `category:` names; none by default. A message
51
+ * carrying such a category's label (`CATEGORY_PROMOTIONS` for `promotions`, and so on) is omitted and counted under
52
+ * `excluded_category`.
53
+ */
54
+ readonly excludedCategories?: readonly GmailCategory[];
33
55
  }
34
56
  /**
35
57
  * Maps one parsed Gmail thread into a sanitized account-source document: one thread, one document, with each retained
@@ -49,12 +71,15 @@ export declare class GmailThreadMapper {
49
71
  * Validates the whole response, filters each message by its internal date and by the spam, trash and draft labels,
50
72
  * keeps the newest eligible messages up to the cap with ties broken by id, spends the thread's character budget
51
73
  * newest first and renders the kept messages oldest first. A message's text is its sanitized header prefix followed
52
- * by its sanitized, trimmed body, and its span covers the body alone. A message that cannot be read is counted under
53
- * `metadata.omitted` by a fixed reason. The cache expiry is the earliest of the permission's retention, the read start
54
- * plus `maximumCacheMs`, the response's cache headers, every kept message's window end and the label names' expiry.
55
- * The version is the history id and `contentHash`, the SHA-256 of the normalized text, metadata and spans: a release
56
- * that normalizes text differently changes it for exactly the threads whose normalized text, metadata or spans
57
- * change, so the store writes those copies again at their next read and keeps the rest.
74
+ * by its sanitized, trimmed body, cut to the message cap (or the thread cap when that is smaller) and never shorter:
75
+ * the first message whose text does not fit in what the thread budget has left, and every older one, is counted
76
+ * under `thread_limit` instead, so the text of a retained message never depends on the rest of its thread. Its span
77
+ * covers the body alone. A message that cannot be read is counted under `metadata.omitted` by a fixed reason. The
78
+ * cache expiry is the earliest of the permission's retention, the read start plus `maximumCacheMs`, the response's
79
+ * cache headers, every kept message's window end and the label names' expiry. The version is the history id and
80
+ * `contentHash`, the SHA-256 of the normalized text, metadata and spans: a release that normalizes text differently
81
+ * changes it for exactly the threads whose normalized text, metadata or spans change, so the store writes those
82
+ * copies again at their next read and keeps the rest.
58
83
  *
59
84
  * @param input The parsed `threads.get` response in the `full` format, from a transport that capped its bytes.
60
85
  * @param options The per-read values.
@@ -1 +1 @@
1
- {"version":3,"file":"mapThread.d.ts","sourceRoot":"","sources":["../src/mapThread.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EACjD,KAAK,oBAAoB,EACtD,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,WAAW,CAAC;AAOnB,+GAA+G;AAC/G,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,qHAAqH;IACrH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAClD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,gHAAgH;IAChH,QAAQ,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAyCD;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C;;;OAGG;gBACS,MAAM,EAAE,kBAAkB;IAEtC,OAAO,CAAC,MAAM;YAKA,SAAS;IAyBvB;;;;;;;;;;;;;;;;;;OAkBG;IACG,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAmFzF"}
1
+ {"version":3,"file":"mapThread.d.ts","sourceRoot":"","sources":["../src/mapThread.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EACjD,KAAK,oBAAoB,EACtD,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,WAAW,CAAC;AAOnB,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3E,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAA0E,CAAC;AAKhI;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,aAAa,EAAE,GAAG,IAAI,CAM/E;AACD,iDAAiD;AACjD,eAAO,MAAM,cAAc,eAAgB,SAAS,aAAa,EAAE,KAAG,YAAY,MAAM,CACtB,CAAC;AACnE,+GAA+G;AAC/G,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,qHAAqH;IACrH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAClD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,gHAAgH;IAChH,QAAQ,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACxD;AA0CD;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C;;;OAGG;gBACS,MAAM,EAAE,kBAAkB;IAEtC,OAAO,CAAC,MAAM;YAKA,SAAS;IAiCvB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;CA8FzF"}
package/dist/mapThread.js CHANGED
@@ -7,9 +7,31 @@
7
7
  */
8
8
  import { createHash } from 'node:crypto';
9
9
  import { decideSourceCache, SourceSyncFault, } from '@framers/agentos-ext-account-sources';
10
- import { GmailMappingFault, mappingBounds, mappingActive, gmailId, parseMimeThread, decodedHeaders, decodeMimeWords, mimeBody, } from './mime.js';
11
- import { GmailTextFault, sanitizeMailHeaders, sanitizeMailMetadata, } from './mailSanitize.js';
10
+ import { GmailMappingFault, mappingBounds, mappingActive, gmailId, parseMimeThread, decodedHeaders, decodeMimeWords, redactMimeWords, mimeBody, } from './mime.js';
11
+ import { GmailTextFault, sanitizeMailText, sanitizeMailHeaders, sanitizeMailMetadata, } from './mailSanitize.js';
12
12
  import { messageText } from './messageText.js';
13
+ /** Every category a client or a mapper can leave out, in the order the scan query names them. */
14
+ export const GMAIL_CATEGORIES = Object.freeze(['forums', 'promotions', 'social', 'updates']);
15
+ // The system label Gmail gives a message of each category.
16
+ const CATEGORY_LABELS = Object.freeze({
17
+ forums: 'CATEGORY_FORUMS', promotions: 'CATEGORY_PROMOTIONS', social: 'CATEGORY_SOCIAL', updates: 'CATEGORY_UPDATES',
18
+ });
19
+ /**
20
+ * The categories an `excludedCategories` option names, deduplicated and in `GMAIL_CATEGORIES` order: none for an
21
+ * undefined option, null when the value is not an array of category names.
22
+ */
23
+ export function gmailCategories(value) {
24
+ if (value === undefined)
25
+ return [];
26
+ if (!Array.isArray(value))
27
+ return null;
28
+ const entries = value;
29
+ if (entries.some((entry) => !GMAIL_CATEGORIES.includes(entry)))
30
+ return null;
31
+ return GMAIL_CATEGORIES.filter((category) => entries.includes(category));
32
+ }
33
+ /** The system labels of the given categories. */
34
+ export const categoryLabels = (categories) => new Set(categories.map((category) => CATEGORY_LABELS[category]));
13
35
  // An epoch-millisecond value a Date can hold.
14
36
  const validTime = (n) => Number.isSafeInteger(n) && n >= 0 && n <= 8_640_000_000_000_000;
15
37
  const compareId = (a, b) => a < b ? -1 : a > b ? 1 : 0;
@@ -28,7 +50,8 @@ function configuration(options) {
28
50
  if (!gmailId(options.sourceId) || typeof url !== 'string' || !/^\/[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*\/?$/.test(url)
29
51
  || url.length > 512 || !validTime(options.cutoff) || !validTime(options.readStartedAt)
30
52
  || !validTime(options.receivedAt) || options.receivedAt < options.readStartedAt || options.cutoff > options.receivedAt
31
- || !Number.isSafeInteger(options.windowMs) || options.windowMs < 1 || options.windowMs > 90 * 86_400_000) {
53
+ || !Number.isSafeInteger(options.windowMs) || options.windowMs < 1 || options.windowMs > 90 * 86_400_000
54
+ || gmailCategories(options.excludedCategories) === null) {
32
55
  throw new GmailMappingFault('configuration');
33
56
  }
34
57
  }
@@ -69,12 +92,20 @@ export class GmailThreadMapper {
69
92
  const attachments = body.attachments.map((attachment) => ({
70
93
  filename: metadata(attachment.filename), mediaType: metadata(attachment.mediaType, 128), size: attachment.size,
71
94
  }));
95
+ // A label name is JSON text, never MIME encoded: decoding it as RFC 2047 words refused a literal `=?` and lost every
96
+ // message carrying the label. It is sanitized as written, and a run of encoded words in it is decoded only to look
97
+ // inside: one whose text holds an address or a credential gives way to what the sanitizer leaves of it, so nothing
98
+ // a reader could decode back is stored.
99
+ const labelText = (raw) => redactMimeWords(raw, budget, (decoded) => {
100
+ const inspected = sanitizeMailText(decoded, this.policy(this.bounds.maxInputCharacters));
101
+ return inspected.addressRedactions + inspected.secretRedactions + inspected.suppressedLines > 0 ? inspected.text : null;
102
+ });
72
103
  const labels = message.labels.map((id) => {
73
104
  const permitted = options.labelCache?.kind === 'cache' && validTime(options.labelCache.expiresAt) && options.labelCache.expiresAt > options.receivedAt && options.labelCache.evidenceId.length > 0;
74
105
  const raw = permitted && Object.hasOwn(options.labelNames, id) ? options.labelNames[id] : id;
75
106
  if (typeof raw !== 'string')
76
107
  throw new SourceSyncFault('invalid_response');
77
- return { id, name: metadata(raw) };
108
+ return { id, name: sanitizeMailMetadata(labelText(raw), this.policy(200)).text };
78
109
  });
79
110
  const lines = ['subject', 'date', 'from', 'to', 'cc']
80
111
  .filter((key) => headers[key] !== '').map((key) => key[0].toUpperCase() + key.slice(1) + ': ' + headers[key]);
@@ -89,12 +120,15 @@ export class GmailThreadMapper {
89
120
  * Validates the whole response, filters each message by its internal date and by the spam, trash and draft labels,
90
121
  * keeps the newest eligible messages up to the cap with ties broken by id, spends the thread's character budget
91
122
  * newest first and renders the kept messages oldest first. A message's text is its sanitized header prefix followed
92
- * by its sanitized, trimmed body, and its span covers the body alone. A message that cannot be read is counted under
93
- * `metadata.omitted` by a fixed reason. The cache expiry is the earliest of the permission's retention, the read start
94
- * plus `maximumCacheMs`, the response's cache headers, every kept message's window end and the label names' expiry.
95
- * The version is the history id and `contentHash`, the SHA-256 of the normalized text, metadata and spans: a release
96
- * that normalizes text differently changes it for exactly the threads whose normalized text, metadata or spans
97
- * change, so the store writes those copies again at their next read and keeps the rest.
123
+ * by its sanitized, trimmed body, cut to the message cap (or the thread cap when that is smaller) and never shorter:
124
+ * the first message whose text does not fit in what the thread budget has left, and every older one, is counted
125
+ * under `thread_limit` instead, so the text of a retained message never depends on the rest of its thread. Its span
126
+ * covers the body alone. A message that cannot be read is counted under `metadata.omitted` by a fixed reason. The
127
+ * cache expiry is the earliest of the permission's retention, the read start plus `maximumCacheMs`, the response's
128
+ * cache headers, every kept message's window end and the label names' expiry. The version is the history id and
129
+ * `contentHash`, the SHA-256 of the normalized text, metadata and spans: a release that normalizes text differently
130
+ * changes it for exactly the threads whose normalized text, metadata or spans change, so the store writes those
131
+ * copies again at their next read and keeps the rest.
98
132
  *
99
133
  * @param input The parsed `threads.get` response in the `full` format, from a transport that capped its bytes.
100
134
  * @param options The per-read values.
@@ -109,6 +143,7 @@ export class GmailThreadMapper {
109
143
  mappingActive(options.signal);
110
144
  const skipped = (reason) => ({ kind: 'skipped', id: options.sourceId, reason });
111
145
  const budget = { bounds: this.bounds, rawBytes: 0, decodedBytes: 0, parts: 0 };
146
+ const excludedLabels = categoryLabels(gmailCategories(options.excludedCategories) ?? []);
112
147
  let thread;
113
148
  try {
114
149
  thread = parseMimeThread(input, options.sourceId, budget, options.signal);
@@ -133,18 +168,29 @@ export class GmailThreadMapper {
133
168
  omit('excluded_label');
134
169
  continue;
135
170
  }
171
+ if (message.labels.some((label) => excludedLabels.has(label))) {
172
+ omit('excluded_category');
173
+ continue;
174
+ }
136
175
  eligible.push(message);
137
176
  }
138
177
  eligible.sort(newest);
139
178
  const selected = eligible.slice(0, this.bounds.maxMessages);
140
179
  omit('message_limit', eligible.length - selected.length);
180
+ // Each message keeps its own cut, whatever else the thread holds: cutting the oldest kept message to what the newer
181
+ // ones left would change its text at every reply near the cap, and the account-source store charges a message its
182
+ // copy holds nothing only when its text hash, cut and length are unchanged. The first message that does not fit
183
+ // whole in what is left reaches the cap: it and every older message are omitted under `thread_limit`, unread, as
184
+ // they were once a cut message had filled the budget.
185
+ const cut = Math.min(this.bounds.maxMessageCharacters, this.bounds.maxThreadCharacters);
141
186
  const retained = [];
142
187
  let used = 0;
188
+ let full = false;
143
189
  let lastReason = 'no_eligible_content';
144
190
  for (const message of selected) {
145
191
  mappingActive(options.signal);
146
192
  const remaining = this.bounds.maxThreadCharacters - used - (retained.length ? 2 : 0);
147
- if (remaining <= 0) {
193
+ if (full || remaining <= 0) {
148
194
  omit('thread_limit');
149
195
  continue;
150
196
  }
@@ -161,26 +207,32 @@ export class GmailThreadMapper {
161
207
  continue;
162
208
  }
163
209
  mappingActive(options.signal);
164
- const maximum = Math.min(this.bounds.maxMessageCharacters, remaining);
165
- if (normalized.prefix.length > maximum) {
210
+ if (normalized.prefix.length > cut) {
166
211
  lastReason = 'structure_limit';
167
212
  omit('thread_limit');
168
213
  continue;
169
214
  }
170
- const body = clip(normalized.body, maximum - normalized.prefix.length);
215
+ const body = clip(normalized.body, cut - normalized.prefix.length);
171
216
  const text = normalized.prefix + body;
172
217
  if (!text) {
173
218
  lastReason = 'no_eligible_content';
174
219
  omit(lastReason);
175
220
  continue;
176
221
  }
222
+ if (text.length > remaining) {
223
+ full = true;
224
+ omit('thread_limit');
225
+ continue;
226
+ }
177
227
  retained.push({ normalized, text, bodyStart: normalized.prefix.length,
178
228
  truncated: normalized.truncated || body.length < normalized.body.length });
179
229
  used += text.length + (retained.length > 1 ? 2 : 0);
180
230
  }
181
231
  if (retained.length === 0) {
182
- if (eligible.length === 0)
183
- lastReason = omitted.excluded_label ? 'excluded_label' : omitted.out_of_window ? 'out_of_window' : lastReason;
232
+ if (eligible.length === 0) {
233
+ lastReason = omitted.excluded_label || omitted.excluded_category ? 'excluded_label'
234
+ : omitted.out_of_window ? 'out_of_window' : lastReason;
235
+ }
184
236
  return skipped(lastReason);
185
237
  }
186
238
  retained.sort((a, b) => a.normalized.message.receivedAt - b.normalized.message.receivedAt