@framers/agentos-ext-gmail-source 0.1.0 → 0.3.0

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.
@@ -0,0 +1,228 @@
1
+ /**
2
+ * @fileoverview Thread document mapping: one Gmail thread becomes one account-source document whose text holds each
3
+ * retained message's sanitized header prefix and trimmed body, with message ids, body spans, labels, attachment
4
+ * listings, omission counts and the earliest permitted cache expiry. The transient MIME objects are never returned or
5
+ * persisted, and the account-source store's fences still decide what is committed.
6
+ * @module agentos-ext-gmail-source/mapThread
7
+ */
8
+ import { createHash } from 'node:crypto';
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';
12
+ import { messageText } from './messageText.js';
13
+ // An epoch-millisecond value a Date can hold.
14
+ const validTime = (n) => Number.isSafeInteger(n) && n >= 0 && n <= 8_640_000_000_000_000;
15
+ const compareId = (a, b) => a < b ? -1 : a > b ? 1 : 0;
16
+ // Newest first, ties broken by id, so the selection is stable.
17
+ const newest = (a, b) => b.receivedAt - a.receivedAt || compareId(a.id, b.id);
18
+ // Clips without leaving the high half of a surrogate pair at the end.
19
+ function clip(text, maximum) {
20
+ let end = Math.min(text.length, maximum);
21
+ if (end > 0 && end < text.length && /[\uD800-\uDBFF]/.test(text[end - 1]) && /[\uDC00-\uDFFF]/.test(text[end]))
22
+ end--;
23
+ return text.slice(0, end);
24
+ }
25
+ // Refuses options that would point attribution outside the host or leave the window or the clock unbounded.
26
+ function configuration(options) {
27
+ const url = options.sourceDetailUrl;
28
+ if (!gmailId(options.sourceId) || typeof url !== 'string' || !/^\/[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*\/?$/.test(url)
29
+ || url.length > 512 || !validTime(options.cutoff) || !validTime(options.readStartedAt)
30
+ || !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) {
32
+ throw new GmailMappingFault('configuration');
33
+ }
34
+ }
35
+ // The skip reason a refusal stands for; every other error propagates.
36
+ function mappingReason(error) {
37
+ if (error instanceof GmailMappingFault && error.reason !== 'configuration')
38
+ return error.reason;
39
+ if (error instanceof GmailTextFault && error.reason === 'input_too_large')
40
+ return 'response_too_large';
41
+ return null;
42
+ }
43
+ /**
44
+ * Maps one parsed Gmail thread into a sanitized account-source document: one thread, one document, with each retained
45
+ * message's id, dates, sanitized headers, labels, attachment listing and body span. It calls no endpoint, writes no log
46
+ * and keeps no state between calls.
47
+ */
48
+ export class GmailThreadMapper {
49
+ bounds;
50
+ /**
51
+ * @param bounds Every operational ceiling; see `GmailMappingBounds`.
52
+ * @throws {GmailMappingFault} `configuration` for an invalid bound.
53
+ */
54
+ constructor(bounds) { this.bounds = mappingBounds(bounds); }
55
+ // The sanitizer policy for one output cap.
56
+ policy(maximum) {
57
+ return { maxInputCharacters: this.bounds.maxInputCharacters,
58
+ maxLineCharacters: this.bounds.maxLineCharacters, maxOutputCharacters: Math.min(maximum, this.bounds.maxInputCharacters) };
59
+ }
60
+ // Decodes, sanitizes and trims one message; `map` counts its refusals against this message alone.
61
+ async normalize(message, budget, options) {
62
+ mappingActive(options.signal);
63
+ const metadataPolicy = this.policy(1000);
64
+ const headers = sanitizeMailHeaders(decodedHeaders(message.payload, budget), metadataPolicy);
65
+ const body = await mimeBody(message.payload, budget, options.signal);
66
+ mappingActive(options.signal);
67
+ const clean = messageText(body.text, this.policy(this.bounds.maxMessageCharacters));
68
+ const metadata = (input, maximum = 200) => sanitizeMailMetadata(decodeMimeWords(input, budget), this.policy(maximum)).text;
69
+ const attachments = body.attachments.map((attachment) => ({
70
+ filename: metadata(attachment.filename), mediaType: metadata(attachment.mediaType, 128), size: attachment.size,
71
+ }));
72
+ const labels = message.labels.map((id) => {
73
+ const permitted = options.labelCache?.kind === 'cache' && validTime(options.labelCache.expiresAt) && options.labelCache.expiresAt > options.receivedAt && options.labelCache.evidenceId.length > 0;
74
+ const raw = permitted && Object.hasOwn(options.labelNames, id) ? options.labelNames[id] : id;
75
+ if (typeof raw !== 'string')
76
+ throw new SourceSyncFault('invalid_response');
77
+ return { id, name: metadata(raw) };
78
+ });
79
+ const lines = ['subject', 'date', 'from', 'to', 'cc']
80
+ .filter((key) => headers[key] !== '').map((key) => key[0].toUpperCase() + key.slice(1) + ': ' + headers[key]);
81
+ const prefix = lines.length > 0 ? lines.join('\n') + '\n\n' : '';
82
+ if (!prefix && !clean.text)
83
+ throw new GmailMappingFault('no_eligible_content');
84
+ return { message, headers, prefix, body: clean.text,
85
+ trimmedQuote: clean.trimmedQuote, trimmedSignature: clean.trimmedSignature, truncated: clean.truncated,
86
+ attachments, labels, unsupportedParts: body.unsupportedParts };
87
+ }
88
+ /**
89
+ * Validates the whole response, filters each message by its internal date and by the spam, trash and draft labels,
90
+ * keeps the newest eligible messages up to the cap with ties broken by id, spends the thread's character budget
91
+ * 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
+ *
96
+ * @param input The parsed `threads.get` response in the `full` format, from a transport that capped its bytes.
97
+ * @param options The per-read values.
98
+ * @returns A document, or a skip with a fixed reason: a thread-wide bound was exceeded, no message survived, or the
99
+ * cache policy refused durable content.
100
+ * @throws {GmailMappingFault} `configuration` for invalid options.
101
+ * @throws {SourceSyncFault} `invalid_response` for an invalid response, never an empty success; `cancelled` once the
102
+ * signal is aborted.
103
+ */
104
+ async map(input, options) {
105
+ configuration(options);
106
+ mappingActive(options.signal);
107
+ const skipped = (reason) => ({ kind: 'skipped', id: options.sourceId, reason });
108
+ const budget = { bounds: this.bounds, rawBytes: 0, decodedBytes: 0, parts: 0 };
109
+ let thread;
110
+ try {
111
+ thread = parseMimeThread(input, options.sourceId, budget, options.signal);
112
+ }
113
+ catch (error) {
114
+ const reason = mappingReason(error);
115
+ if (reason)
116
+ return skipped(reason);
117
+ throw error;
118
+ }
119
+ const omitted = {};
120
+ const omit = (reason, count = 1) => { if (count > 0)
121
+ omitted[reason] = (omitted[reason] ?? 0) + count; };
122
+ const eligible = [];
123
+ for (const message of thread.messages) {
124
+ if (message.receivedAt > options.cutoff || message.receivedAt <= options.cutoff - options.windowMs
125
+ || !validTime(message.receivedAt + options.windowMs) || message.receivedAt + options.windowMs <= options.receivedAt) {
126
+ omit('out_of_window');
127
+ continue;
128
+ }
129
+ if (message.labels.some((label) => ['SPAM', 'TRASH', 'DRAFT'].includes(label))) {
130
+ omit('excluded_label');
131
+ continue;
132
+ }
133
+ eligible.push(message);
134
+ }
135
+ eligible.sort(newest);
136
+ const selected = eligible.slice(0, this.bounds.maxMessages);
137
+ omit('message_limit', eligible.length - selected.length);
138
+ const retained = [];
139
+ let used = 0;
140
+ let lastReason = 'no_eligible_content';
141
+ for (const message of selected) {
142
+ mappingActive(options.signal);
143
+ const remaining = this.bounds.maxThreadCharacters - used - (retained.length ? 2 : 0);
144
+ if (remaining <= 0) {
145
+ omit('thread_limit');
146
+ continue;
147
+ }
148
+ let normalized;
149
+ try {
150
+ normalized = await this.normalize(message, budget, options);
151
+ }
152
+ catch (error) {
153
+ const reason = mappingReason(error);
154
+ if (!reason)
155
+ throw error;
156
+ lastReason = reason;
157
+ omit(reason);
158
+ continue;
159
+ }
160
+ mappingActive(options.signal);
161
+ const maximum = Math.min(this.bounds.maxMessageCharacters, remaining);
162
+ if (normalized.prefix.length > maximum) {
163
+ lastReason = 'structure_limit';
164
+ omit('thread_limit');
165
+ continue;
166
+ }
167
+ const body = clip(normalized.body, maximum - normalized.prefix.length);
168
+ const text = normalized.prefix + body;
169
+ if (!text) {
170
+ lastReason = 'no_eligible_content';
171
+ omit(lastReason);
172
+ continue;
173
+ }
174
+ retained.push({ normalized, text, bodyStart: normalized.prefix.length,
175
+ truncated: normalized.truncated || body.length < normalized.body.length });
176
+ used += text.length + (retained.length > 1 ? 2 : 0);
177
+ }
178
+ if (retained.length === 0) {
179
+ if (eligible.length === 0)
180
+ lastReason = omitted.excluded_label ? 'excluded_label' : omitted.out_of_window ? 'out_of_window' : lastReason;
181
+ return skipped(lastReason);
182
+ }
183
+ retained.sort((a, b) => a.normalized.message.receivedAt - b.normalized.message.receivedAt
184
+ || compareId(a.normalized.message.id, b.normalized.message.id));
185
+ const messages = [];
186
+ const metadataMessages = [];
187
+ const texts = [];
188
+ let offset = 0;
189
+ for (const kept of retained) {
190
+ const { normalized } = kept;
191
+ const { message, headers } = normalized;
192
+ if (texts.length)
193
+ offset += 2;
194
+ messages.push({ messageId: message.id, start: offset + kept.bodyStart, end: offset + kept.text.length,
195
+ receivedAt: message.receivedAt, windowExpiresAt: message.receivedAt + options.windowMs, truncated: kept.truncated });
196
+ metadataMessages.push({ messageId: message.id, headers: { ...headers }, labels: normalized.labels,
197
+ attachments: normalized.attachments, trimmedQuote: normalized.trimmedQuote,
198
+ trimmedSignature: normalized.trimmedSignature, unsupportedParts: normalized.unsupportedParts });
199
+ texts.push(kept.text);
200
+ offset += kept.text.length;
201
+ }
202
+ const metadata = { messages: metadataMessages,
203
+ omitted: Object.fromEntries(Object.entries(omitted).sort(([a], [b]) => compareId(a, b))),
204
+ attachmentsRead: false };
205
+ const metadataJson = JSON.stringify(metadata);
206
+ if (metadataJson.length > this.bounds.maxMetadataCharacters)
207
+ return skipped('structure_limit');
208
+ const cache = decideSourceCache({ permission: options.permission, maximumCacheMs: this.bounds.maximumCacheMs,
209
+ readStartedAt: options.readStartedAt, receivedAt: options.receivedAt,
210
+ windowExpiresAt: Math.min(...messages.map((m) => m.windowExpiresAt)), headers: options.cacheHeaders });
211
+ if (cache.kind === 'skip')
212
+ return skipped(cache.reason);
213
+ const labelExpiry = options.labelCache?.kind === 'cache' && options.labelCache.expiresAt > options.receivedAt ? options.labelCache.expiresAt : cache.expiresAt;
214
+ const allowedCache = { ...cache, expiresAt: Math.min(cache.expiresAt, labelExpiry) };
215
+ const text = texts.join('\n\n');
216
+ const contentHash = createHash('sha256').update(JSON.stringify({ text, metadata, messages })).digest('hex');
217
+ const version = thread.historyId + ':' + contentHash;
218
+ const mostRecent = [...retained].sort((a, b) => newest(a.normalized.message, b.normalized.message));
219
+ const title = mostRecent.find((m) => m.normalized.headers.subject)?.normalized.headers.subject || 'Mail thread';
220
+ mappingActive(options.signal);
221
+ return { kind: 'document', document: {
222
+ read: { item: { id: thread.id, title, size: text.length, version }, content: { text },
223
+ ref: { kind: 'gmail', title, url: options.sourceDetailUrl, version, readAt: new Date(options.receivedAt).toISOString() } },
224
+ messages, metadata, activityAt: Math.max(...messages.map((m) => m.receivedAt)), contentHash, cache: allowedCache,
225
+ } };
226
+ }
227
+ }
228
+ //# sourceMappingURL=mapThread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapThread.js","sourceRoot":"","sources":["../src/mapThread.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview Conservative trimming of a sanitized mail body: recognized reply history, a trailing quote block after
3
+ * a blank line and a short signature after its exact separator are removed; explicit forwards, inline answers and
4
+ * ambiguous prose stay. Nothing is summarized or rewritten, so a quote span refers to the returned text.
5
+ * @module agentos-ext-gmail-source/messageText
6
+ */
7
+ import { type GmailSanitizedText, type GmailTextPolicy } from './mailSanitize.js';
8
+ /** A sanitized, trimmed message body, its content-free counts and what trimming removed. */
9
+ export interface GmailMessageText extends GmailSanitizedText {
10
+ /** Whether recognized reply history or a trailing quote block was removed. */
11
+ readonly trimmedQuote: boolean;
12
+ /** Whether a short signature after its exact separator, or a final known mobile signature line, was removed. */
13
+ readonly trimmedSignature: boolean;
14
+ }
15
+ /**
16
+ * Sanitizes a decoded body with `sanitizeMailText`, then trims recognized reply history and short signatures, then
17
+ * applies the output cap without splitting a surrogate pair. A body with an explicit forward marker is not trimmed.
18
+ * Ambiguous prose, sign-offs, unmarked header-looking paragraphs and inline answers stay; nothing is summarized or
19
+ * rewritten, so quote offsets refer to the returned text.
20
+ *
21
+ * @param input A decoded plain-text body, or the inert text of an HTML body.
22
+ * @param policy The input, line and output bounds.
23
+ * @returns The retained text, the sanitizer counts and what trimming and the cap removed.
24
+ * @throws {GmailTextFault} `configuration` for an invalid policy, `input_too_large` above the input cap.
25
+ */
26
+ export declare function messageText(input: string, policy: GmailTextPolicy): GmailMessageText;
27
+ //# sourceMappingURL=messageText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messageText.d.ts","sourceRoot":"","sources":["../src/messageText.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAoB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpG,4FAA4F;AAC5F,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,gHAAgH;IAChH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAkFD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,gBAAgB,CAgBpF"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * @fileoverview Conservative trimming of a sanitized mail body: recognized reply history, a trailing quote block after
3
+ * a blank line and a short signature after its exact separator are removed; explicit forwards, inline answers and
4
+ * ambiguous prose stay. Nothing is summarized or rewritten, so a quote span refers to the returned text.
5
+ * @module agentos-ext-gmail-source/messageText
6
+ */
7
+ import { sanitizeMailText } from './mailSanitize.js';
8
+ // Explicit forward markers, after any quote prefix: they protect the whole body from trimming.
9
+ const forward = /^(?:-{2,}[ \t]*)?(?:forwarded message|begin forwarded message:|转发邮件|转寄邮件)(?:[ \t:-]|$)/i;
10
+ // An original-message separator; it counts only when structured headers follow it.
11
+ const original = /^[ \t]*-{2,}[ \t]*(?:Original Message|Replied Message)[ \t]*-{2,}[ \t]*$/i;
12
+ // A known mobile signature, recognized only as the final line after a blank line.
13
+ const mobile = /^(?:Sent from my iPhone|Sent from my iPad|Sent from my Android)$/i;
14
+ const blank = (line) => line.trim().length === 0;
15
+ const quoted = (line) => /^[ \t]*>/.test(line);
16
+ function trimBlank(lines) {
17
+ let start = 0;
18
+ let end = lines.length;
19
+ while (start < end && blank(lines[start]))
20
+ start++;
21
+ while (end > start && blank(lines[end - 1]))
22
+ end--;
23
+ return lines.slice(start, end);
24
+ }
25
+ // Whether From, Sent or Date, and To or Subject header lines follow the separator before the first blank line.
26
+ function structuredHeaders(lines, start) {
27
+ const found = new Set();
28
+ for (let i = start; i < Math.min(start + 8, lines.length); i++) {
29
+ const line = lines[i];
30
+ if (blank(line)) {
31
+ if (found.size > 0)
32
+ break;
33
+ else
34
+ continue;
35
+ }
36
+ const header = line.match(/^[ \t]*(From|Sent|Date|To|Subject):[ \t]*\S/i);
37
+ if (!header)
38
+ return false;
39
+ found.add(header[1].toLowerCase());
40
+ }
41
+ return found.has('from') && (found.has('sent') || found.has('date'))
42
+ && (found.has('to') || found.has('subject'));
43
+ }
44
+ // The index after a reply introducer at `index`: "On ... wrote:" on one line or wrapped over two short lines.
45
+ function replyEnd(lines, index) {
46
+ const first = lines[index];
47
+ if (first.length <= 300 && /^[ \t]*On .+ wrote:[ \t]*$/i.test(first))
48
+ return index + 1;
49
+ const second = lines[index + 1];
50
+ if (second !== undefined && first.length <= 220 && second.length <= 220
51
+ && /^[ \t]*On .+/i.test(first) && /.+ wrote:[ \t]*$/i.test(second))
52
+ return index + 2;
53
+ return null;
54
+ }
55
+ // Removes reply history only when every nonblank line after its introducer is quoted, or a structured original
56
+ // message, then a trailing quote block that follows a blank line; a body that is only quotes stays.
57
+ function cutQuotes(input) {
58
+ let lines = [...input];
59
+ let changed = false;
60
+ let lastUnquoted = -1;
61
+ let lastNonblank = -1;
62
+ for (let j = 0; j < lines.length; j++) {
63
+ if (!blank(lines[j])) {
64
+ lastNonblank = j;
65
+ if (!quoted(lines[j]))
66
+ lastUnquoted = j;
67
+ }
68
+ }
69
+ for (let i = 1; i < lines.length; i++) {
70
+ if (!blank(lines[i - 1]))
71
+ continue;
72
+ const end = replyEnd(lines, i);
73
+ if (end !== null) {
74
+ const tailIsQuoted = end > lastUnquoted && end <= lastNonblank;
75
+ if (tailIsQuoted) {
76
+ lines = trimBlank(lines.slice(0, i));
77
+ changed = true;
78
+ break;
79
+ }
80
+ }
81
+ if (original.test(lines[i]) && structuredHeaders(lines, i + 1)) {
82
+ lines = trimBlank(lines.slice(0, i));
83
+ changed = true;
84
+ break;
85
+ }
86
+ }
87
+ let cursor = lines.length;
88
+ let count = 0;
89
+ while (cursor > 0 && (blank(lines[cursor - 1]) || quoted(lines[cursor - 1]))) {
90
+ if (quoted(lines[cursor - 1]))
91
+ count++;
92
+ cursor--;
93
+ }
94
+ if (count > 0 && cursor > 0 && cursor < lines.length && blank(lines[cursor])) {
95
+ lines = trimBlank(lines.slice(0, cursor));
96
+ changed = true;
97
+ }
98
+ return { lines, changed };
99
+ }
100
+ // Removes at most 12 short unquoted lines after an exact "-- " line that follows a blank line, or a final known
101
+ // mobile signature line.
102
+ function cutSignature(input) {
103
+ const lines = [...input];
104
+ for (let i = 1; i < lines.length; i++) {
105
+ if (lines[i] !== '-- ' || !blank(lines[i - 1]) || lines.length - i - 1 > 12)
106
+ continue;
107
+ const suffix = lines.slice(i + 1);
108
+ if (suffix.length <= 12 && suffix.join('\n').length <= 1000 && !suffix.some(quoted)) {
109
+ return { lines: trimBlank(lines.slice(0, i)), changed: true };
110
+ }
111
+ }
112
+ const last = lines.length - 1;
113
+ if (last >= 2 && mobile.test(lines[last].trim()) && blank(lines[last - 1])
114
+ && lines.slice(0, last - 1).some((line) => !blank(line))) {
115
+ return { lines: trimBlank(lines.slice(0, last - 1)), changed: true };
116
+ }
117
+ return { lines, changed: false };
118
+ }
119
+ /**
120
+ * Sanitizes a decoded body with `sanitizeMailText`, then trims recognized reply history and short signatures, then
121
+ * applies the output cap without splitting a surrogate pair. A body with an explicit forward marker is not trimmed.
122
+ * Ambiguous prose, sign-offs, unmarked header-looking paragraphs and inline answers stay; nothing is summarized or
123
+ * rewritten, so quote offsets refer to the returned text.
124
+ *
125
+ * @param input A decoded plain-text body, or the inert text of an HTML body.
126
+ * @param policy The input, line and output bounds.
127
+ * @returns The retained text, the sanitizer counts and what trimming and the cap removed.
128
+ * @throws {GmailTextFault} `configuration` for an invalid policy, `input_too_large` above the input cap.
129
+ */
130
+ export function messageText(input, policy) {
131
+ // Validate the caller's output cap before temporarily widening it for trimming.
132
+ sanitizeMailText('', policy);
133
+ const safe = sanitizeMailText(input, { ...policy, maxOutputCharacters: policy.maxInputCharacters });
134
+ let lines = trimBlank(safe.text.split('\n'));
135
+ let trimmedQuote = false;
136
+ let trimmedSignature = false;
137
+ if (!lines.some((line) => forward.test(line.replace(/^[ \t>]*/, '')))) {
138
+ const quotes = cutQuotes(lines);
139
+ lines = quotes.lines;
140
+ trimmedQuote = quotes.changed;
141
+ const signature = cutSignature(lines);
142
+ lines = signature.lines;
143
+ trimmedSignature = signature.changed;
144
+ }
145
+ const complete = lines.join('\n');
146
+ let end = Math.min(complete.length, policy.maxOutputCharacters);
147
+ if (end > 0 && end < complete.length && /[\uD800-\uDBFF]/.test(complete[end - 1])
148
+ && /[\uDC00-\uDFFF]/.test(complete[end]))
149
+ end--;
150
+ const text = complete.slice(0, end);
151
+ return { ...safe, text, truncated: safe.truncated || text.length < complete.length, trimmedQuote, trimmedSignature };
152
+ }
153
+ //# sourceMappingURL=messageText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messageText.js","sourceRoot":"","sources":["../src/messageText.ts"],"names":[],"mappings":"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"}
package/dist/mime.d.ts ADDED
@@ -0,0 +1,141 @@
1
+ import { type SourceSyncSkipReason } from '@framers/agentos-ext-account-sources';
2
+ import type { GmailHeaderInput } from './mailSanitize.js';
3
+ /**
4
+ * The ceilings one mapper enforces, each a positive safe integer no greater than the value in brackets. They are
5
+ * operating choices, not Gmail service limits.
6
+ */
7
+ export interface GmailMappingBounds {
8
+ /** Bytes of recognized strings read from one parsed thread response (2,097,152). */
9
+ readonly maxResponseBytes: number;
10
+ /** Bytes decoded from bodies and encoded header words in one thread (2,097,152). */
11
+ readonly maxDecodedBytes: number;
12
+ /** MIME nesting depth, a message's payload being level 1 (20). */
13
+ readonly maxMimeDepth: number;
14
+ /** MIME parts across every message of the thread, and the entries any one list may hold (1,000). */
15
+ readonly maxMimeParts: number;
16
+ /** Messages retained in one thread document, newest first (100). */
17
+ readonly maxMessages: number;
18
+ /** UTF-16 code units of one message's header prefix and body together (20,000). */
19
+ readonly maxMessageCharacters: number;
20
+ /** UTF-16 code units of the thread document's text, separators included (200,000). */
21
+ readonly maxThreadCharacters: number;
22
+ /** Characters of the document's serialized metadata (200,000). */
23
+ readonly maxMetadataCharacters: number;
24
+ /** Characters one string may hold before or after decoding, and the sanitizer's input cap (2,097,152). */
25
+ readonly maxInputCharacters: number;
26
+ /** The sanitizer's line cap: a longer line is suppressed (65,536). */
27
+ readonly maxLineCharacters: number;
28
+ /** Cache lifetime in milliseconds a document may receive before permission and response limits (86,400,000). */
29
+ readonly maximumCacheMs: number;
30
+ }
31
+ /**
32
+ * A mapper's fixed refusal; its message is `gmail_mapping_<reason>` and never carries mail text. `configuration` is
33
+ * thrown for invalid bounds or options. `map` catches every other reason and answers it as a skipped thread, or counts
34
+ * it against the one message it concerns.
35
+ */
36
+ export declare class GmailMappingFault extends Error {
37
+ readonly reason: 'configuration' | SourceSyncSkipReason;
38
+ /** @param reason `configuration`, or the skip reason the refusal stands for. */
39
+ constructor(reason: 'configuration' | SourceSyncSkipReason);
40
+ }
41
+ /** One MIME part as this package reads it. Internal: never persisted and not exported from the package root. */
42
+ export interface MimePart {
43
+ /** The media type in lower case. */
44
+ readonly mimeType: string;
45
+ /** Gmail's filename for the part; empty when there is none. */
46
+ readonly filename: string;
47
+ readonly headers: readonly GmailHeaderInput[];
48
+ /** Gmail's decoded byte count of the body. */
49
+ readonly size: number;
50
+ /** The base64url body, kept only for a text/plain or text/html part outside every attachment; otherwise empty. */
51
+ readonly data: string;
52
+ /** Whether the body sits behind an attachment id. */
53
+ readonly external: boolean;
54
+ /** Whether the part is listed as an attachment instead of read. */
55
+ readonly attachment: boolean;
56
+ readonly parts: readonly MimePart[];
57
+ }
58
+ /** One message's protocol fields. Internal. */
59
+ export interface MimeMessage {
60
+ readonly id: string;
61
+ /** Gmail's `internalDate`, epoch milliseconds. */
62
+ readonly receivedAt: number;
63
+ /** Label ids, unique and sorted. */
64
+ readonly labels: readonly string[];
65
+ readonly payload: MimePart;
66
+ }
67
+ /** One thread's protocol fields. Internal. */
68
+ export interface MimeThread {
69
+ readonly id: string;
70
+ /** The thread's history value, decimal digits. */
71
+ readonly historyId: string;
72
+ readonly messages: readonly MimeMessage[];
73
+ }
74
+ /** An attachment as listed: its contents are never read. Internal. */
75
+ export interface MimeAttachment {
76
+ readonly filename: string;
77
+ readonly mediaType: string;
78
+ readonly size: number;
79
+ }
80
+ /** A message body before sanitization, with its attachment list. Internal. */
81
+ export interface MimeBody {
82
+ readonly text: string;
83
+ readonly attachments: readonly MimeAttachment[];
84
+ /** Parts whose media type is not read, and alternatives that offered no readable branch. */
85
+ readonly unsupportedParts: number;
86
+ }
87
+ /** The running counts of one `map` call, checked against its bounds. Internal. */
88
+ export interface MimeBudget {
89
+ readonly bounds: GmailMappingBounds;
90
+ rawBytes: number;
91
+ decodedBytes: number;
92
+ parts: number;
93
+ }
94
+ /** Whether a value is an accepted Gmail message or thread id: 1 to 64 hexadecimal characters. */
95
+ export declare const gmailId: (value: unknown) => value is string;
96
+ /** Throws `SourceSyncFault('cancelled')` once the signal is aborted. */
97
+ export declare function mappingActive(signal?: AbortSignal): void;
98
+ /**
99
+ * Validates and freezes a mapper's bounds.
100
+ *
101
+ * @throws {GmailMappingFault} `configuration` when a bound is not a positive safe integer or exceeds its ceiling, or
102
+ * when the message or thread character cap exceeds the input cap.
103
+ */
104
+ export declare function mappingBounds(input: GmailMappingBounds): GmailMappingBounds;
105
+ /**
106
+ * Validate the whole structure before decoding any selected message. Copies only the fields this package reads: ids,
107
+ * internal dates, labels and each payload's MIME tree. Every message's tree, excluded messages included, counts against
108
+ * the byte, depth and part bounds. `raw`, `snippet` and unknown fields are never read.
109
+ *
110
+ * @param value The parsed `threads.get` response.
111
+ * @param sourceId The thread id the caller asked for; any other id is an invalid response.
112
+ * @param budget The call's running counts.
113
+ * @param signal Checked before each part.
114
+ * @throws {SourceSyncFault} `invalid_response` for an invalid shape, id, history value, date, label, media type or a
115
+ * repeated message id; `cancelled` once the signal is aborted.
116
+ * @throws {GmailMappingFault} `response_too_large` or `structure_limit` when a bound is exceeded.
117
+ */
118
+ export declare function parseMimeThread(value: unknown, sourceId: string, budget: MimeBudget, signal?: AbortSignal): MimeThread;
119
+ /**
120
+ * Decoding is followed by sanitation even when the input looked like ASCII. Decodes the RFC 2047 encoded words (B and
121
+ * Q) of one header value with a fatal decoder for each declared charset; whitespace between adjacent encoded words is
122
+ * dropped, as RFC 2047 requires.
123
+ *
124
+ * @throws {GmailMappingFault} `invalid_encoding` for a malformed or overlong word, invalid bytes or a value that still
125
+ * holds an encoded-word opener after decoding; `unsupported_charset` for a charset the runtime does not decode;
126
+ * `response_too_large` above the character or decoded-byte bound.
127
+ */
128
+ export declare function decodeMimeWords(input: string, budget: MimeBudget): string;
129
+ /** A part's Subject, Date, From, To and Cc, decoded; Bcc and every other header are never decoded or returned. */
130
+ export declare function decodedHeaders(part: MimePart, budget: MimeBudget): readonly GmailHeaderInput[];
131
+ /**
132
+ * Select before decoding, and never interpret Content-Transfer-Encoding a second time: Gmail's `data` already holds the
133
+ * part's bytes. Lists the message's attachments and builds its body text. Within `multipart/alternative` the branch
134
+ * with eligible plain text wins over HTML; other multipart containers join their text children in MIME order. HTML
135
+ * becomes inert text through `HtmlLoader` given an in-memory Buffer. Other media types are counted, not read.
136
+ *
137
+ * @throws {GmailMappingFault} `invalid_encoding`, `unsupported_charset` or `response_too_large` for the message.
138
+ * @throws {SourceSyncFault} `cancelled` once the signal is aborted.
139
+ */
140
+ export declare function mimeBody(root: MimePart, budget: MimeBudget, signal?: AbortSignal): Promise<MimeBody>;
141
+ //# sourceMappingURL=mime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../src/mime.ts"],"names":[],"mappings":"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"}