@mcp-z/mcp-outlook 1.0.11 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/cjs/email/querying/client-filter.d.cts +6 -0
  2. package/dist/cjs/email/querying/client-filter.d.ts +6 -0
  3. package/dist/cjs/email/querying/client-filter.js +309 -0
  4. package/dist/cjs/email/querying/client-filter.js.map +1 -0
  5. package/dist/cjs/email/querying/execute-query.d.cts +1 -0
  6. package/dist/cjs/email/querying/execute-query.d.ts +1 -0
  7. package/dist/cjs/email/querying/execute-query.js +3 -2
  8. package/dist/cjs/email/querying/execute-query.js.map +1 -1
  9. package/dist/cjs/email/querying/pagination-token.d.cts +13 -0
  10. package/dist/cjs/email/querying/pagination-token.d.ts +13 -0
  11. package/dist/cjs/email/querying/pagination-token.js +84 -0
  12. package/dist/cjs/email/querying/pagination-token.js.map +1 -0
  13. package/dist/cjs/email/querying/query-builder.d.cts +18 -0
  14. package/dist/cjs/email/querying/query-builder.d.ts +18 -0
  15. package/dist/cjs/email/querying/query-builder.js +139 -89
  16. package/dist/cjs/email/querying/query-builder.js.map +1 -1
  17. package/dist/cjs/email/querying/search-execution.d.cts +1 -6
  18. package/dist/cjs/email/querying/search-execution.d.ts +1 -6
  19. package/dist/cjs/email/querying/search-execution.js +199 -62
  20. package/dist/cjs/email/querying/search-execution.js.map +1 -1
  21. package/dist/cjs/mcp/prompts/query-syntax.js +1 -1
  22. package/dist/cjs/mcp/prompts/query-syntax.js.map +1 -1
  23. package/dist/cjs/mcp/tools/message-search.d.cts +2 -2
  24. package/dist/cjs/mcp/tools/message-search.d.ts +2 -2
  25. package/dist/cjs/mcp/tools/message-search.js +14 -11
  26. package/dist/cjs/mcp/tools/message-search.js.map +1 -1
  27. package/dist/cjs/mcp/tools/messages-export-csv.d.cts +2 -2
  28. package/dist/cjs/mcp/tools/messages-export-csv.d.ts +2 -2
  29. package/dist/cjs/mcp/tools/messages-export-csv.js +9 -8
  30. package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -1
  31. package/dist/cjs/schemas/outlook-query-schema.d.cts +2 -1
  32. package/dist/cjs/schemas/outlook-query-schema.d.ts +2 -1
  33. package/dist/cjs/schemas/outlook-query-schema.js +40 -18
  34. package/dist/cjs/schemas/outlook-query-schema.js.map +1 -1
  35. package/dist/esm/email/querying/client-filter.d.ts +6 -0
  36. package/dist/esm/email/querying/client-filter.js +213 -0
  37. package/dist/esm/email/querying/client-filter.js.map +1 -0
  38. package/dist/esm/email/querying/execute-query.d.ts +1 -0
  39. package/dist/esm/email/querying/execute-query.js +2 -1
  40. package/dist/esm/email/querying/execute-query.js.map +1 -1
  41. package/dist/esm/email/querying/pagination-token.d.ts +13 -0
  42. package/dist/esm/email/querying/pagination-token.js +62 -0
  43. package/dist/esm/email/querying/pagination-token.js.map +1 -0
  44. package/dist/esm/email/querying/query-builder.d.ts +18 -0
  45. package/dist/esm/email/querying/query-builder.js +109 -69
  46. package/dist/esm/email/querying/query-builder.js.map +1 -1
  47. package/dist/esm/email/querying/search-execution.d.ts +1 -6
  48. package/dist/esm/email/querying/search-execution.js +148 -56
  49. package/dist/esm/email/querying/search-execution.js.map +1 -1
  50. package/dist/esm/mcp/prompts/query-syntax.js +4 -1
  51. package/dist/esm/mcp/prompts/query-syntax.js.map +1 -1
  52. package/dist/esm/mcp/tools/message-search.d.ts +2 -2
  53. package/dist/esm/mcp/tools/message-search.js +14 -11
  54. package/dist/esm/mcp/tools/message-search.js.map +1 -1
  55. package/dist/esm/mcp/tools/messages-export-csv.d.ts +2 -2
  56. package/dist/esm/mcp/tools/messages-export-csv.js +9 -8
  57. package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -1
  58. package/dist/esm/schemas/outlook-query-schema.d.ts +2 -1
  59. package/dist/esm/schemas/outlook-query-schema.js +37 -18
  60. package/dist/esm/schemas/outlook-query-schema.js.map +1 -1
  61. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ import type { Message } from '@microsoft/microsoft-graph-types';
