@aaronsb/google-workspace-mcp 4.6.0 → 4.7.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.
- package/build/accounts/oauth.js +6 -1
- package/build/accounts/oauth.js.map +1 -1
- package/build/factory/manifest/gmail.yaml +211 -6
- package/build/factory/safety.js +35 -11
- package/build/factory/safety.js.map +1 -1
- package/build/server/call-context.d.ts +12 -0
- package/build/server/call-context.js +20 -0
- package/build/server/call-context.js.map +1 -0
- package/build/server/handler.d.ts +4 -0
- package/build/server/handler.js +9 -1
- package/build/server/handler.js.map +1 -1
- package/build/server/preview-gate.d.ts +36 -0
- package/build/server/preview-gate.js +105 -0
- package/build/server/preview-gate.js.map +1 -0
- package/build/server/scratchpad/adapters/import-drive.js +12 -31
- package/build/server/scratchpad/adapters/import-drive.js.map +1 -1
- package/build/server/scratchpad/adapters/send-workspace.js +23 -20
- package/build/server/scratchpad/adapters/send-workspace.js.map +1 -1
- package/build/server/scratchpad/handler.js +28 -30
- package/build/server/scratchpad/handler.js.map +1 -1
- package/build/server/scratchpad/manager.d.ts +1 -0
- package/build/server/scratchpad/manager.js.map +1 -1
- package/build/server/tools.js +2 -1
- package/build/server/tools.js.map +1 -1
- package/build/services/drive/patch.js +4 -23
- package/build/services/drive/patch.js.map +1 -1
- package/build/services/drive/workspace-download.d.ts +24 -0
- package/build/services/drive/workspace-download.js +50 -0
- package/build/services/drive/workspace-download.js.map +1 -0
- package/build/services/gmail/filters.d.ts +88 -0
- package/build/services/gmail/filters.js +504 -0
- package/build/services/gmail/filters.js.map +1 -0
- package/build/services/gmail/hydrate.d.ts +29 -0
- package/build/services/gmail/hydrate.js +116 -0
- package/build/services/gmail/hydrate.js.map +1 -0
- package/build/services/gmail/patch.js +72 -116
- package/build/services/gmail/patch.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gmail filters — routing applied to mail as it arrives. ADR-309, #202.
|
|
3
|
+
*
|
|
4
|
+
* A filter is a standing-effect write: it keeps acting after the call, on messages the
|
|
5
|
+
* call never saw. So the lifecycle is gated. `previewFilter` evaluates a filter against the
|
|
6
|
+
* mail already there and mints a token for that exact filter; `createFilter` and
|
|
7
|
+
* `updateFilter` refuse without it. Every action Gmail supports stays available, and the
|
|
8
|
+
* preview is where a dangerous one (trash, forward) is explained.
|
|
9
|
+
*
|
|
10
|
+
* Gmail has no `filters.update`. `updateFilter` creates the replacement first and deletes
|
|
11
|
+
* the original after, so a failure part-way leaves two filters, never none.
|
|
12
|
+
*
|
|
13
|
+
* Parameters are flat, like every other operation on this tool: criteria are `match*`,
|
|
14
|
+
* actions are `addLabelIds`, `removeLabelIds` and `forwardTo`.
|
|
15
|
+
*/
|
|
16
|
+
import { call } from '../../google/client.js';
|
|
17
|
+
import { GoogleApiError } from '../../google/errors.js';
|
|
18
|
+
import { formatShortDate, truncate } from '../../server/formatting/markdown.js';
|
|
19
|
+
import { requireString } from '../../server/handlers/validate.js';
|
|
20
|
+
import { PREVIEW_TTL_MS, canonicalJson, checkPreviewToken, describeTokenFailure, mintPreviewToken, } from '../../server/preview-gate.js';
|
|
21
|
+
import { hydrateMessages } from './hydrate.js';
|
|
22
|
+
// Named for the operation a token authorizes, so a token offered to its sibling says which it is for.
|
|
23
|
+
const CREATE_KIND = 'manage_email.createFilter';
|
|
24
|
+
const UPDATE_KIND = 'manage_email.updateFilter';
|
|
25
|
+
/** Gmail's per-user limit. */
|
|
26
|
+
const FILTER_LIMIT = 1000;
|
|
27
|
+
/** Gmail stores a filter's size criterion as an int32. */
|
|
28
|
+
const MAX_SIZE = 2 ** 31 - 1;
|
|
29
|
+
/** How many matches the preview walks before it settles for "at least". */
|
|
30
|
+
const COUNT_CAP = 2000;
|
|
31
|
+
const SAMPLE_SIZE = 5;
|
|
32
|
+
/** Tool param → criteria field, for the string criteria. */
|
|
33
|
+
const STRING_CRITERIA = {
|
|
34
|
+
matchFrom: 'from',
|
|
35
|
+
matchTo: 'to',
|
|
36
|
+
matchSubject: 'subject',
|
|
37
|
+
matchQuery: 'query',
|
|
38
|
+
matchNegatedQuery: 'negatedQuery',
|
|
39
|
+
};
|
|
40
|
+
function str(value) {
|
|
41
|
+
if (value === undefined || value === null)
|
|
42
|
+
return undefined;
|
|
43
|
+
const s = String(value).trim();
|
|
44
|
+
return s || undefined;
|
|
45
|
+
}
|
|
46
|
+
function bool(value) {
|
|
47
|
+
return value === true || value === 'true';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A boolean param, strictly. A value read as false drops a criterion and widens the
|
|
51
|
+
* filter, so anything that is not plainly true or false is refused rather than guessed.
|
|
52
|
+
*/
|
|
53
|
+
function paramBool(value, name) {
|
|
54
|
+
if (value === undefined || value === null || value === '' || value === false || value === 'false')
|
|
55
|
+
return false;
|
|
56
|
+
if (value === true || value === 'true')
|
|
57
|
+
return true;
|
|
58
|
+
throw new Error(`${name} must be true or false, not '${String(value)}'.`);
|
|
59
|
+
}
|
|
60
|
+
function labelList(value) {
|
|
61
|
+
const items = Array.isArray(value) ? value.map(String) : String(value ?? '').split(',');
|
|
62
|
+
const ids = [...new Set(items.map((s) => s.trim()).filter(Boolean))].sort();
|
|
63
|
+
return ids.length ? ids : undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Reduce any filter, from our params or from Google, to one canonical spec, so two
|
|
67
|
+
* filters that do the same thing compare equal and a token minted over one matches the
|
|
68
|
+
* other. Empty strings, false booleans and empty label lists are absent.
|
|
69
|
+
*/
|
|
70
|
+
export function normalizeSpec(raw) {
|
|
71
|
+
const c = raw.criteria ?? {};
|
|
72
|
+
const a = raw.action ?? {};
|
|
73
|
+
const criteria = {};
|
|
74
|
+
for (const field of ['from', 'to', 'subject', 'query', 'negatedQuery']) {
|
|
75
|
+
const v = str(c[field]);
|
|
76
|
+
if (v)
|
|
77
|
+
criteria[field] = v;
|
|
78
|
+
}
|
|
79
|
+
if (bool(c.hasAttachment))
|
|
80
|
+
criteria.hasAttachment = true;
|
|
81
|
+
if (bool(c.excludeChats))
|
|
82
|
+
criteria.excludeChats = true;
|
|
83
|
+
const size = Number(c.size);
|
|
84
|
+
const comparison = str(c.sizeComparison);
|
|
85
|
+
if (size > 0 && (comparison === 'larger' || comparison === 'smaller')) {
|
|
86
|
+
criteria.size = size;
|
|
87
|
+
criteria.sizeComparison = comparison;
|
|
88
|
+
}
|
|
89
|
+
const action = {};
|
|
90
|
+
const add = labelList(a.addLabelIds);
|
|
91
|
+
const remove = labelList(a.removeLabelIds);
|
|
92
|
+
const forward = str(a.forward)?.toLowerCase();
|
|
93
|
+
if (add)
|
|
94
|
+
action.addLabelIds = add;
|
|
95
|
+
if (remove)
|
|
96
|
+
action.removeLabelIds = remove;
|
|
97
|
+
if (forward)
|
|
98
|
+
action.forward = forward;
|
|
99
|
+
return { criteria, action };
|
|
100
|
+
}
|
|
101
|
+
/** Build and validate the filter a call describes. Throws a sentence naming what is missing. */
|
|
102
|
+
export function buildFilterSpec(params) {
|
|
103
|
+
const criteria = {};
|
|
104
|
+
for (const [param, field] of Object.entries(STRING_CRITERIA))
|
|
105
|
+
criteria[field] = params[param];
|
|
106
|
+
criteria.hasAttachment = paramBool(params.matchHasAttachment, 'matchHasAttachment');
|
|
107
|
+
criteria.excludeChats = paramBool(params.matchExcludeChats, 'matchExcludeChats');
|
|
108
|
+
const size = params.matchSize;
|
|
109
|
+
const comparison = str(params.matchSizeComparison);
|
|
110
|
+
if (comparison && comparison !== 'larger' && comparison !== 'smaller') {
|
|
111
|
+
throw new Error(`matchSizeComparison must be 'larger' or 'smaller', not '${comparison}'.`);
|
|
112
|
+
}
|
|
113
|
+
const hasSize = size !== undefined && size !== null && size !== '';
|
|
114
|
+
if (hasSize !== Boolean(comparison)) {
|
|
115
|
+
throw new Error('matchSize and matchSizeComparison go together: a size in bytes, and whether matches are larger or smaller.');
|
|
116
|
+
}
|
|
117
|
+
const bytes = Number(size);
|
|
118
|
+
if (hasSize && !(Number.isInteger(bytes) && bytes > 0 && bytes <= MAX_SIZE)) {
|
|
119
|
+
throw new Error(`matchSize must be a whole number of bytes from 1 to ${MAX_SIZE}, not '${String(size)}'.`);
|
|
120
|
+
}
|
|
121
|
+
criteria.size = hasSize ? bytes : undefined;
|
|
122
|
+
criteria.sizeComparison = comparison;
|
|
123
|
+
const spec = normalizeSpec({
|
|
124
|
+
criteria,
|
|
125
|
+
action: { addLabelIds: params.addLabelIds, removeLabelIds: params.removeLabelIds, forward: params.forwardTo },
|
|
126
|
+
});
|
|
127
|
+
const { excludeChats: _ignored, ...matching } = spec.criteria;
|
|
128
|
+
if (Object.keys(matching).length === 0) {
|
|
129
|
+
throw new Error('A filter needs at least one criterion: matchFrom, matchTo, matchSubject, matchQuery, ' +
|
|
130
|
+
'matchNegatedQuery, matchHasAttachment, or matchSize with matchSizeComparison.');
|
|
131
|
+
}
|
|
132
|
+
if (Object.keys(spec.action).length === 0) {
|
|
133
|
+
throw new Error('A filter needs at least one action: addLabelIds, removeLabelIds (e.g. INBOX to skip the inbox), or forwardTo.');
|
|
134
|
+
}
|
|
135
|
+
return spec;
|
|
136
|
+
}
|
|
137
|
+
/** The Gmail search a filter's criteria amount to. Filters and search share one syntax. */
|
|
138
|
+
export function criteriaToQuery(c) {
|
|
139
|
+
const parts = [];
|
|
140
|
+
if (c.from)
|
|
141
|
+
parts.push(`from:(${c.from})`);
|
|
142
|
+
if (c.to)
|
|
143
|
+
parts.push(`to:(${c.to})`);
|
|
144
|
+
if (c.subject)
|
|
145
|
+
parts.push(`subject:(${c.subject})`);
|
|
146
|
+
if (c.query)
|
|
147
|
+
parts.push(`(${c.query})`);
|
|
148
|
+
if (c.negatedQuery)
|
|
149
|
+
parts.push(`-(${c.negatedQuery})`);
|
|
150
|
+
if (c.hasAttachment)
|
|
151
|
+
parts.push('has:attachment');
|
|
152
|
+
if (c.size && c.sizeComparison)
|
|
153
|
+
parts.push(`${c.sizeComparison}:${c.size}`);
|
|
154
|
+
if (c.excludeChats)
|
|
155
|
+
parts.push('-in:chats');
|
|
156
|
+
return parts.join(' ');
|
|
157
|
+
}
|
|
158
|
+
/** The tool params that describe this filter, for recreating or editing it. */
|
|
159
|
+
export function specToParams(spec) {
|
|
160
|
+
const out = {};
|
|
161
|
+
for (const [param, field] of Object.entries(STRING_CRITERIA)) {
|
|
162
|
+
const v = spec.criteria[field];
|
|
163
|
+
if (v)
|
|
164
|
+
out[param] = v;
|
|
165
|
+
}
|
|
166
|
+
if (spec.criteria.hasAttachment)
|
|
167
|
+
out.matchHasAttachment = true;
|
|
168
|
+
if (spec.criteria.excludeChats)
|
|
169
|
+
out.matchExcludeChats = true;
|
|
170
|
+
if (spec.criteria.size) {
|
|
171
|
+
out.matchSize = spec.criteria.size;
|
|
172
|
+
out.matchSizeComparison = spec.criteria.sizeComparison;
|
|
173
|
+
}
|
|
174
|
+
if (spec.action.addLabelIds)
|
|
175
|
+
out.addLabelIds = spec.action.addLabelIds.join(',');
|
|
176
|
+
if (spec.action.removeLabelIds)
|
|
177
|
+
out.removeLabelIds = spec.action.removeLabelIds.join(',');
|
|
178
|
+
if (spec.action.forward)
|
|
179
|
+
out.forwardTo = spec.action.forward;
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
const SYSTEM_LABEL_EFFECTS = {
|
|
183
|
+
INBOX: { add: { text: 'kept in the inbox' }, remove: { text: 'skips the inbox: archived on arrival' } },
|
|
184
|
+
UNREAD: { add: { text: 'marked unread' }, remove: { text: 'marked read on arrival' } },
|
|
185
|
+
STARRED: { add: { text: 'starred' }, remove: { text: 'never starred' } },
|
|
186
|
+
IMPORTANT: { add: { text: 'marked important' }, remove: { text: 'never marked important' } },
|
|
187
|
+
TRASH: {
|
|
188
|
+
add: {
|
|
189
|
+
text: 'moved to trash on arrival',
|
|
190
|
+
detail: 'Gmail deletes trash permanently after 30 days, so matching mail nobody looks at is gone after that',
|
|
191
|
+
warn: true,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
SPAM: {
|
|
195
|
+
add: { text: 'sent to spam on arrival', warn: true },
|
|
196
|
+
remove: { text: 'never sent to spam' },
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
export function describeActions(action, labelNames) {
|
|
200
|
+
const effects = [];
|
|
201
|
+
const name = (id) => labelNames.get(id) ?? id;
|
|
202
|
+
for (const id of action.addLabelIds ?? []) {
|
|
203
|
+
const system = SYSTEM_LABEL_EFFECTS[id]?.add;
|
|
204
|
+
if (system)
|
|
205
|
+
effects.push(system);
|
|
206
|
+
else if (id.startsWith('CATEGORY_'))
|
|
207
|
+
effects.push({ text: `sorted into the ${id.slice(9).toLowerCase()} category` });
|
|
208
|
+
else
|
|
209
|
+
effects.push({ text: `labeled "${name(id)}"` });
|
|
210
|
+
}
|
|
211
|
+
for (const id of action.removeLabelIds ?? []) {
|
|
212
|
+
const system = SYSTEM_LABEL_EFFECTS[id]?.remove;
|
|
213
|
+
if (system)
|
|
214
|
+
effects.push(system);
|
|
215
|
+
else if (id.startsWith('CATEGORY_'))
|
|
216
|
+
effects.push({ text: `kept out of the ${id.slice(9).toLowerCase()} category` });
|
|
217
|
+
else
|
|
218
|
+
effects.push({ text: `"${name(id)}" label removed` });
|
|
219
|
+
}
|
|
220
|
+
if (action.forward) {
|
|
221
|
+
effects.push({
|
|
222
|
+
text: `forwarded in full to ${action.forward}`,
|
|
223
|
+
detail: 'every time, with no further prompt; whoever reads that address reads every match',
|
|
224
|
+
warn: true,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return effects;
|
|
228
|
+
}
|
|
229
|
+
function effectLines(action, labelNames) {
|
|
230
|
+
return describeActions(action, labelNames).map((e) => `- ${e.warn ? '⚠ ' : ''}${e.text}${e.detail ? `. ${e.detail}` : ''}`);
|
|
231
|
+
}
|
|
232
|
+
function summarize(spec, labelNames) {
|
|
233
|
+
return describeActions(spec.action, labelNames).map((e) => e.text).join('; ');
|
|
234
|
+
}
|
|
235
|
+
function describeFilter(spec, labelNames) {
|
|
236
|
+
return [`**Criteria:** \`${criteriaToQuery(spec.criteria)}\``, '**Actions:** matching mail is', ...effectLines(spec.action, labelNames)];
|
|
237
|
+
}
|
|
238
|
+
// --- Reading what the account has ---
|
|
239
|
+
async function listFilters(account) {
|
|
240
|
+
const raw = await call('gmail', 'users.settings.filters.list', { userId: 'me' }, { account });
|
|
241
|
+
const filters = (raw?.filter ?? []);
|
|
242
|
+
return filters.map((f) => ({ id: String(f.id ?? ''), ...normalizeSpec(f) }));
|
|
243
|
+
}
|
|
244
|
+
async function getStoredFilter(account, id) {
|
|
245
|
+
try {
|
|
246
|
+
const f = await call('gmail', 'users.settings.filters.get', { userId: 'me', id }, { account });
|
|
247
|
+
return { id: String(f.id ?? id), ...normalizeSpec(f) };
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
if (err instanceof GoogleApiError && err.status === 404)
|
|
251
|
+
return undefined;
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function labelNames(account) {
|
|
256
|
+
const raw = await call('gmail', 'users.labels.list', { userId: 'me' }, { account });
|
|
257
|
+
const labels = (raw?.labels ?? []);
|
|
258
|
+
return new Map(labels.filter((l) => l.id).map((l) => [String(l.id), String(l.name ?? l.id)]));
|
|
259
|
+
}
|
|
260
|
+
async function forwardingAddresses(account) {
|
|
261
|
+
const raw = await call('gmail', 'users.settings.forwardingAddresses.list', { userId: 'me' }, { account });
|
|
262
|
+
return (raw?.forwardingAddresses ?? []);
|
|
263
|
+
}
|
|
264
|
+
const same = (a, b) => canonicalJson(a) === canonicalJson(b);
|
|
265
|
+
const sameCriteria = (a, b) => canonicalJson(a.criteria) === canonicalJson(b.criteria);
|
|
266
|
+
const asSpec = (f) => ({ criteria: f.criteria, action: f.action });
|
|
267
|
+
/** Walk ids-only pages of the filter's query, up to COUNT_CAP. */
|
|
268
|
+
async function countMatches(account, q) {
|
|
269
|
+
let count = 0;
|
|
270
|
+
let estimate;
|
|
271
|
+
let pageToken;
|
|
272
|
+
const sampleIds = [];
|
|
273
|
+
do {
|
|
274
|
+
const page = await call('gmail', 'users.messages.list', {
|
|
275
|
+
userId: 'me', q, maxResults: 500, ...(pageToken ? { pageToken } : {}),
|
|
276
|
+
}, { account });
|
|
277
|
+
const ids = (page?.messages ?? []).map((m) => m.id);
|
|
278
|
+
if (estimate === undefined && typeof page?.resultSizeEstimate === 'number')
|
|
279
|
+
estimate = page.resultSizeEstimate;
|
|
280
|
+
count += ids.length;
|
|
281
|
+
sampleIds.push(...ids.slice(0, SAMPLE_SIZE - sampleIds.length));
|
|
282
|
+
pageToken = typeof page?.nextPageToken === 'string' && page.nextPageToken ? page.nextPageToken : undefined;
|
|
283
|
+
} while (pageToken && count < COUNT_CAP);
|
|
284
|
+
return { count, exact: !pageToken, estimate, sampleIds };
|
|
285
|
+
}
|
|
286
|
+
function refused(text, refs = {}) {
|
|
287
|
+
return { text, refs: { ...refs, blocked: true } };
|
|
288
|
+
}
|
|
289
|
+
// --- Operations ---
|
|
290
|
+
/** `filters` — every filter on the account, one line each. */
|
|
291
|
+
export async function handleListFilters(_params, account) {
|
|
292
|
+
const [filters, names] = await Promise.all([listFilters(account), labelNames(account)]);
|
|
293
|
+
if (filters.length === 0)
|
|
294
|
+
return { text: 'No filters on this account.', refs: { count: 0, filterIds: [] } };
|
|
295
|
+
const rows = filters.map((f) => `${f.id} | ${truncate(criteriaToQuery(f.criteria), 70)} | ${summarize(f, names)}`);
|
|
296
|
+
return {
|
|
297
|
+
text: `## Filters (${filters.length} of ${FILTER_LIMIT.toLocaleString('en-US')})\n\n${rows.join('\n')}`,
|
|
298
|
+
refs: { count: filters.length, filterId: filters[0].id, filterIds: filters.map((f) => f.id) },
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/** `getFilter` — one filter, in words, with the parameters that recreate or edit it. */
|
|
302
|
+
export async function handleGetFilter(params, account) {
|
|
303
|
+
const id = requireString(params, 'filterId');
|
|
304
|
+
const [filter, names] = await Promise.all([getStoredFilter(account, id), labelNames(account)]);
|
|
305
|
+
if (!filter)
|
|
306
|
+
return refused(`No filter ${id} on ${account}. List them with \`filters\`.`, { filterId: id });
|
|
307
|
+
const recreate = specToParams(filter);
|
|
308
|
+
return {
|
|
309
|
+
text: [
|
|
310
|
+
`## Filter ${id}`, '',
|
|
311
|
+
...describeFilter(filter, names), '',
|
|
312
|
+
`**As parameters** (for previewFilter, with filterId to edit it): \`${JSON.stringify(recreate)}\``,
|
|
313
|
+
].join('\n'),
|
|
314
|
+
refs: { filterId: id, query: criteriaToQuery(filter.criteria), params: recreate },
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* `previewFilter` — evaluate a filter without creating it, and mint the token the write
|
|
319
|
+
* needs. With `filterId`, evaluates replacing that filter and mints an update token.
|
|
320
|
+
*
|
|
321
|
+
* Problems that would make the write fail or do nothing (an unknown label, an unverified
|
|
322
|
+
* forwarding address, an exact duplicate) are errors and withhold the token. Consequences
|
|
323
|
+
* worth a second look are shown, not refused.
|
|
324
|
+
*/
|
|
325
|
+
export async function handlePreviewFilter(params, account) {
|
|
326
|
+
const spec = buildFilterSpec(params);
|
|
327
|
+
const replacingId = str(params.filterId);
|
|
328
|
+
const [filters, names, forwarding] = await Promise.all([
|
|
329
|
+
listFilters(account),
|
|
330
|
+
labelNames(account),
|
|
331
|
+
spec.action.forward ? forwardingAddresses(account) : Promise.resolve([]),
|
|
332
|
+
]);
|
|
333
|
+
const errors = [];
|
|
334
|
+
const notes = [];
|
|
335
|
+
const replacing = replacingId ? filters.find((f) => f.id === replacingId) : undefined;
|
|
336
|
+
if (replacingId && !replacing)
|
|
337
|
+
errors.push(`No filter ${replacingId} exists on this account. List them with \`filters\`.`);
|
|
338
|
+
if (replacing && same(asSpec(replacing), spec))
|
|
339
|
+
errors.push(`Filter ${replacingId} already has exactly these criteria and actions; there is nothing to change.`);
|
|
340
|
+
const byName = new Map([...names].map(([id, n]) => [n.toLowerCase(), id]));
|
|
341
|
+
for (const id of [...(spec.action.addLabelIds ?? []), ...(spec.action.removeLabelIds ?? [])]) {
|
|
342
|
+
if (names.has(id))
|
|
343
|
+
continue;
|
|
344
|
+
const hint = byName.get(id.toLowerCase());
|
|
345
|
+
errors.push(hint
|
|
346
|
+
? `'${id}' is a label name; filters take its id, ${hint}.`
|
|
347
|
+
: `No label with id '${id}' on this account. Create it with \`createLabel\`, or see ids with \`labels\`.`);
|
|
348
|
+
}
|
|
349
|
+
if (spec.action.forward) {
|
|
350
|
+
const address = forwarding.find((a) => a.forwardingEmail.toLowerCase() === spec.action.forward);
|
|
351
|
+
if (!address) {
|
|
352
|
+
errors.push(`${spec.action.forward} is not a forwarding address on this account. Gmail forwards only to ` +
|
|
353
|
+
'addresses added and verified in Gmail settings, under Forwarding and POP/IMAP.');
|
|
354
|
+
}
|
|
355
|
+
else if (address.verificationStatus !== 'accepted') {
|
|
356
|
+
errors.push(`${spec.action.forward} is a forwarding address but is not verified yet (${address.verificationStatus ?? 'unknown'}).`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const others = filters.filter((f) => f.id !== replacingId);
|
|
360
|
+
const duplicate = others.find((f) => same(asSpec(f), spec));
|
|
361
|
+
if (duplicate)
|
|
362
|
+
errors.push(`Filter ${duplicate.id} already does exactly this.`);
|
|
363
|
+
for (const f of others) {
|
|
364
|
+
if (f !== duplicate && sameCriteria(f, spec)) {
|
|
365
|
+
notes.push(`⚠ Filter ${f.id} has the same criteria and does: ${summarize(f, names)}. Both will apply to every match.`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (filters.length >= FILTER_LIMIT) {
|
|
369
|
+
errors.push(replacing
|
|
370
|
+
? `This account has ${filters.length} filters, Gmail's limit. An update creates the replacement before deleting ` +
|
|
371
|
+
`the original, and Gmail refuses the 1,001st. Delete ${replacingId} first (deleteFilter returns its parameters), ` +
|
|
372
|
+
'then preview and create the replacement.'
|
|
373
|
+
: `This account has ${filters.length} filters, Gmail's limit.`);
|
|
374
|
+
}
|
|
375
|
+
else if (filters.length >= FILTER_LIMIT - 50)
|
|
376
|
+
notes.push(`This account has ${filters.length} of Gmail's ${FILTER_LIMIT} filters.`);
|
|
377
|
+
const query = criteriaToQuery(spec.criteria);
|
|
378
|
+
const matches = await countMatches(account, query);
|
|
379
|
+
const sample = matches.sampleIds.length ? await hydrateMessages(matches.sampleIds.map((id) => ({ id })), account) : [];
|
|
380
|
+
const write = replacing ? 'updateFilter' : 'createFilter';
|
|
381
|
+
const lines = [replacing ? `## Preview: replace filter ${replacingId}` : '## Preview: new filter', ''];
|
|
382
|
+
lines.push(...describeFilter(spec, names), '');
|
|
383
|
+
if (replacing) {
|
|
384
|
+
lines.push(`**Replaces** filter ${replacingId}, which is:`, `- criteria \`${criteriaToQuery(replacing.criteria)}\``);
|
|
385
|
+
lines.push(...describeActions(replacing.action, names).map((e) => `- ${e.text}`));
|
|
386
|
+
lines.push(`Gmail has no in-place update: the replacement gets a new id, and ${replacingId} is deleted after it is created.`, '');
|
|
387
|
+
}
|
|
388
|
+
if (matches.exact) {
|
|
389
|
+
lines.push(matches.count === 0
|
|
390
|
+
? '**Matches today:** none. A filter that matches nothing yet may be mistyped, or may be for mail that has not started arriving.'
|
|
391
|
+
: `**Matches today:** ${matches.count} message${matches.count === 1 ? '' : 's'}.`);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
const est = matches.estimate !== undefined ? ` Google estimates about ${matches.estimate}, which is an estimate.` : '';
|
|
395
|
+
lines.push(`**Matches today:** at least ${matches.count}; counting stopped there.${est}`);
|
|
396
|
+
}
|
|
397
|
+
if (sample.length) {
|
|
398
|
+
lines.push('', 'Most recent matches:');
|
|
399
|
+
for (const m of sample) {
|
|
400
|
+
lines.push(m.error
|
|
401
|
+
? `${String(m.id)} | ⚠ ${String(m.error)}`
|
|
402
|
+
: `${String(m.id)} | ${truncate(String(m.from ?? ''), 30)} | ${truncate(String(m.subject ?? '(no subject)'), 50)} | ${formatShortDate(m.date)}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (matches.count > 0) {
|
|
406
|
+
lines.push('', `A filter acts only on mail that arrives after it exists; the messages counted above stay as they are (spam and trash were not counted). ` +
|
|
407
|
+
`To give them the same treatment, collect their ids with \`search\` (query \`${query}\`, idsOnly: true) and pass them to bulk_operations batch \`modify\`.`);
|
|
408
|
+
}
|
|
409
|
+
if (notes.length)
|
|
410
|
+
lines.push('', ...notes);
|
|
411
|
+
const refs = {
|
|
412
|
+
query,
|
|
413
|
+
matchCount: matches.count,
|
|
414
|
+
matchCountExact: matches.exact,
|
|
415
|
+
...(matches.estimate !== undefined ? { resultSizeEstimate: matches.estimate } : {}),
|
|
416
|
+
...(replacingId ? { filterId: replacingId } : {}),
|
|
417
|
+
};
|
|
418
|
+
if (errors.length) {
|
|
419
|
+
lines.push('', `### Cannot ${replacing ? 'replace' : 'create'} this filter`, ...errors.map((e) => `- ${e}`), '', 'No previewToken issued. Fix the parameters and preview again.');
|
|
420
|
+
return { text: lines.join('\n'), refs: { ...refs, errors } };
|
|
421
|
+
}
|
|
422
|
+
const token = replacing
|
|
423
|
+
? mintPreviewToken(UPDATE_KIND, account, { filterId: replacingId, before: asSpec(replacing), spec })
|
|
424
|
+
: mintPreviewToken(CREATE_KIND, account, { spec });
|
|
425
|
+
lines.push('', replacing
|
|
426
|
+
? `To apply this change, call \`${write}\` with filterId ${replacingId}, the same parameters, and previewToken:`
|
|
427
|
+
: `To create it, call \`${write}\` with the same parameters and previewToken:`, `\`${token}\``, `Good for ${PREVIEW_TTL_MS / 60_000} minutes, for this account and exactly these parameters.`);
|
|
428
|
+
return { text: lines.join('\n'), refs: { ...refs, previewToken: token } };
|
|
429
|
+
}
|
|
430
|
+
/** `createFilter` — create a filter its preview has already shown. */
|
|
431
|
+
export async function handleCreateFilter(params, account) {
|
|
432
|
+
const spec = buildFilterSpec(params);
|
|
433
|
+
const check = checkPreviewToken(params.previewToken, CREATE_KIND, account, { spec });
|
|
434
|
+
if (!check.ok)
|
|
435
|
+
return refused(`**Not created.** ${describeTokenFailure(check, 'createFilter', 'previewFilter')}`);
|
|
436
|
+
const [filters, names] = await Promise.all([listFilters(account), labelNames(account)]);
|
|
437
|
+
const duplicate = filters.find((f) => same(asSpec(f), spec));
|
|
438
|
+
if (duplicate)
|
|
439
|
+
return refused(`**Not created.** Filter ${duplicate.id} already does exactly this.`, { filterId: duplicate.id });
|
|
440
|
+
const created = await call('gmail', 'users.settings.filters.create', { userId: 'me', ...spec }, { account });
|
|
441
|
+
const id = String(created.id ?? '');
|
|
442
|
+
return {
|
|
443
|
+
text: [`Created filter **${id}**.`, '', ...describeFilter(spec, names), '',
|
|
444
|
+
'It acts on mail arriving from now on; messages already in the mailbox are unchanged.'].join('\n'),
|
|
445
|
+
refs: { filterId: id, created: true },
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* `updateFilter` — replace a filter with the one its preview showed.
|
|
450
|
+
*
|
|
451
|
+
* The token covers the filter being replaced as it was at preview time, so a filter that
|
|
452
|
+
* changed in the meantime is not replaced on the strength of a preview of something else.
|
|
453
|
+
*/
|
|
454
|
+
export async function handleUpdateFilter(params, account) {
|
|
455
|
+
const filterId = requireString(params, 'filterId');
|
|
456
|
+
const spec = buildFilterSpec(params);
|
|
457
|
+
const [current, filters, names] = await Promise.all([getStoredFilter(account, filterId), listFilters(account), labelNames(account)]);
|
|
458
|
+
if (!current) {
|
|
459
|
+
return refused(`**Not changed.** Filter ${filterId} no longer exists on ${account}. To make it fresh, preview without filterId and use createFilter.`, { filterId });
|
|
460
|
+
}
|
|
461
|
+
const check = checkPreviewToken(params.previewToken, UPDATE_KIND, account, { filterId, before: asSpec(current), spec });
|
|
462
|
+
if (!check.ok)
|
|
463
|
+
return refused(`**Not changed.** ${describeTokenFailure(check, 'updateFilter', 'previewFilter (with filterId)')}`, { filterId });
|
|
464
|
+
const duplicate = filters.find((f) => f.id !== filterId && same(asSpec(f), spec));
|
|
465
|
+
if (duplicate)
|
|
466
|
+
return refused(`**Not changed.** Filter ${duplicate.id} already does exactly this.`, { filterId });
|
|
467
|
+
const created = await call('gmail', 'users.settings.filters.create', { userId: 'me', ...spec }, { account });
|
|
468
|
+
const newId = String(created.id ?? '');
|
|
469
|
+
try {
|
|
470
|
+
await call('gmail', 'users.settings.filters.delete', { userId: 'me', id: filterId }, { account });
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
// Already gone is the outcome the delete was for.
|
|
474
|
+
if (!(err instanceof GoogleApiError && err.status === 404)) {
|
|
475
|
+
// Half done is a failure, not a success with a caveat: thrown, so a queue with
|
|
476
|
+
// onError 'bail' stops here instead of running on.
|
|
477
|
+
const why = err instanceof Error ? err.message : String(err);
|
|
478
|
+
throw new Error(`updateFilter half done: created the replacement filter ${newId}, but could not delete the original ` +
|
|
479
|
+
`${filterId} (${why}). Both are active now. Remove the original with deleteFilter filterId ${filterId}.`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
text: [`Replaced filter **${filterId}** with **${newId}**. Gmail has no in-place update, so the filter has a new id.`, '',
|
|
484
|
+
...describeFilter(spec, names), '',
|
|
485
|
+
'It acts on mail arriving from now on; messages already in the mailbox are unchanged.'].join('\n'),
|
|
486
|
+
refs: { filterId: newId, replacedFilterId: filterId, originalDeleted: true },
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/** `deleteFilter` — stop a filter, and return what it was so it can be put back. */
|
|
490
|
+
export async function handleDeleteFilter(params, account) {
|
|
491
|
+
const filterId = requireString(params, 'filterId');
|
|
492
|
+
const [filter, names] = await Promise.all([getStoredFilter(account, filterId), labelNames(account)]);
|
|
493
|
+
if (!filter)
|
|
494
|
+
return refused(`No filter ${filterId} on ${account}; nothing deleted. List them with \`filters\`.`, { filterId });
|
|
495
|
+
await call('gmail', 'users.settings.filters.delete', { userId: 'me', id: filterId }, { account });
|
|
496
|
+
const recreate = specToParams(filter);
|
|
497
|
+
return {
|
|
498
|
+
text: [`Deleted filter **${filterId}**. Mail it matched now arrives without its routing.`, '', 'It was:',
|
|
499
|
+
...describeFilter(filter, names), '',
|
|
500
|
+
`To put it back, preview and create with: \`${JSON.stringify(recreate)}\``].join('\n'),
|
|
501
|
+
refs: { filterId, deleted: true, params: recreate },
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../../../src/services/gmail/filters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydration — turn the bare ids Gmail's list methods return into rows a reader can use.
|
|
3
|
+
*
|
|
4
|
+
* `messages.list` and `drafts.list` return ids and nothing else, so every row costs one
|
|
5
|
+
* `messages.get`. Shared by search, triage, listDrafts and the filter preview.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Hydrate message IDs with metadata (From, Subject, Date, snippet).
|
|
9
|
+
* Reused from the original email handler.
|
|
10
|
+
*/
|
|
11
|
+
export declare function hydrateMessages(messageIds: Array<{
|
|
12
|
+
id: string;
|
|
13
|
+
}>, account: string): Promise<Record<string, unknown>[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Hydrate draft resources with message metadata (From, To, Subject, Date, snippet).
|
|
16
|
+
*
|
|
17
|
+
* users.drafts.list returns one bare {id: draftId, message: {id, threadId}} per draft —
|
|
18
|
+
* enough to identify a draft, nothing to tell drafts apart. Each draft's message is
|
|
19
|
+
* fetched (metadata format, exactly like the search/triage hydration) and the DRAFT id
|
|
20
|
+
* stays on the row, because it — not the message id — is what deleteDraft addresses.
|
|
21
|
+
*/
|
|
22
|
+
export declare function hydrateDrafts(drafts: Array<{
|
|
23
|
+
id: string;
|
|
24
|
+
message?: {
|
|
25
|
+
id?: string;
|
|
26
|
+
threadId?: string;
|
|
27
|
+
};
|
|
28
|
+
}>, account: string): Promise<Record<string, unknown>[]>;
|
|
29
|
+
export declare function mapLimited<T, R>(items: T[], limit: number, fn: (item: T) => Promise<R>): Promise<R[]>;
|