2
+ import type { OutlookQuery } from '../../schemas/outlook-query-schema.js';
3
+ type Predicate = (message: Message) => boolean;
4
+ export declare function buildClientPredicate(query: OutlookQuery): Predicate;
5
+ export declare function needsBody(query: OutlookQuery): boolean;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Message } from '@microsoft/microsoft-graph-types';
2
+ import type { OutlookQuery } from '../../schemas/outlook-query-schema.js';
3
+ type Predicate = (message: Message) => boolean;
4
+ export declare function buildClientPredicate(query: OutlookQuery): Predicate;
5
+ export declare function needsBody(query: OutlookQuery): boolean;
6
+ export {};
@@ -0,0 +1,309 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get buildClientPredicate () {
13
+ return buildClientPredicate;
14
+ },
15
+ get needsBody () {
16
+ return needsBody;
17
+ }
18
+ });
19
+ var _querybuilderts = require("./query-builder.js");
20
+ function _type_of(obj) {
21
+ "@swc/helpers - typeof";
22
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
23
+ }
24
+ function buildClientPredicate(query) {
25
+ var nodePredicate = buildNodePredicate(query);
26
+ return function(message) {
27
+ return nodePredicate(message);
28
+ };
29
+ }
30
+ function needsBody(query) {
31
+ return hasBodyTextOrExact(query);
32
+ }
33
+ function buildNodePredicate(node) {
34
+ if (!node || (typeof node === "undefined" ? "undefined" : _type_of(node)) !== 'object') return function() {
35
+ return true;
36
+ };
37
+ if (node.$and) {
38
+ var children = node.$and.map(buildNodePredicate);
39
+ return function(message) {
40
+ return children.every(function(child) {
41
+ return child(message);
42
+ });
43
+ };
44
+ }
45
+ if (node.$or) {
46
+ var children1 = node.$or.map(buildNodePredicate);
47
+ return function(message) {
48
+ return children1.some(function(child) {
49
+ return child(message);
50
+ });
51
+ };
52
+ }
53
+ if (node.$not) {
54
+ var child = buildNodePredicate(node.$not);
55
+ return function(message) {
56
+ return !child(message);
57
+ };
58
+ }
59
+ var predicates = [];
60
+ if ('hasAttachment' in node && typeof node.hasAttachment === 'boolean') {
61
+ predicates.push(function(message) {
62
+ return message.hasAttachments === node.hasAttachment;
63
+ });
64
+ }
65
+ if ('isRead' in node && typeof node.isRead === 'boolean') {
66
+ predicates.push(function(message) {
67
+ return message.isRead === node.isRead;
68
+ });
69
+ }
70
+ if ('importance' in node && node.importance) {
71
+ var expected = node.importance.toLowerCase();
72
+ predicates.push(function(message) {
73
+ return typeof message.importance === 'string' && message.importance.toLowerCase() === expected;
74
+ });
75
+ }
76
+ if ('date' in node && node.date) {
77
+ var _node_date = node.date, $gte = _node_date.$gte, $lt = _node_date.$lt;
78
+ predicates.push(function(message) {
79
+ return matchesDate(message.receivedDateTime, $gte, $lt);
80
+ });
81
+ }
82
+ if ('from' in node && node.from) {
83
+ predicates.push(function(message) {
84
+ return matchesAddressField(normalizeAddress(message.from), node.from);
85
+ });
86
+ }
87
+ if ('to' in node && node.to) {
88
+ predicates.push(function(message) {
89
+ return matchesRecipientField(message.toRecipients, node.to);
90
+ });
91
+ }
92
+ if ('cc' in node && node.cc) {
93
+ predicates.push(function(message) {
94
+ return matchesRecipientField(message.ccRecipients, node.cc);
95
+ });
96
+ }
97
+ if ('bcc' in node && node.bcc) {
98
+ predicates.push(function(message) {
99
+ return matchesRecipientField(message.bccRecipients, node.bcc);
100
+ });
101
+ }
102
+ if ('subject' in node && node.subject) {
103
+ predicates.push(function(message) {
104
+ return matchesSubject(message, node.subject);
105
+ });
106
+ }
107
+ if ('text' in node && node.text) {
108
+ predicates.push(function(message) {
109
+ return matchesText(message, node.text);
110
+ });
111
+ }
112
+ if ('body' in node && node.body) {
113
+ predicates.push(function(message) {
114
+ return matchesBody(message, node.body);
115
+ });
116
+ }
117
+ if ('exactPhrase' in node && node.exactPhrase) {
118
+ predicates.push(function(message) {
119
+ return matchesExactPhrase(message, node.exactPhrase);
120
+ });
121
+ }
122
+ if ('categories' in node && node.categories) {
123
+ predicates.push(function(message) {
124
+ var _message_categories;
125
+ return matchesCategoryField((_message_categories = message.categories) !== null && _message_categories !== void 0 ? _message_categories : [], node.categories);
126
+ });
127
+ }
128
+ if ('label' in node && node.label) {
129
+ predicates.push(function(message) {
130
+ var _message_categories;
131
+ return matchesLabelField((_message_categories = message.categories) !== null && _message_categories !== void 0 ? _message_categories : [], node.label);
132
+ });
133
+ }
134
+ if (predicates.length === 0) return function() {
135
+ return true;
136
+ };
137
+ return function(message) {
138
+ return predicates.every(function(predicate) {
139
+ return predicate(message);
140
+ });
141
+ };
142
+ }
143
+ function hasBodyTextOrExact(node) {
144
+ if (!node || (typeof node === "undefined" ? "undefined" : _type_of(node)) !== 'object') return false;
145
+ if ('body' in node && node.body) return true;
146
+ if ('text' in node && node.text) return true;
147
+ if ('exactPhrase' in node && node.exactPhrase) return true;
148
+ if ('$and' in node && node.$and) {
149
+ return node.$and.some(function(child) {
150
+ return hasBodyTextOrExact(child);
151
+ });
152
+ }
153
+ if ('$or' in node && node.$or) {
154
+ return node.$or.some(function(child) {
155
+ return hasBodyTextOrExact(child);
156
+ });
157
+ }
158
+ if ('$not' in node && node.$not) {
159
+ return hasBodyTextOrExact(node.$not);
160
+ }
161
+ return false;
162
+ }
163
+ function matchesSubject(message, value) {
164
+ var normalizedSubject = normalizeForMatch(message.subject);
165
+ return evaluateOperator(value, function(term) {
166
+ return normalizedSubject.includes(term);
167
+ });
168
+ }
169
+ function matchesText(message, value) {
170
+ var textSources = getTextSources(message);
171
+ return evaluateOperator(value, function(term) {
172
+ return textSources.some(function(source) {
173
+ return source.includes(term);
174
+ });
175
+ });
176
+ }
177
+ function matchesBody(message, value) {
178
+ var _message_body;
179
+ var bodyContent = normalizeForMatch((_message_body = message.body) === null || _message_body === void 0 ? void 0 : _message_body.content);
180
+ return evaluateOperator(value, function(term) {
181
+ return bodyContent.includes(term);
182
+ });
183
+ }
184
+ function matchesExactPhrase(message, phrase) {
185
+ var normalizedPhrase = normalizeTerm(phrase);
186
+ if (!normalizedPhrase) return false;
187
+ var textSources = getTextSources(message);
188
+ return textSources.some(function(source) {
189
+ return source.includes(normalizedPhrase);
190
+ });
191
+ }
192
+ function matchesAddressField(addressData, value) {
193
+ var matchTerm = function(term) {
194
+ var addressMatch = addressData.address.includes(term);
195
+ var nameMatch = addressData.name.includes(term);
196
+ if (term.includes('@')) {
197
+ return addressMatch || nameMatch;
198
+ }
199
+ return addressMatch || nameMatch;
200
+ };
201
+ return evaluateOperator(value, matchTerm);
202
+ }
203
+ function normalizeAddress(recipient) {
204
+ var _recipient_emailAddress, _recipient_emailAddress1;
205
+ return {
206
+ address: normalizeForMatch(recipient === null || recipient === void 0 ? void 0 : (_recipient_emailAddress = recipient.emailAddress) === null || _recipient_emailAddress === void 0 ? void 0 : _recipient_emailAddress.address),
207
+ name: normalizeForMatch(recipient === null || recipient === void 0 ? void 0 : (_recipient_emailAddress1 = recipient.emailAddress) === null || _recipient_emailAddress1 === void 0 ? void 0 : _recipient_emailAddress1.name)
208
+ };
209
+ }
210
+ function matchesRecipientField(recipients, value) {
211
+ var normalizedRecipients = (recipients !== null && recipients !== void 0 ? recipients : []).map(function(recipient) {
212
+ var _recipient_emailAddress, _recipient_emailAddress1;
213
+ return {
214
+ address: normalizeForMatch(recipient === null || recipient === void 0 ? void 0 : (_recipient_emailAddress = recipient.emailAddress) === null || _recipient_emailAddress === void 0 ? void 0 : _recipient_emailAddress.address),
215
+ name: normalizeForMatch(recipient === null || recipient === void 0 ? void 0 : (_recipient_emailAddress1 = recipient.emailAddress) === null || _recipient_emailAddress1 === void 0 ? void 0 : _recipient_emailAddress1.name)
216
+ };
217
+ });
218
+ var matchTerm = function(term) {
219
+ return normalizedRecipients.some(function(recipient) {
220
+ return recipient.address.includes(term) || recipient.name.includes(term);
221
+ });
222
+ };
223
+ return evaluateOperator(value, matchTerm);
224
+ }
225
+ function matchesCategoryField(categories, value) {
226
+ var mappedCategories = categories.map(function(category) {
227
+ return category !== null && category !== void 0 ? category : '';
228
+ });
229
+ var matchTerm = function(term) {
230
+ try {
231
+ var mappedTerm = (0, _querybuilderts.mapOutlookCategory)(term);
232
+ return mappedCategories.includes(mappedTerm);
233
+ } catch (unused) {
234
+ return false;
235
+ }
236
+ };
237
+ return evaluateOperator(value, matchTerm);
238
+ }
239
+ function matchesLabelField(categories, value) {
240
+ var normalizeLabelTerm = function(input) {
241
+ var trimmed = input.trim();
242
+ return trimmed === '' ? null : trimmed;
243
+ };
244
+ var matchTerm = function(term) {
245
+ return categories.includes(term);
246
+ };
247
+ return evaluateOperator(value, matchTerm, normalizeLabelTerm);
248
+ }
249
+ function matchesDate(received, gte, lt) {
250
+ if (!received) return false;
251
+ var receivedTs = Date.parse(received);
252
+ if (Number.isNaN(receivedTs)) return false;
253
+ if (gte) {
254
+ var start = Date.parse("".concat(gte, "T00:00:00Z"));
255
+ if (Number.isNaN(start) || receivedTs < start) return false;
256
+ }
257
+ if (lt) {
258
+ var end = Date.parse("".concat(lt, "T00:00:00Z"));
259
+ if (Number.isNaN(end) || receivedTs >= end) return false;
260
+ }
261
+ return true;
262
+ }
263
+ function evaluateOperator(value, matcher) {
264
+ var normalizeFn = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : normalizeTerm;
265
+ if (typeof value === 'string') {
266
+ var normalized = normalizeFn(value);
267
+ return normalized !== null && matcher(normalized);
268
+ }
269
+ var hasConstraint = false;
270
+ if (Array.isArray(value.$any) && value.$any.length > 0) {
271
+ hasConstraint = true;
272
+ var terms = value.$any.map(normalizeFn).filter(function(term) {
273
+ return Boolean(term);
274
+ });
275
+ if (terms.length === 0 || !terms.some(matcher)) return false;
276
+ }
277
+ if (Array.isArray(value.$all) && value.$all.length > 0) {
278
+ hasConstraint = true;
279
+ var terms1 = value.$all.map(normalizeFn).filter(function(term) {
280
+ return Boolean(term);
281
+ });
282
+ if (terms1.length === 0 || !terms1.every(matcher)) return false;
283
+ }
284
+ if (Array.isArray(value.$none) && value.$none.length > 0) {
285
+ hasConstraint = true;
286
+ var terms2 = value.$none.map(normalizeFn).filter(function(term) {
287
+ return Boolean(term);
288
+ });
289
+ if (terms2.some(matcher)) return false;
290
+ }
291
+ return !!hasConstraint;
292
+ }
293
+ function normalizeTerm(input) {
294
+ var collapsed = input.replace(/\s+/g, ' ').trim().toLowerCase();
295
+ return collapsed === '' ? null : collapsed;
296
+ }
297
+ function normalizeForMatch(value) {
298
+ var _normalizeTerm;
299
+ return (_normalizeTerm = normalizeTerm(value !== null && value !== void 0 ? value : '')) !== null && _normalizeTerm !== void 0 ? _normalizeTerm : '';
300
+ }
301
+ function getTextSources(message) {
302
+ var _message_body;
303
+ return [
304
+ normalizeForMatch(message.subject),
305
+ normalizeForMatch((_message_body = message.body) === null || _message_body === void 0 ? void 0 : _message_body.content),
306
+ normalizeForMatch(message.bodyPreview)
307
+ ];
308
+ }
309
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/email/querying/client-filter.ts"],"sourcesContent":["import type { FieldOperator } from '@mcp-z/email';\nimport type { Message, Recipient } from '@microsoft/microsoft-graph-types';\nimport type { OutlookQuery } from '../../schemas/outlook-query-schema.ts';\nimport { mapOutlookCategory } from './query-builder.ts';\n\ntype Predicate = (message: Message) => boolean;\n\nexport function buildClientPredicate(query: OutlookQuery): Predicate {\n const nodePredicate = buildNodePredicate(query);\n return (message) => nodePredicate(message);\n}\n\nexport function needsBody(query: OutlookQuery): boolean {\n return hasBodyTextOrExact(query);\n}\n\nfunction buildNodePredicate(node: OutlookQuery | undefined | null): Predicate {\n if (!node || typeof node !== 'object') return () => true;\n\n if (node.$and) {\n const children = node.$and.map(buildNodePredicate);\n return (message) => children.every((child) => child(message));\n }\n if (node.$or) {\n const children = node.$or.map(buildNodePredicate);\n return (message) => children.some((child) => child(message));\n }\n if (node.$not) {\n const child = buildNodePredicate(node.$not);\n return (message) => !child(message);\n }\n\n const predicates: Predicate[] = [];\n\n if ('hasAttachment' in node && typeof node.hasAttachment === 'boolean') {\n predicates.push((message) => message.hasAttachments === node.hasAttachment);\n }\n if ('isRead' in node && typeof node.isRead === 'boolean') {\n predicates.push((message) => message.isRead === node.isRead);\n }\n if ('importance' in node && node.importance) {\n const expected = node.importance.toLowerCase();\n predicates.push((message) => typeof message.importance === 'string' && message.importance.toLowerCase() === expected);\n }\n if ('date' in node && node.date) {\n const { $gte, $lt } = node.date;\n predicates.push((message) => matchesDate(message.receivedDateTime, $gte, $lt));\n }\n\n if ('from' in node && node.from) {\n predicates.push((message) => matchesAddressField(normalizeAddress(message.from), node.from));\n }\n if ('to' in node && node.to) {\n predicates.push((message) => matchesRecipientField(message.toRecipients, node.to));\n }\n if ('cc' in node && node.cc) {\n predicates.push((message) => matchesRecipientField(message.ccRecipients, node.cc));\n }\n if ('bcc' in node && node.bcc) {\n predicates.push((message) => matchesRecipientField(message.bccRecipients, node.bcc));\n }\n if ('subject' in node && node.subject) {\n predicates.push((message) => matchesSubject(message, node.subject));\n }\n if ('text' in node && node.text) {\n predicates.push((message) => matchesText(message, node.text));\n }\n if ('body' in node && node.body) {\n predicates.push((message) => matchesBody(message, node.body));\n }\n if ('exactPhrase' in node && node.exactPhrase) {\n predicates.push((message) => matchesExactPhrase(message, node.exactPhrase));\n }\n if ('categories' in node && node.categories) {\n predicates.push((message) => matchesCategoryField(message.categories ?? [], node.categories));\n }\n if ('label' in node && node.label) {\n predicates.push((message) => matchesLabelField(message.categories ?? [], node.label));\n }\n\n if (predicates.length === 0) return () => true;\n return (message) => predicates.every((predicate) => predicate(message));\n}\n\nfunction hasBodyTextOrExact(node: OutlookQuery | undefined | null): boolean {\n if (!node || typeof node !== 'object') return false;\n if ('body' in node && node.body) return true;\n if ('text' in node && node.text) return true;\n if ('exactPhrase' in node && node.exactPhrase) return true;\n if ('$and' in node && node.$and) {\n return node.$and.some((child) => hasBodyTextOrExact(child));\n }\n if ('$or' in node && node.$or) {\n return node.$or.some((child) => hasBodyTextOrExact(child));\n }\n if ('$not' in node && node.$not) {\n return hasBodyTextOrExact(node.$not);\n }\n return false;\n}\n\nfunction matchesSubject(message: Message, value: string | FieldOperator): boolean {\n const normalizedSubject = normalizeForMatch(message.subject);\n return evaluateOperator(value, (term) => normalizedSubject.includes(term));\n}\n\nfunction matchesText(message: Message, value: string | FieldOperator): boolean {\n const textSources = getTextSources(message);\n return evaluateOperator(value, (term) => textSources.some((source) => source.includes(term)));\n}\n\nfunction matchesBody(message: Message, value: string | FieldOperator): boolean {\n const bodyContent = normalizeForMatch(message.body?.content);\n return evaluateOperator(value, (term) => bodyContent.includes(term));\n}\n\nfunction matchesExactPhrase(message: Message, phrase: string): boolean {\n const normalizedPhrase = normalizeTerm(phrase);\n if (!normalizedPhrase) return false;\n const textSources = getTextSources(message);\n return textSources.some((source) => source.includes(normalizedPhrase));\n}\n\nfunction matchesAddressField(addressData: NormalizedAddress, value: string | FieldOperator): boolean {\n const matchTerm = (term: string) => {\n const addressMatch = addressData.address.includes(term);\n const nameMatch = addressData.name.includes(term);\n if (term.includes('@')) {\n return addressMatch || nameMatch;\n }\n return addressMatch || nameMatch;\n };\n return evaluateOperator(value, matchTerm);\n}\n\ntype NormalizedAddress = { address: string; name: string };\n\nfunction normalizeAddress(recipient: Recipient | undefined): NormalizedAddress {\n return {\n address: normalizeForMatch(recipient?.emailAddress?.address),\n name: normalizeForMatch(recipient?.emailAddress?.name),\n };\n}\n\nfunction matchesRecipientField(recipients: Recipient[] | undefined, value: string | FieldOperator): boolean {\n const normalizedRecipients = (recipients ?? []).map((recipient) => ({\n address: normalizeForMatch(recipient?.emailAddress?.address),\n name: normalizeForMatch(recipient?.emailAddress?.name),\n }));\n const matchTerm = (term: string) => normalizedRecipients.some((recipient) => recipient.address.includes(term) || recipient.name.includes(term));\n return evaluateOperator(value, matchTerm);\n}\n\nfunction matchesCategoryField(categories: string[], value: string | FieldOperator): boolean {\n const mappedCategories = categories.map((category) => category ?? '');\n const matchTerm = (term: string) => {\n try {\n const mappedTerm = mapOutlookCategory(term);\n return mappedCategories.includes(mappedTerm);\n } catch {\n return false;\n }\n };\n return evaluateOperator(value, matchTerm);\n}\n\nfunction matchesLabelField(categories: string[], value: string | FieldOperator): boolean {\n const normalizeLabelTerm = (input: string): string | null => {\n const trimmed = input.trim();\n return trimmed === '' ? null : trimmed;\n };\n const matchTerm = (term: string) => categories.includes(term);\n return evaluateOperator(value, matchTerm, normalizeLabelTerm);\n}\n\nfunction matchesDate(received: string | undefined, gte?: string, lt?: string): boolean {\n if (!received) return false;\n const receivedTs = Date.parse(received);\n if (Number.isNaN(receivedTs)) return false;\n if (gte) {\n const start = Date.parse(`${gte}T00:00:00Z`);\n if (Number.isNaN(start) || receivedTs < start) return false;\n }\n if (lt) {\n const end = Date.parse(`${lt}T00:00:00Z`);\n if (Number.isNaN(end) || receivedTs >= end) return false;\n }\n return true;\n}\n\nfunction evaluateOperator(value: string | FieldOperator, matcher: (normalizedTerm: string) => boolean, normalizeFn: (input: string) => string = normalizeTerm): boolean {\n if (typeof value === 'string') {\n const normalized = normalizeFn(value);\n return normalized !== null && matcher(normalized);\n }\n let hasConstraint = false;\n if (Array.isArray(value.$any) && value.$any.length > 0) {\n hasConstraint = true;\n const terms = value.$any.map(normalizeFn).filter((term): term is string => Boolean(term));\n if (terms.length === 0 || !terms.some(matcher)) return false;\n }\n if (Array.isArray(value.$all) && value.$all.length > 0) {\n hasConstraint = true;\n const terms = value.$all.map(normalizeFn).filter((term): term is string => Boolean(term));\n if (terms.length === 0 || !terms.every(matcher)) return false;\n }\n if (Array.isArray(value.$none) && value.$none.length > 0) {\n hasConstraint = true;\n const terms = value.$none.map(normalizeFn).filter((term): term is string => Boolean(term));\n if (terms.some(matcher)) return false;\n }\n return !!hasConstraint;\n}\n\nfunction normalizeTerm(input: string): string | null {\n const collapsed = input.replace(/\\s+/g, ' ').trim().toLowerCase();\n return collapsed === '' ? null : collapsed;\n}\n\nfunction normalizeForMatch(value?: string): string {\n return normalizeTerm(value ?? '') ?? '';\n}\n\nfunction getTextSources(message: Message): string[] {\n return [normalizeForMatch(message.subject), normalizeForMatch(message.body?.content), normalizeForMatch(message.bodyPreview)];\n}\n"],"names":["buildClientPredicate","needsBody","query","nodePredicate","buildNodePredicate","message","hasBodyTextOrExact","node","$and","children","map","every","child","$or","some","$not","predicates","hasAttachment","push","hasAttachments","isRead","importance","expected","toLowerCase","date","$gte","$lt","matchesDate","receivedDateTime","from","matchesAddressField","normalizeAddress","to","matchesRecipientField","toRecipients","cc","ccRecipients","bcc","bccRecipients","subject","matchesSubject","text","matchesText","body","matchesBody","exactPhrase","matchesExactPhrase","categories","matchesCategoryField","label","matchesLabelField","length","predicate","value","normalizedSubject","normalizeForMatch","evaluateOperator","term","includes","textSources","getTextSources","source","bodyContent","content","phrase","normalizedPhrase","normalizeTerm","addressData","matchTerm","addressMatch","address","nameMatch","name","recipient","emailAddress","recipients","normalizedRecipients","mappedCategories","category","mappedTerm","mapOutlookCategory","normalizeLabelTerm","input","trimmed","trim","received","gte","lt","receivedTs","Date","parse","Number","isNaN","start","end","matcher","normalizeFn","normalized","hasConstraint","Array","isArray","$any","terms","filter","Boolean","$all","$none","collapsed","replace","bodyPreview"],"mappings":"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"}
@@ -7,6 +7,7 @@ export interface ExecuteQueryOptions {
7
7
  readonly limit?: number;
8
8
  readonly includeBody?: boolean;
9
9
  readonly maxPages?: number | null;
10
+ readonly maxItemsScanned?: number | null;
10
11
  readonly pageSize?: number;
11
12
  readonly pageToken?: string;
12
13
  readonly timezone?: string;
@@ -7,6 +7,7 @@ export interface ExecuteQueryOptions {
7
7
  readonly limit?: number;
8
8
  readonly includeBody?: boolean;
9
9
  readonly maxPages?: number | null;
10
+ readonly maxItemsScanned?: number | null;
10
11
  readonly pageSize?: number;
11
12
  readonly pageToken?: string;
12
13
  readonly timezone?: string;
@@ -198,11 +198,11 @@ function _ts_generator(thisArg, body) {
198
198
  }
199
199
  function executeQuery(graph, query, options, transform) {
200
200
  return _async_to_generator(function() {
201
- var logger, limit, includeBody, maxPages, pageSize, pageToken, result, transformedResults, error;
201
+ var logger, limit, includeBody, maxPages, maxItemsScanned, pageSize, pageToken, result, transformedResults, error;
202
202
  return _ts_generator(this, function(_state) {
203
203
  switch(_state.label){
204
204
  case 0:
205
- logger = options.logger, limit = options.limit, includeBody = options.includeBody, maxPages = options.maxPages, pageSize = options.pageSize, pageToken = options.pageToken;
205
+ logger = options.logger, limit = options.limit, includeBody = options.includeBody, maxPages = options.maxPages, maxItemsScanned = options.maxItemsScanned, pageSize = options.pageSize, pageToken = options.pageToken;
206
206
  // Single execution - direct query to Microsoft Graph API
207
207
  logger.info('executeQuery: executing direct Outlook query');
208
208
  _state.label = 1;
@@ -221,6 +221,7 @@ function executeQuery(graph, query, options, transform) {
221
221
  limit: limit !== null && limit !== void 0 ? limit : 50,
222
222
  includeBody: includeBody !== null && includeBody !== void 0 ? includeBody : false,
223
223
  maxPages: maxPages !== null && maxPages !== void 0 ? maxPages : null,
224
+ maxItemsScanned: maxItemsScanned !== null && maxItemsScanned !== void 0 ? maxItemsScanned : null,
224
225
  pageSize: pageSize !== null && pageSize !== void 0 ? pageSize : 50,
225
226
  pageToken: pageToken !== null && pageToken !== void 0 ? pageToken : undefined,
226
227
  logger: logger
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/email/querying/execute-query.ts"],"sourcesContent":["import type { ExecutionResult } from '@mcp-z/email';\nimport type { Client } from '@microsoft/microsoft-graph-client';\nimport type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.ts';\nimport type { Logger } from '../../types.ts';\nimport { searchMessages } from './search-execution.ts';\n\nexport interface ExecuteQueryOptions {\n readonly logger: Logger;\n readonly limit?: number;\n readonly includeBody?: boolean;\n readonly maxPages?: number | null;\n readonly pageSize?: number;\n readonly pageToken?: string;\n readonly timezone?: string;\n readonly abortSignal?: AbortSignal;\n}\n\n/**\n * Execute an Outlook query with direct, single-attempt execution.\n * No planning, no fallbacks, no retries.\n * Microsoft Graph errors are returned directly to the caller for actionable feedback.\n */\nexport async function executeQuery<T>(graph: Client, query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>> {\n const { logger, limit, includeBody, maxPages, pageSize, pageToken } = options;\n\n // Single execution - direct query to Microsoft Graph API\n logger.info('executeQuery: executing direct Outlook query');\n\n try {\n const result = await searchMessages(graph, {\n ...(query !== undefined && { query }),\n limit: limit ?? 50,\n includeBody: includeBody ?? false,\n maxPages: maxPages ?? null,\n pageSize: pageSize ?? 50,\n pageToken: pageToken ?? undefined,\n logger,\n });\n\n // Transform directly - if Microsoft Graph returns invalid data, fail loud\n const transformedResults = result.messages.map((item, index) => {\n try {\n return transform(item);\n } catch (transformError) {\n logger.error(`Transform function failed for item ${index}`, {\n itemIndex: index,\n error: transformError instanceof Error ? transformError.message : String(transformError),\n });\n throw new Error(`Transform failed at item ${index}: ${transformError}`);\n }\n });\n\n logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);\n\n return {\n success: true,\n items: transformedResults,\n metadata: {\n nextPageToken: result.nextPageToken,\n totalFetched: result.messages.length,\n },\n };\n } catch (error) {\n // Re-throw errors directly - no fallback logic\n logger.error('executeQuery: failed', error as Record<string, unknown>);\n throw error;\n }\n}\n"],"names":["executeQuery","graph","query","options","transform","logger","limit","includeBody","maxPages","pageSize","pageToken","result","transformedResults","error","info","searchMessages","undefined","messages","map","item","index","transformError","itemIndex","Error","message","String","length","success","items","metadata","nextPageToken","totalFetched"],"mappings":";;;;+BAsBsBA;;;eAAAA;;;iCAlBS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBxB,SAAeA,aAAgBC,KAAa,EAAEC,KAA4B,EAAEC,OAA4B,EAAEC,SAA+B;;YACtIC,QAAQC,OAAOC,aAAaC,UAAUC,UAAUC,WAMhDC,QAWAC,oBAsBCC;;;;oBAvCDR,SAA8DF,QAA9DE,QAAQC,QAAsDH,QAAtDG,OAAOC,cAA+CJ,QAA/CI,aAAaC,WAAkCL,QAAlCK,UAAUC,WAAwBN,QAAxBM,UAAUC,YAAcP,QAAdO;oBAExD,yDAAyD;oBACzDL,OAAOS,IAAI,CAAC;;;;;;;;;oBAGK;;wBAAMC,IAAAA,iCAAc,EAACd,OAAO,wCACrCC,UAAUc,aAAa;4BAAEd,OAAAA;wBAAM;4BACnCI,KAAK,EAAEA,kBAAAA,mBAAAA,QAAS;4BAChBC,WAAW,EAAEA,wBAAAA,yBAAAA,cAAe;4BAC5BC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;4BACtBC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;4BACtBC,SAAS,EAAEA,sBAAAA,uBAAAA,YAAaM;4BACxBX,QAAAA;;;;oBAPIM,SAAS;oBAUf,0EAA0E;oBACpEC,qBAAqBD,OAAOM,QAAQ,CAACC,GAAG,CAAC,SAACC,MAAMC;wBACpD,IAAI;4BACF,OAAOhB,UAAUe;wBACnB,EAAE,OAAOE,gBAAgB;4BACvBhB,OAAOQ,KAAK,CAAC,AAAC,sCAA2C,OAANO,QAAS;gCAC1DE,WAAWF;gCACXP,OAAOQ,AAAc,YAAdA,gBAA0BE,SAAQF,eAAeG,OAAO,GAAGC,OAAOJ;4BAC3E;4BACA,MAAM,IAAIE,MAAM,AAAC,4BAAqCF,OAAVD,OAAM,MAAmB,OAAfC;wBACxD;oBACF;oBAEAhB,OAAOS,IAAI,CAAC,AAAC,gCAAyD,OAA1BF,mBAAmBc,MAAM,EAAC;oBAEtE;;wBAAO;4BACLC,SAAS;4BACTC,OAAOhB;4BACPiB,UAAU;gCACRC,eAAenB,OAAOmB,aAAa;gCACnCC,cAAcpB,OAAOM,QAAQ,CAACS,MAAM;4BACtC;wBACF;;;oBACOb;oBACP,+CAA+C;oBAC/CR,OAAOQ,KAAK,CAAC,wBAAwBA;oBACrC,MAAMA;;;;;;;IAEV"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/email/querying/execute-query.ts"],"sourcesContent":["import type { ExecutionResult } from '@mcp-z/email';\nimport type { Client } from '@microsoft/microsoft-graph-client';\nimport type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.ts';\nimport type { Logger } from '../../types.ts';\nimport { searchMessages } from './search-execution.ts';\n\nexport interface ExecuteQueryOptions {\n readonly logger: Logger;\n readonly limit?: number;\n readonly includeBody?: boolean;\n readonly maxPages?: number | null;\n readonly maxItemsScanned?: number | null;\n readonly pageSize?: number;\n readonly pageToken?: string;\n readonly timezone?: string;\n readonly abortSignal?: AbortSignal;\n}\n\n/**\n * Execute an Outlook query with direct, single-attempt execution.\n * No planning, no fallbacks, no retries.\n * Microsoft Graph errors are returned directly to the caller for actionable feedback.\n */\nexport async function executeQuery<T>(graph: Client, query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>> {\n const { logger, limit, includeBody, maxPages, maxItemsScanned, pageSize, pageToken } = options;\n\n // Single execution - direct query to Microsoft Graph API\n logger.info('executeQuery: executing direct Outlook query');\n\n try {\n const result = await searchMessages(graph, {\n ...(query !== undefined && { query }),\n limit: limit ?? 50,\n includeBody: includeBody ?? false,\n maxPages: maxPages ?? null,\n maxItemsScanned: maxItemsScanned ?? null,\n pageSize: pageSize ?? 50,\n pageToken: pageToken ?? undefined,\n logger,\n });\n\n // Transform directly - if Microsoft Graph returns invalid data, fail loud\n const transformedResults = result.messages.map((item, index) => {\n try {\n return transform(item);\n } catch (transformError) {\n logger.error(`Transform function failed for item ${index}`, {\n itemIndex: index,\n error: transformError instanceof Error ? transformError.message : String(transformError),\n });\n throw new Error(`Transform failed at item ${index}: ${transformError}`);\n }\n });\n\n logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);\n\n return {\n success: true,\n items: transformedResults,\n metadata: {\n nextPageToken: result.nextPageToken,\n totalFetched: result.messages.length,\n },\n };\n } catch (error) {\n // Re-throw errors directly - no fallback logic\n logger.error('executeQuery: failed', error as Record<string, unknown>);\n throw error;\n }\n}\n"],"names":["executeQuery","graph","query","options","transform","logger","limit","includeBody","maxPages","maxItemsScanned","pageSize","pageToken","result","transformedResults","error","info","searchMessages","undefined","messages","map","item","index","transformError","itemIndex","Error","message","String","length","success","items","metadata","nextPageToken","totalFetched"],"mappings":";;;;+BAuBsBA;;;eAAAA;;;iCAnBS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBxB,SAAeA,aAAgBC,KAAa,EAAEC,KAA4B,EAAEC,OAA4B,EAAEC,SAA+B;;YACtIC,QAAQC,OAAOC,aAAaC,UAAUC,iBAAiBC,UAAUC,WAMjEC,QAYAC,oBAsBCC;;;;oBAxCDT,SAA+EF,QAA/EE,QAAQC,QAAuEH,QAAvEG,OAAOC,cAAgEJ,QAAhEI,aAAaC,WAAmDL,QAAnDK,UAAUC,kBAAyCN,QAAzCM,iBAAiBC,WAAwBP,QAAxBO,UAAUC,YAAcR,QAAdQ;oBAEzE,yDAAyD;oBACzDN,OAAOU,IAAI,CAAC;;;;;;;;;oBAGK;;wBAAMC,IAAAA,iCAAc,EAACf,OAAO,wCACrCC,UAAUe,aAAa;4BAAEf,OAAAA;wBAAM;4BACnCI,KAAK,EAAEA,kBAAAA,mBAAAA,QAAS;4BAChBC,WAAW,EAAEA,wBAAAA,yBAAAA,cAAe;4BAC5BC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;4BACtBC,eAAe,EAAEA,4BAAAA,6BAAAA,kBAAmB;4BACpCC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;4BACtBC,SAAS,EAAEA,sBAAAA,uBAAAA,YAAaM;4BACxBZ,QAAAA;;;;oBARIO,SAAS;oBAWf,0EAA0E;oBACpEC,qBAAqBD,OAAOM,QAAQ,CAACC,GAAG,CAAC,SAACC,MAAMC;wBACpD,IAAI;4BACF,OAAOjB,UAAUgB;wBACnB,EAAE,OAAOE,gBAAgB;4BACvBjB,OAAOS,KAAK,CAAC,AAAC,sCAA2C,OAANO,QAAS;gCAC1DE,WAAWF;gCACXP,OAAOQ,AAAc,YAAdA,gBAA0BE,SAAQF,eAAeG,OAAO,GAAGC,OAAOJ;4BAC3E;4BACA,MAAM,IAAIE,MAAM,AAAC,4BAAqCF,OAAVD,OAAM,MAAmB,OAAfC;wBACxD;oBACF;oBAEAjB,OAAOU,IAAI,CAAC,AAAC,gCAAyD,OAA1BF,mBAAmBc,MAAM,EAAC;oBAEtE;;wBAAO;4BACLC,SAAS;4BACTC,OAAOhB;4BACPiB,UAAU;gCACRC,eAAenB,OAAOmB,aAAa;gCACnCC,cAAcpB,OAAOM,QAAQ,CAACS,MAAM;4BACtC;wBACF;;;oBACOb;oBACP,+CAA+C;oBAC/CT,OAAOS,KAAK,CAAC,wBAAwBA;oBACrC,MAAMA;;;;;;;IAEV"}
@@ -0,0 +1,13 @@
1
+ export declare const FIRST_PAGE_SKIP_TOKEN = "__mcp_outlook_first_page__";
2
+ export interface DecodeNextPageTokenResult {
3
+ skipToken?: string;
4
+ offset: number;
5
+ mode?: string;
6
+ legacy: boolean;
7
+ }
8
+ export declare function encodeNextPageToken(params: {
9
+ skipToken?: string;
10
+ offset: number;
11
+ mode?: string;
12
+ }): string;
13
+ export declare function decodeNextPageToken(token: string | undefined): DecodeNextPageTokenResult;
@@ -0,0 +1,13 @@
1
+ export declare const FIRST_PAGE_SKIP_TOKEN = "__mcp_outlook_first_page__";
2
+ export interface DecodeNextPageTokenResult {
3
+ skipToken?: string;
4
+ offset: number;
5
+ mode?: string;
6
+ legacy: boolean;
7
+ }
8
+ export declare function encodeNextPageToken(params: {
9
+ skipToken?: string;
10
+ offset: number;
11
+ mode?: string;
12
+ }): string;
13
+ export declare function decodeNextPageToken(token: string | undefined): DecodeNextPageTokenResult;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get FIRST_PAGE_SKIP_TOKEN () {
13
+ return FIRST_PAGE_SKIP_TOKEN;
14
+ },
15
+ get decodeNextPageToken () {
16
+ return decodeNextPageToken;
17
+ },
18
+ get encodeNextPageToken () {
19
+ return encodeNextPageToken;
20
+ }
21
+ });
22
+ var PREFIX = 'v2:';
23
+ var FIRST_PAGE_SKIP_TOKEN = '__mcp_outlook_first_page__';
24
+ function encodeNextPageToken(params) {
25
+ var _params_skipToken;
26
+ var sanitizedOffset = Math.max(0, Math.trunc(params.offset));
27
+ var payload = {
28
+ v: 2,
29
+ skipToken: (_params_skipToken = params.skipToken) !== null && _params_skipToken !== void 0 ? _params_skipToken : FIRST_PAGE_SKIP_TOKEN,
30
+ offset: sanitizedOffset
31
+ };
32
+ if (typeof params.mode === 'string' && params.mode.length > 0) {
33
+ payload.mode = params.mode;
34
+ }
35
+ var serialized = JSON.stringify(payload);
36
+ return "".concat(PREFIX).concat(base64UrlEncode(serialized));
37
+ }
38
+ function decodeNextPageToken(token) {
39
+ if (!token) {
40
+ return {
41
+ offset: 0,
42
+ legacy: true
43
+ };
44
+ }
45
+ if (!token.startsWith(PREFIX)) {
46
+ return {
47
+ skipToken: token,
48
+ offset: 0,
49
+ legacy: true
50
+ };
51
+ }
52
+ var encoded = token.slice(PREFIX.length);
53
+ try {
54
+ var decodedJson = base64UrlDecode(encoded);
55
+ var parsed = JSON.parse(decodedJson);
56
+ if (parsed.v !== 2) throw new Error('unsupported token version');
57
+ var skipTokenRaw = parsed.skipToken;
58
+ var offsetRaw = parsed.offset;
59
+ if (typeof skipTokenRaw !== 'string' || skipTokenRaw.trim() === '') throw new Error('missing skipToken');
60
+ if (typeof offsetRaw !== 'number' || !Number.isInteger(offsetRaw) || offsetRaw < 0) throw new Error('invalid offset');
61
+ return {
62
+ skipToken: skipTokenRaw === FIRST_PAGE_SKIP_TOKEN ? undefined : skipTokenRaw,
63
+ offset: offsetRaw,
64
+ mode: typeof parsed.mode === 'string' ? parsed.mode : undefined,
65
+ legacy: false
66
+ };
67
+ } catch (unused) {
68
+ return {
69
+ skipToken: token,
70
+ offset: 0,
71
+ legacy: true
72
+ };
73
+ }
74
+ }
75
+ function base64UrlEncode(value) {
76
+ return Buffer.from(value, 'utf8').toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
77
+ }
78
+ function base64UrlDecode(value) {
79
+ var padded = value.replace(/-/g, '+').replace(/_/g, '/');
80
+ var padLength = (4 - padded.length % 4) % 4;
81
+ var normalized = padded + '='.repeat(padLength);
82
+ return Buffer.from(normalized, 'base64').toString('utf8');
83
+ }
84
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/email/querying/pagination-token.ts"],"sourcesContent":["const PREFIX = 'v2:';\nexport const FIRST_PAGE_SKIP_TOKEN = '__mcp_outlook_first_page__';\n\ninterface V2Payload {\n v: 2;\n skipToken: string;\n offset: number;\n mode?: string;\n}\n\nexport interface DecodeNextPageTokenResult {\n skipToken?: string;\n offset: number;\n mode?: string;\n legacy: boolean;\n}\n\nexport function encodeNextPageToken(params: { skipToken?: string; offset: number; mode?: string }): string {\n const sanitizedOffset = Math.max(0, Math.trunc(params.offset));\n const payload: V2Payload = {\n v: 2,\n skipToken: params.skipToken ?? FIRST_PAGE_SKIP_TOKEN,\n offset: sanitizedOffset,\n };\n if (typeof params.mode === 'string' && params.mode.length > 0) {\n payload.mode = params.mode;\n }\n const serialized = JSON.stringify(payload);\n return `${PREFIX}${base64UrlEncode(serialized)}`;\n}\n\nexport function decodeNextPageToken(token: string | undefined): DecodeNextPageTokenResult {\n if (!token) {\n return { offset: 0, legacy: true };\n }\n\n if (!token.startsWith(PREFIX)) {\n return { skipToken: token, offset: 0, legacy: true };\n }\n\n const encoded = token.slice(PREFIX.length);\n try {\n const decodedJson = base64UrlDecode(encoded);\n const parsed = JSON.parse(decodedJson) as Record<string, unknown>;\n if (parsed.v !== 2) throw new Error('unsupported token version');\n const skipTokenRaw = parsed.skipToken;\n const offsetRaw = parsed.offset;\n if (typeof skipTokenRaw !== 'string' || skipTokenRaw.trim() === '') throw new Error('missing skipToken');\n if (typeof offsetRaw !== 'number' || !Number.isInteger(offsetRaw) || offsetRaw < 0) throw new Error('invalid offset');\n\n return {\n skipToken: skipTokenRaw === FIRST_PAGE_SKIP_TOKEN ? undefined : skipTokenRaw,\n offset: offsetRaw,\n mode: typeof parsed.mode === 'string' ? parsed.mode : undefined,\n legacy: false,\n };\n } catch {\n return { skipToken: token, offset: 0, legacy: true };\n }\n}\n\nfunction base64UrlEncode(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction base64UrlDecode(value: string): string {\n const padded = value.replace(/-/g, '+').replace(/_/g, '/');\n const padLength = (4 - (padded.length % 4)) % 4;\n const normalized = padded + '='.repeat(padLength);\n return Buffer.from(normalized, 'base64').toString('utf8');\n}\n"],"names":["FIRST_PAGE_SKIP_TOKEN","decodeNextPageToken","encodeNextPageToken","PREFIX","params","sanitizedOffset","Math","max","trunc","offset","payload","v","skipToken","mode","length","serialized","JSON","stringify","base64UrlEncode","token","legacy","startsWith","encoded","slice","decodedJson","base64UrlDecode","parsed","parse","Error","skipTokenRaw","offsetRaw","trim","Number","isInteger","undefined","value","Buffer","from","toString","replace","padded","padLength","normalized","repeat"],"mappings":";;;;;;;;;;;QACaA;eAAAA;;QA8BGC;eAAAA;;QAdAC;eAAAA;;;AAjBhB,IAAMC,SAAS;AACR,IAAMH,wBAAwB;AAgB9B,SAASE,oBAAoBE,MAA6D;QAIlFA;IAHb,IAAMC,kBAAkBC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAACJ,OAAOK,MAAM;IAC5D,IAAMC,UAAqB;QACzBC,GAAG;QACHC,SAAS,GAAER,oBAAAA,OAAOQ,SAAS,cAAhBR,+BAAAA,oBAAoBJ;QAC/BS,QAAQJ;IACV;IACA,IAAI,OAAOD,OAAOS,IAAI,KAAK,YAAYT,OAAOS,IAAI,CAACC,MAAM,GAAG,GAAG;QAC7DJ,QAAQG,IAAI,GAAGT,OAAOS,IAAI;IAC5B;IACA,IAAME,aAAaC,KAAKC,SAAS,CAACP;IAClC,OAAO,AAAC,GAAWQ,OAATf,QAAqC,OAA5Be,gBAAgBH;AACrC;AAEO,SAASd,oBAAoBkB,KAAyB;IAC3D,IAAI,CAACA,OAAO;QACV,OAAO;YAAEV,QAAQ;YAAGW,QAAQ;QAAK;IACnC;IAEA,IAAI,CAACD,MAAME,UAAU,CAAClB,SAAS;QAC7B,OAAO;YAAES,WAAWO;YAAOV,QAAQ;YAAGW,QAAQ;QAAK;IACrD;IAEA,IAAME,UAAUH,MAAMI,KAAK,CAACpB,OAAOW,MAAM;IACzC,IAAI;QACF,IAAMU,cAAcC,gBAAgBH;QACpC,IAAMI,SAASV,KAAKW,KAAK,CAACH;QAC1B,IAAIE,OAAOf,CAAC,KAAK,GAAG,MAAM,IAAIiB,MAAM;QACpC,IAAMC,eAAeH,OAAOd,SAAS;QACrC,IAAMkB,YAAYJ,OAAOjB,MAAM;QAC/B,IAAI,OAAOoB,iBAAiB,YAAYA,aAAaE,IAAI,OAAO,IAAI,MAAM,IAAIH,MAAM;QACpF,IAAI,OAAOE,cAAc,YAAY,CAACE,OAAOC,SAAS,CAACH,cAAcA,YAAY,GAAG,MAAM,IAAIF,MAAM;QAEpG,OAAO;YACLhB,WAAWiB,iBAAiB7B,wBAAwBkC,YAAYL;YAChEpB,QAAQqB;YACRjB,MAAM,OAAOa,OAAOb,IAAI,KAAK,WAAWa,OAAOb,IAAI,GAAGqB;YACtDd,QAAQ;QACV;IACF,EAAE,eAAM;QACN,OAAO;YAAER,WAAWO;YAAOV,QAAQ;YAAGW,QAAQ;QAAK;IACrD;AACF;AAEA,SAASF,gBAAgBiB,KAAa;IACpC,OAAOC,OAAOC,IAAI,CAACF,OAAO,QAAQG,QAAQ,CAAC,UAAUC,OAAO,CAAC,OAAO,KAAKA,OAAO,CAAC,OAAO,KAAKA,OAAO,CAAC,OAAO;AAC9G;AAEA,SAASd,gBAAgBU,KAAa;IACpC,IAAMK,SAASL,MAAMI,OAAO,CAAC,MAAM,KAAKA,OAAO,CAAC,MAAM;IACtD,IAAME,YAAY,AAAC,CAAA,IAAKD,OAAO1B,MAAM,GAAG,CAAC,IAAK;IAC9C,IAAM4B,aAAaF,SAAS,IAAIG,MAAM,CAACF;IACvC,OAAOL,OAAOC,IAAI,CAACK,YAAY,UAAUJ,QAAQ,CAAC;AACpD"}
@@ -1,8 +1,26 @@
1
1
  import type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.js';
2
+ /**
3
+ * Outlook category mappings - case insensitive input to exact system categories
4
+ * Note: These are user-defined categories in Outlook, not system categories like Gmail
5
+ */
6
+ export declare const OUTLOOK_CATEGORIES: {
7
+ readonly personal: "Personal";
8
+ readonly work: "Work";
9
+ readonly family: "Family";
10
+ readonly travel: "Travel";
11
+ readonly important: "Important";
12
+ readonly urgent: "Urgent";
13
+ };
14
+ /**
15
+ * Validate and map category name to Outlook system category
16
+ * Throws error for invalid categories (fail fast principle)
17
+ */
18
+ export declare function mapOutlookCategory(category: string): string;
2
19
  export interface ODataFilterResult {
3
20
  search: string | null;
4
21
  filter: string | null;
5
22
  requireBodyClientFilter: boolean;
23
+ hasFullText: boolean;
6
24
  }
7
25
  export declare function toGraphFilter(query: QueryNode): ODataFilterResult;
8
26
  export declare function toOutlookFilter(parsed: QueryNode, _options?: {
@@ -1,8 +1,26 @@
1
1
  import type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.js';
2
+ /**
3
+ * Outlook category mappings - case insensitive input to exact system categories
4
+ * Note: These are user-defined categories in Outlook, not system categories like Gmail
5
+ */
6
+ export declare const OUTLOOK_CATEGORIES: {
7
+ readonly personal: "Personal";
8
+ readonly work: "Work";
9
+ readonly family: "Family";
10
+ readonly travel: "Travel";
11
+ readonly important: "Important";
12
+ readonly urgent: "Urgent";
13
+ };
14
+ /**
15
+ * Validate and map category name to Outlook system category
16
+ * Throws error for invalid categories (fail fast principle)
17
+ */
18
+ export declare function mapOutlookCategory(category: string): string;
2
19
  export interface ODataFilterResult {
3
20
  search: string | null;
4
21
  filter: string | null;
5
22
  requireBodyClientFilter: boolean;
23
+ hasFullText: boolean;
6
24
  }
7
25
  export declare function toGraphFilter(query: QueryNode): ODataFilterResult;
8
26
  export declare function toOutlookFilter(parsed: QueryNode, _options?: {