@mcp-z/mcp-gmail 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/email/querying/query-builder.js +6 -0
- package/dist/cjs/email/querying/query-builder.js.map +1 -1
- package/dist/cjs/mcp/tools/message-search.d.cts +2 -2
- package/dist/cjs/mcp/tools/message-search.d.ts +2 -2
- package/dist/cjs/mcp/tools/message-search.js +13 -12
- package/dist/cjs/mcp/tools/message-search.js.map +1 -1
- package/dist/cjs/mcp/tools/messages-export-csv.d.cts +2 -2
- package/dist/cjs/mcp/tools/messages-export-csv.d.ts +2 -2
- package/dist/cjs/mcp/tools/messages-export-csv.js +10 -9
- package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -1
- package/dist/cjs/schemas/gmail-query-schema.d.cts +3 -0
- package/dist/cjs/schemas/gmail-query-schema.d.ts +3 -0
- package/dist/cjs/schemas/gmail-query-schema.js +42 -3
- package/dist/cjs/schemas/gmail-query-schema.js.map +1 -1
- package/dist/esm/email/querying/query-builder.js +6 -0
- package/dist/esm/email/querying/query-builder.js.map +1 -1
- package/dist/esm/mcp/tools/message-search.d.ts +2 -2
- package/dist/esm/mcp/tools/message-search.js +14 -13
- package/dist/esm/mcp/tools/message-search.js.map +1 -1
- package/dist/esm/mcp/tools/messages-export-csv.d.ts +2 -2
- package/dist/esm/mcp/tools/messages-export-csv.js +10 -9
- package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -1
- package/dist/esm/schemas/gmail-query-schema.d.ts +3 -0
- package/dist/esm/schemas/gmail-query-schema.js +21 -0
- package/dist/esm/schemas/gmail-query-schema.js.map +1 -1
- package/package.json +1 -1
|
@@ -77,6 +77,12 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
77
77
|
function toGmailQuery(query) {
|
|
78
78
|
var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
79
79
|
var slashDates = options.dateSlash !== false;
|
|
80
|
+
if (query.rawGmailQuery) {
|
|
81
|
+
return {
|
|
82
|
+
q: query.rawGmailQuery,
|
|
83
|
+
filters: {}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
80
86
|
var subjectIncludes = [];
|
|
81
87
|
var bodyIncludes = [];
|
|
82
88
|
var textIncludes = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/email/querying/query-builder.ts"],"sourcesContent":["import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.ts';\n\n/**\n * Field operator interface for query filters\n */\nexport interface FieldOperator {\n $any?: string[];\n $all?: string[];\n $none?: string[];\n}\n\n/**\n * Field query interface with support for all email fields including categories and labels\n */\nexport interface FieldQuery {\n from?: FieldOperator | string;\n to?: FieldOperator | string;\n cc?: FieldOperator | string;\n bcc?: FieldOperator | string;\n subject?: FieldOperator | string;\n text?: FieldOperator | string;\n body?: FieldOperator | string;\n categories?: FieldOperator | string;\n label?: FieldOperator | string;\n}\n\n/**\n * Filter extraction result with all collected values from a query\n */\nexport interface Filters {\n subjectIncludes?: string[];\n bodyIncludes?: string[];\n textIncludes?: string[];\n fromIncludes?: string[];\n toIncludes?: string[];\n ccIncludes?: string[];\n bccIncludes?: string[];\n categoriesIncludes?: string[];\n labelIncludes?: string[];\n hasAttachment?: boolean;\n since?: string;\n before?: string;\n}\n\n/**\n * Gmail category mappings - case insensitive input to exact system labels\n */\nconst GMAIL_CATEGORIES = {\n primary: 'CATEGORY_PERSONAL',\n social: 'CATEGORY_SOCIAL',\n promotions: 'CATEGORY_PROMOTIONS',\n updates: 'CATEGORY_UPDATES',\n forums: 'CATEGORY_FORUMS',\n} as const;\n\n/**\n * Validate and map category name to Gmail system label\n * Throws error for invalid categories (fail fast principle)\n */\nfunction mapCategoryToLabel(category: string): string {\n // Input validation - fail fast on invalid input\n if (!category || typeof category !== 'string') {\n throw new Error(`Invalid category: expected non-empty string, got ${typeof category}`);\n }\n\n const trimmed = category.trim();\n if (trimmed === '') {\n throw new Error('Invalid category: empty string after trimming');\n }\n\n // Fail fast on unknown categories\n const normalizedCategory = trimmed.toLowerCase();\n const systemLabel = GMAIL_CATEGORIES[normalizedCategory as keyof typeof GMAIL_CATEGORIES];\n\n if (!systemLabel) {\n throw new Error(`Invalid Gmail category: \"${category}\". Valid categories: ${Object.keys(GMAIL_CATEGORIES).join(', ')}`);\n }\n\n return systemLabel;\n}\n\nexport function toGmailQuery(query: QueryNode, options: { dateSlash?: boolean } = {}) {\n const slashDates = options.dateSlash !== false;\n const subjectIncludes: string[] = [];\n const bodyIncludes: string[] = [];\n const textIncludes: string[] = [];\n const fromIncludes: string[] = [];\n const toIncludes: string[] = [];\n const ccIncludes: string[] = [];\n const bccIncludes: string[] = [];\n const categoriesIncludes: string[] = [];\n const labelIncludes: string[] = [];\n let hasAttachment: boolean | undefined;\n\n function p(s: unknown) {\n return `(${String(s ?? '')})`;\n }\n function fmt(d: unknown) {\n const str = String(d ?? '');\n return slashDates ? str.replace(/-/g, '/') : str;\n }\n\n function fv(field: string, raw?: unknown) {\n const rawVal = String(raw ?? '');\n if (rawVal.trim() === '') {\n throw new Error(`Invalid ${field} value: empty string`);\n }\n const v = quote(rawVal);\n if (field === 'subject') subjectIncludes.push(rawVal);\n if (field === 'body') bodyIncludes.push(rawVal);\n if (field === 'text') {\n textIncludes.push(rawVal);\n bodyIncludes.push(rawVal);\n }\n if (field === 'from') fromIncludes.push(rawVal);\n if (field === 'to') toIncludes.push(rawVal);\n if (field === 'cc') ccIncludes.push(rawVal);\n if (field === 'bcc') bccIncludes.push(rawVal);\n if (field === 'categories') {\n const systemLabel = mapCategoryToLabel(rawVal);\n categoriesIncludes.push(rawVal);\n return `label:${systemLabel}`;\n }\n if (field === 'label') {\n // Direct passthrough to Gmail's label syntax (case-sensitive)\n labelIncludes.push(rawVal);\n return `label:${quote(rawVal)}`;\n }\n if (field === 'text' || field === 'body') return p(`subject:${v} OR ${v}`);\n return `${field}:${v}`;\n }\n\n function chain(op: 'AND' | 'OR', arr: string[]) {\n if (arr.length === 0) throw new Error(`chain: empty array for ${op} operation`);\n if (arr.length === 1) {\n const first = arr[0] ?? '';\n return first;\n }\n return p(arr.join(` ${op} `));\n }\n\n function fieldExpr(field: string, op: FieldOperator) {\n if (op.$any) {\n const results = op.$any.map((v: string) => fv(field, String(v ?? '')));\n return chain('OR', results);\n }\n if (op.$all) {\n const results = op.$all.map((v: string) => fv(field, String(v ?? '')));\n return chain('AND', results);\n }\n if (op.$none) {\n const results = op.$none.map((v: string) => fv(field, String(v ?? '')));\n return `NOT ${p(chain('OR', results))}`;\n }\n throw new Error(`Unknown field operator ${JSON.stringify(op)}`);\n }\n\n function dateExpr(d: unknown) {\n const parts: string[] = [];\n if (d && typeof d === 'object' && '$gte' in d) {\n parts.push(`after:${fmt(d.$gte)}`);\n }\n if (d && typeof d === 'object' && '$lt' in d) {\n parts.push(`before:${fmt(d.$lt)}`);\n }\n return parts.length > 1 ? p(parts.join(' AND ')) : (parts[0] ?? '');\n }\n\n function fieldKeys() {\n return ['from', 'to', 'cc', 'bcc', 'subject', 'text', 'body', 'categories', 'label'];\n }\n\n function quote(s?: unknown) {\n const str = String(s ?? '');\n return /[\\s\"()]/.test(str) ? `\"${str.replace(/[\"\\\\]/g, (m) => `\\\\${m}`)}\"` : str;\n }\n\n function emit(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return p(n.$and.map(emit).join(' AND '));\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return p(n.$or.map(emit).join(' OR '));\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n // Example: { fuzzyPhrase: \"quarterly report\" } -> \"quarterly report\"\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n\n // Handle empty objects\n const keys = Object.keys(n);\n if (keys.length === 0) return '';\n\n if (keys.length === 1) {\n const k = String(keys[0] ?? '');\n if (fieldKeys().includes(k)) {\n const op = (n as Record<string, unknown>)[k];\n // Handle string-only category queries properly (C2 fix)\n const normalizedOp: FieldOperator = typeof op === 'string' ? { $any: [op] } : (op ?? {});\n return fieldExpr(k, normalizedOp);\n }\n }\n throw new Error(`Unknown node: ${JSON.stringify(n)}`);\n }\n\n function emitTop(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n // Handle empty objects\n if (Object.keys(n).length === 0) return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return n.$and.map(emit).join(' ');\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return n.$or.map(emit).join(' OR ');\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n return emit(n);\n }\n\n const q = emitTop(query);\n const filters: Record<string, unknown> = {};\n if (subjectIncludes.length) filters.subjectIncludes = subjectIncludes;\n if (bodyIncludes.length) filters.bodyIncludes = bodyIncludes;\n if (textIncludes.length) filters.textIncludes = textIncludes;\n if (fromIncludes.length) filters.fromIncludes = fromIncludes;\n if (toIncludes.length) filters.toIncludes = toIncludes;\n if (ccIncludes.length) filters.ccIncludes = ccIncludes;\n if (bccIncludes.length) filters.bccIncludes = bccIncludes;\n if (categoriesIncludes.length) filters.categoriesIncludes = categoriesIncludes;\n if (labelIncludes.length) filters.labelIncludes = labelIncludes;\n if (typeof hasAttachment === 'boolean') filters.hasAttachment = hasAttachment;\n return { q: q ?? '', filters };\n}\n\nexport function extractFiltersFromParsed(parsed: QueryNode): Filters {\n const filters: Filters = {\n subjectIncludes: [],\n bodyIncludes: [],\n textIncludes: [],\n categoriesIncludes: [],\n labelIncludes: [],\n };\n\n function walk(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n\n if ('$and' in node && Array.isArray(node.$and)) {\n node.$and.forEach(walk);\n return;\n }\n if ('$or' in node && Array.isArray(node.$or)) {\n node.$or.forEach(walk);\n return;\n }\n if ('$not' in node) {\n walk(node.$not);\n return;\n }\n if ('hasAttachment' in node) {\n filters.hasAttachment = node.hasAttachment === true;\n return;\n }\n if ('date' in node) {\n const dateObj = node.date;\n if (dateObj && typeof dateObj === 'object') {\n if ('$gte' in dateObj) {\n filters.since = String(dateObj.$gte);\n }\n if ('$lt' in dateObj) {\n filters.before = String(dateObj.$lt);\n }\n }\n return;\n }\n\n const keys = Object.keys(node || {});\n for (const k of keys) {\n const v = (node as Record<string, unknown>)[k];\n if (!v || typeof v !== 'object') continue;\n\n if (k === 'subject') {\n if ('$any' in v && Array.isArray(v.$any)) filters.subjectIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.subjectIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.subjectIncludes?.push(...v.$none);\n } else if (k === 'body') {\n if ('$any' in v && Array.isArray(v.$any)) filters.bodyIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.bodyIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.bodyIncludes?.push(...v.$none);\n } else if (k === 'text') {\n if ('$any' in v && Array.isArray(v.$any)) filters.textIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.textIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.textIncludes?.push(...v.$none);\n } else if (k === 'categories') {\n // Validate all categories (will throw on invalid)\n if ('$any' in v && Array.isArray(v.$any)) {\n v.$any.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$any.map(String));\n }\n if ('$all' in v && Array.isArray(v.$all)) {\n v.$all.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$all.map(String));\n }\n if ('$none' in v && Array.isArray(v.$none)) {\n v.$none.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$none.map(String));\n }\n } else if (k === 'label') {\n // Direct passthrough for labels (case-sensitive)\n if ('$any' in v && Array.isArray(v.$any)) filters.labelIncludes?.push(...v.$any.map(String));\n if ('$all' in v && Array.isArray(v.$all)) filters.labelIncludes?.push(...v.$all.map(String));\n if ('$none' in v && Array.isArray(v.$none)) filters.labelIncludes?.push(...v.$none.map(String));\n }\n }\n }\n walk(parsed);\n return filters;\n}\n"],"names":["extractFiltersFromParsed","toGmailQuery","GMAIL_CATEGORIES","primary","social","promotions","updates","forums","mapCategoryToLabel","category","Error","trimmed","trim","normalizedCategory","toLowerCase","systemLabel","Object","keys","join","query","options","slashDates","dateSlash","subjectIncludes","bodyIncludes","textIncludes","fromIncludes","toIncludes","ccIncludes","bccIncludes","categoriesIncludes","labelIncludes","hasAttachment","p","s","String","fmt","d","str","replace","fv","field","raw","rawVal","v","quote","push","chain","op","arr","length","first","fieldExpr","$any","results","map","$all","$none","JSON","stringify","dateExpr","parts","$gte","$lt","fieldKeys","test","m","emit","n","Array","isArray","$and","$or","$not","fuzzyPhrase","date","k","includes","normalizedOp","emitTop","q","filters","parsed","walk","node","forEach","dateObj","since","before","cat"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/email/querying/query-builder.ts"],"sourcesContent":["import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.ts';\n\n/**\n * Field operator interface for query filters\n */\nexport interface FieldOperator {\n $any?: string[];\n $all?: string[];\n $none?: string[];\n}\n\n/**\n * Field query interface with support for all email fields including categories and labels\n */\nexport interface FieldQuery {\n from?: FieldOperator | string;\n to?: FieldOperator | string;\n cc?: FieldOperator | string;\n bcc?: FieldOperator | string;\n subject?: FieldOperator | string;\n text?: FieldOperator | string;\n body?: FieldOperator | string;\n categories?: FieldOperator | string;\n label?: FieldOperator | string;\n}\n\n/**\n * Filter extraction result with all collected values from a query\n */\nexport interface Filters {\n subjectIncludes?: string[];\n bodyIncludes?: string[];\n textIncludes?: string[];\n fromIncludes?: string[];\n toIncludes?: string[];\n ccIncludes?: string[];\n bccIncludes?: string[];\n categoriesIncludes?: string[];\n labelIncludes?: string[];\n hasAttachment?: boolean;\n since?: string;\n before?: string;\n}\n\n/**\n * Gmail category mappings - case insensitive input to exact system labels\n */\nconst GMAIL_CATEGORIES = {\n primary: 'CATEGORY_PERSONAL',\n social: 'CATEGORY_SOCIAL',\n promotions: 'CATEGORY_PROMOTIONS',\n updates: 'CATEGORY_UPDATES',\n forums: 'CATEGORY_FORUMS',\n} as const;\n\n/**\n * Validate and map category name to Gmail system label\n * Throws error for invalid categories (fail fast principle)\n */\nfunction mapCategoryToLabel(category: string): string {\n // Input validation - fail fast on invalid input\n if (!category || typeof category !== 'string') {\n throw new Error(`Invalid category: expected non-empty string, got ${typeof category}`);\n }\n\n const trimmed = category.trim();\n if (trimmed === '') {\n throw new Error('Invalid category: empty string after trimming');\n }\n\n // Fail fast on unknown categories\n const normalizedCategory = trimmed.toLowerCase();\n const systemLabel = GMAIL_CATEGORIES[normalizedCategory as keyof typeof GMAIL_CATEGORIES];\n\n if (!systemLabel) {\n throw new Error(`Invalid Gmail category: \"${category}\". Valid categories: ${Object.keys(GMAIL_CATEGORIES).join(', ')}`);\n }\n\n return systemLabel;\n}\n\nexport function toGmailQuery(query: QueryNode, options: { dateSlash?: boolean } = {}) {\n const slashDates = options.dateSlash !== false;\n if (query.rawGmailQuery) {\n return { q: query.rawGmailQuery, filters: {} };\n }\n const subjectIncludes: string[] = [];\n const bodyIncludes: string[] = [];\n const textIncludes: string[] = [];\n const fromIncludes: string[] = [];\n const toIncludes: string[] = [];\n const ccIncludes: string[] = [];\n const bccIncludes: string[] = [];\n const categoriesIncludes: string[] = [];\n const labelIncludes: string[] = [];\n let hasAttachment: boolean | undefined;\n\n function p(s: unknown) {\n return `(${String(s ?? '')})`;\n }\n function fmt(d: unknown) {\n const str = String(d ?? '');\n return slashDates ? str.replace(/-/g, '/') : str;\n }\n\n function fv(field: string, raw?: unknown) {\n const rawVal = String(raw ?? '');\n if (rawVal.trim() === '') {\n throw new Error(`Invalid ${field} value: empty string`);\n }\n const v = quote(rawVal);\n if (field === 'subject') subjectIncludes.push(rawVal);\n if (field === 'body') bodyIncludes.push(rawVal);\n if (field === 'text') {\n textIncludes.push(rawVal);\n bodyIncludes.push(rawVal);\n }\n if (field === 'from') fromIncludes.push(rawVal);\n if (field === 'to') toIncludes.push(rawVal);\n if (field === 'cc') ccIncludes.push(rawVal);\n if (field === 'bcc') bccIncludes.push(rawVal);\n if (field === 'categories') {\n const systemLabel = mapCategoryToLabel(rawVal);\n categoriesIncludes.push(rawVal);\n return `label:${systemLabel}`;\n }\n if (field === 'label') {\n // Direct passthrough to Gmail's label syntax (case-sensitive)\n labelIncludes.push(rawVal);\n return `label:${quote(rawVal)}`;\n }\n if (field === 'text' || field === 'body') return p(`subject:${v} OR ${v}`);\n return `${field}:${v}`;\n }\n\n function chain(op: 'AND' | 'OR', arr: string[]) {\n if (arr.length === 0) throw new Error(`chain: empty array for ${op} operation`);\n if (arr.length === 1) {\n const first = arr[0] ?? '';\n return first;\n }\n return p(arr.join(` ${op} `));\n }\n\n function fieldExpr(field: string, op: FieldOperator) {\n if (op.$any) {\n const results = op.$any.map((v: string) => fv(field, String(v ?? '')));\n return chain('OR', results);\n }\n if (op.$all) {\n const results = op.$all.map((v: string) => fv(field, String(v ?? '')));\n return chain('AND', results);\n }\n if (op.$none) {\n const results = op.$none.map((v: string) => fv(field, String(v ?? '')));\n return `NOT ${p(chain('OR', results))}`;\n }\n throw new Error(`Unknown field operator ${JSON.stringify(op)}`);\n }\n\n function dateExpr(d: unknown) {\n const parts: string[] = [];\n if (d && typeof d === 'object' && '$gte' in d) {\n parts.push(`after:${fmt(d.$gte)}`);\n }\n if (d && typeof d === 'object' && '$lt' in d) {\n parts.push(`before:${fmt(d.$lt)}`);\n }\n return parts.length > 1 ? p(parts.join(' AND ')) : (parts[0] ?? '');\n }\n\n function fieldKeys() {\n return ['from', 'to', 'cc', 'bcc', 'subject', 'text', 'body', 'categories', 'label'];\n }\n\n function quote(s?: unknown) {\n const str = String(s ?? '');\n return /[\\s\"()]/.test(str) ? `\"${str.replace(/[\"\\\\]/g, (m) => `\\\\${m}`)}\"` : str;\n }\n\n function emit(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return p(n.$and.map(emit).join(' AND '));\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return p(n.$or.map(emit).join(' OR '));\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n // Example: { fuzzyPhrase: \"quarterly report\" } -> \"quarterly report\"\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n\n // Handle empty objects\n const keys = Object.keys(n);\n if (keys.length === 0) return '';\n\n if (keys.length === 1) {\n const k = String(keys[0] ?? '');\n if (fieldKeys().includes(k)) {\n const op = (n as Record<string, unknown>)[k];\n // Handle string-only category queries properly (C2 fix)\n const normalizedOp: FieldOperator = typeof op === 'string' ? { $any: [op] } : (op ?? {});\n return fieldExpr(k, normalizedOp);\n }\n }\n throw new Error(`Unknown node: ${JSON.stringify(n)}`);\n }\n\n function emitTop(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n // Handle empty objects\n if (Object.keys(n).length === 0) return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return n.$and.map(emit).join(' ');\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return n.$or.map(emit).join(' OR ');\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n return emit(n);\n }\n\n const q = emitTop(query);\n const filters: Record<string, unknown> = {};\n if (subjectIncludes.length) filters.subjectIncludes = subjectIncludes;\n if (bodyIncludes.length) filters.bodyIncludes = bodyIncludes;\n if (textIncludes.length) filters.textIncludes = textIncludes;\n if (fromIncludes.length) filters.fromIncludes = fromIncludes;\n if (toIncludes.length) filters.toIncludes = toIncludes;\n if (ccIncludes.length) filters.ccIncludes = ccIncludes;\n if (bccIncludes.length) filters.bccIncludes = bccIncludes;\n if (categoriesIncludes.length) filters.categoriesIncludes = categoriesIncludes;\n if (labelIncludes.length) filters.labelIncludes = labelIncludes;\n if (typeof hasAttachment === 'boolean') filters.hasAttachment = hasAttachment;\n return { q: q ?? '', filters };\n}\n\nexport function extractFiltersFromParsed(parsed: QueryNode): Filters {\n const filters: Filters = {\n subjectIncludes: [],\n bodyIncludes: [],\n textIncludes: [],\n categoriesIncludes: [],\n labelIncludes: [],\n };\n\n function walk(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n\n if ('$and' in node && Array.isArray(node.$and)) {\n node.$and.forEach(walk);\n return;\n }\n if ('$or' in node && Array.isArray(node.$or)) {\n node.$or.forEach(walk);\n return;\n }\n if ('$not' in node) {\n walk(node.$not);\n return;\n }\n if ('hasAttachment' in node) {\n filters.hasAttachment = node.hasAttachment === true;\n return;\n }\n if ('date' in node) {\n const dateObj = node.date;\n if (dateObj && typeof dateObj === 'object') {\n if ('$gte' in dateObj) {\n filters.since = String(dateObj.$gte);\n }\n if ('$lt' in dateObj) {\n filters.before = String(dateObj.$lt);\n }\n }\n return;\n }\n\n const keys = Object.keys(node || {});\n for (const k of keys) {\n const v = (node as Record<string, unknown>)[k];\n if (!v || typeof v !== 'object') continue;\n\n if (k === 'subject') {\n if ('$any' in v && Array.isArray(v.$any)) filters.subjectIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.subjectIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.subjectIncludes?.push(...v.$none);\n } else if (k === 'body') {\n if ('$any' in v && Array.isArray(v.$any)) filters.bodyIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.bodyIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.bodyIncludes?.push(...v.$none);\n } else if (k === 'text') {\n if ('$any' in v && Array.isArray(v.$any)) filters.textIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.textIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.textIncludes?.push(...v.$none);\n } else if (k === 'categories') {\n // Validate all categories (will throw on invalid)\n if ('$any' in v && Array.isArray(v.$any)) {\n v.$any.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$any.map(String));\n }\n if ('$all' in v && Array.isArray(v.$all)) {\n v.$all.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$all.map(String));\n }\n if ('$none' in v && Array.isArray(v.$none)) {\n v.$none.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$none.map(String));\n }\n } else if (k === 'label') {\n // Direct passthrough for labels (case-sensitive)\n if ('$any' in v && Array.isArray(v.$any)) filters.labelIncludes?.push(...v.$any.map(String));\n if ('$all' in v && Array.isArray(v.$all)) filters.labelIncludes?.push(...v.$all.map(String));\n if ('$none' in v && Array.isArray(v.$none)) filters.labelIncludes?.push(...v.$none.map(String));\n }\n }\n }\n walk(parsed);\n return filters;\n}\n"],"names":["extractFiltersFromParsed","toGmailQuery","GMAIL_CATEGORIES","primary","social","promotions","updates","forums","mapCategoryToLabel","category","Error","trimmed","trim","normalizedCategory","toLowerCase","systemLabel","Object","keys","join","query","options","slashDates","dateSlash","rawGmailQuery","q","filters","subjectIncludes","bodyIncludes","textIncludes","fromIncludes","toIncludes","ccIncludes","bccIncludes","categoriesIncludes","labelIncludes","hasAttachment","p","s","String","fmt","d","str","replace","fv","field","raw","rawVal","v","quote","push","chain","op","arr","length","first","fieldExpr","$any","results","map","$all","$none","JSON","stringify","dateExpr","parts","$gte","$lt","fieldKeys","test","m","emit","n","Array","isArray","$and","$or","$not","fuzzyPhrase","date","k","includes","normalizedOp","emitTop","parsed","walk","node","forEach","dateObj","since","before","cat"],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ declare const inputSchema: z.ZodObject<{
|
|
|
12
12
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
13
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
14
14
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
15
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
15
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
16
16
|
fields: z.ZodOptional<z.ZodString>;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
declare const outputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -125,7 +125,7 @@ export default function createTool(): {
|
|
|
125
125
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
126
126
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
127
127
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
128
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
128
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
129
129
|
fields: z.ZodOptional<z.ZodString>;
|
|
130
130
|
}, z.core.$strip>;
|
|
131
131
|
readonly outputSchema: z.ZodObject<{
|
|
@@ -12,7 +12,7 @@ declare const inputSchema: z.ZodObject<{
|
|
|
12
12
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
13
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
14
14
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
15
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
15
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
16
16
|
fields: z.ZodOptional<z.ZodString>;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
declare const outputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -125,7 +125,7 @@ export default function createTool(): {
|
|
|
125
125
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
126
126
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
127
127
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
128
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
128
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
129
129
|
fields: z.ZodOptional<z.ZodString>;
|
|
130
130
|
}, z.core.$strip>;
|
|
131
131
|
readonly outputSchema: z.ZodObject<{
|
|
@@ -207,7 +207,7 @@ function _ts_generator(thisArg, body) {
|
|
|
207
207
|
}
|
|
208
208
|
var AuthRequiredBranchSchema = _oauthgoogle.schemas.AuthRequiredBranchSchema;
|
|
209
209
|
var inputSchema = _zod.z.object(_object_spread_props(_object_spread({
|
|
210
|
-
query: _gmailqueryschemats.
|
|
210
|
+
query: _gmailqueryschemats.GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),
|
|
211
211
|
fields: (0, _server.createFieldsSchema)({
|
|
212
212
|
availableFields: _email.EMAIL_FIELDS,
|
|
213
213
|
fieldDescriptions: _email.EMAIL_FIELD_DESCRIPTIONS,
|
|
@@ -253,30 +253,31 @@ var config = {
|
|
|
253
253
|
};
|
|
254
254
|
function handler(_0, _1) {
|
|
255
255
|
return _async_to_generator(function(param, extra) {
|
|
256
|
-
var query, _param_pageSize, pageSize, pageToken, fields, _param_shape, shape, _param_contentType, contentType, _param_excludeThreadHistory, excludeThreadHistory, logger, requestedFields, includeBody, gmail, started, exec, items, metadata, durationMs, filteredItems, metadataObj, result, error, message;
|
|
256
|
+
var query, _param_pageSize, pageSize, pageToken, fields, _param_shape, shape, _param_contentType, contentType, _param_excludeThreadHistory, excludeThreadHistory, logger, parsedQuery, requestedFields, includeBody, gmail, started, exec, items, metadata, durationMs, filteredItems, metadataObj, result, error, message;
|
|
257
257
|
return _ts_generator(this, function(_state) {
|
|
258
258
|
switch(_state.label){
|
|
259
259
|
case 0:
|
|
260
260
|
query = param.query, _param_pageSize = param.pageSize, pageSize = _param_pageSize === void 0 ? _constantsts.DEFAULT_PAGE_SIZE : _param_pageSize, pageToken = param.pageToken, fields = param.fields, _param_shape = param.shape, shape = _param_shape === void 0 ? 'arrays' : _param_shape, _param_contentType = param.contentType, contentType = _param_contentType === void 0 ? 'text' : _param_contentType, _param_excludeThreadHistory = param.excludeThreadHistory, excludeThreadHistory = _param_excludeThreadHistory === void 0 ? false : _param_excludeThreadHistory;
|
|
261
261
|
logger = extra.logger;
|
|
262
|
+
_state.label = 1;
|
|
263
|
+
case 1:
|
|
264
|
+
_state.trys.push([
|
|
265
|
+
1,
|
|
266
|
+
3,
|
|
267
|
+
,
|
|
268
|
+
4
|
|
269
|
+
]);
|
|
270
|
+
parsedQuery = (0, _gmailqueryschemats.parseGmailQueryParameter)(query);
|
|
262
271
|
requestedFields = (0, _server.parseFields)(fields, _email.EMAIL_FIELDS);
|
|
263
272
|
includeBody = requestedFields === 'all' || requestedFields.has('body');
|
|
264
273
|
logger.info('gmail.message.search called', {
|
|
265
|
-
query:
|
|
274
|
+
query: parsedQuery,
|
|
266
275
|
pageSize: pageSize,
|
|
267
276
|
pageToken: pageToken ? '[provided]' : undefined,
|
|
268
277
|
fields: fields,
|
|
269
278
|
includeBody: includeBody,
|
|
270
279
|
accountId: extra.authContext.accountId
|
|
271
280
|
});
|
|
272
|
-
_state.label = 1;
|
|
273
|
-
case 1:
|
|
274
|
-
_state.trys.push([
|
|
275
|
-
1,
|
|
276
|
-
3,
|
|
277
|
-
,
|
|
278
|
-
4
|
|
279
|
-
]);
|
|
280
281
|
gmail = _googleapis.google.gmail({
|
|
281
282
|
version: 'v1',
|
|
282
283
|
auth: extra.authContext.auth
|
|
@@ -284,7 +285,7 @@ function handler(_0, _1) {
|
|
|
284
285
|
started = Date.now();
|
|
285
286
|
return [
|
|
286
287
|
4,
|
|
287
|
-
(0, _executequeryts.executeQuery)(
|
|
288
|
+
(0, _executequeryts.executeQuery)(parsedQuery, _object_spread_props(_object_spread({
|
|
288
289
|
client: gmail,
|
|
289
290
|
logger: logger,
|
|
290
291
|
pageSize: pageSize
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["createTool","AuthRequiredBranchSchema","schemas","inputSchema","z","object","query","GmailQuerySchema","optional","describe","fields","createFieldsSchema","availableFields","EMAIL_FIELDS","fieldDescriptions","EMAIL_FIELD_DESCRIPTIONS","commonPatterns","EMAIL_COMMON_PATTERNS","resourceName","createPaginationSchema","defaultPageSize","DEFAULT_PAGE_SIZE","maxPageSize","MAX_PAGE_SIZE","provider","shape","createShapeSchema","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successObjectsBranchSchema","type","literal","items","array","EmailDetailSchema","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","extra","pageSize","pageToken","logger","requestedFields","includeBody","gmail","started","exec","metadata","durationMs","filteredItems","metadataObj","error","message","parseFields","has","info","undefined","accountId","authContext","google","version","auth","Date","now","executeGmailQuery","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","extractBodyFromPayload","bodyContentType","item","filterFields","resultCount","length","toColumnarFormat","content","text","JSON","stringify","structuredContent","Error","McpError","ErrorCode","InternalError","stack"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query: parsedQuery,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["createTool","AuthRequiredBranchSchema","schemas","inputSchema","z","object","query","GmailQueryParameterSchema","optional","describe","fields","createFieldsSchema","availableFields","EMAIL_FIELDS","fieldDescriptions","EMAIL_FIELD_DESCRIPTIONS","commonPatterns","EMAIL_COMMON_PATTERNS","resourceName","createPaginationSchema","defaultPageSize","DEFAULT_PAGE_SIZE","maxPageSize","MAX_PAGE_SIZE","provider","shape","createShapeSchema","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successObjectsBranchSchema","type","literal","items","array","EmailDetailSchema","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","extra","pageSize","pageToken","logger","parsedQuery","requestedFields","includeBody","gmail","started","exec","metadata","durationMs","filteredItems","metadataObj","error","message","parseGmailQueryParameter","parseFields","has","info","undefined","accountId","authContext","google","version","auth","Date","now","executeGmailQuery","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","extractBodyFromPayload","bodyContentType","item","filterFields","resultCount","length","toColumnarFormat","content","text","JSON","stringify","structuredContent","Error","McpError","ErrorCode","InternalError","stack"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { EnrichedExtra } from '@mcp-z/oauth-google';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { StorageExtra } from '../../types.js';
|
|
4
4
|
declare const inputSchema: z.ZodObject<{
|
|
5
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
5
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
6
6
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
filename: z.ZodDefault<z.ZodString>;
|
|
8
8
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -55,7 +55,7 @@ export default function createTool(): {
|
|
|
55
55
|
config: {
|
|
56
56
|
readonly description: "Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.";
|
|
57
57
|
readonly inputSchema: z.ZodObject<{
|
|
58
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
58
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
59
59
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
60
60
|
filename: z.ZodDefault<z.ZodString>;
|
|
61
61
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -2,7 +2,7 @@ import type { EnrichedExtra } from '@mcp-z/oauth-google';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { StorageExtra } from '../../types.js';
|
|
4
4
|
declare const inputSchema: z.ZodObject<{
|
|
5
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
5
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
6
6
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
filename: z.ZodDefault<z.ZodString>;
|
|
8
8
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -55,7 +55,7 @@ export default function createTool(): {
|
|
|
55
55
|
config: {
|
|
56
56
|
readonly description: "Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.";
|
|
57
57
|
readonly inputSchema: z.ZodObject<{
|
|
58
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
58
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
59
59
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
60
60
|
filename: z.ZodDefault<z.ZodString>;
|
|
61
61
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -212,7 +212,7 @@ var AuthRequiredBranchSchema = _oauthgoogle.schemas.AuthRequiredBranchSchema;
|
|
|
212
212
|
var DEFAULT_MAX_ITEMS = 10000;
|
|
213
213
|
var MAX_EXPORT_ITEMS = 50000;
|
|
214
214
|
var inputSchema = _zod.z.object({
|
|
215
|
-
query: _gmailqueryschemats.
|
|
215
|
+
query: _gmailqueryschemats.GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),
|
|
216
216
|
maxItems: _zod.z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe("Maximum messages to export (default: ".concat(DEFAULT_MAX_ITEMS, ", max: ").concat(MAX_EXPORT_ITEMS, ")")),
|
|
217
217
|
filename: _zod.z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),
|
|
218
218
|
contentType: _email.EmailContentTypeSchema,
|
|
@@ -247,7 +247,7 @@ var config = {
|
|
|
247
247
|
* - NO RETRIES (fail fast on error)
|
|
248
248
|
*/ function handler(_0, _1) {
|
|
249
249
|
return _async_to_generator(function(param, extra) {
|
|
250
|
-
var query, maxItems, filename, contentType, excludeThreadHistory, logger, storageContext, transport, resourceStoreUri, baseUrl, reservation, storedName, fullPath, gmail, csvHeaders, writeStream, headerLine, totalRows, nextPageToken, started, _exec_metadata, remainingItems, pageSize, exec, csvRows, rowsContent, durationMs, truncated, uri, result, error, _cleanupError, message;
|
|
250
|
+
var query, maxItems, filename, contentType, excludeThreadHistory, logger, storageContext, transport, resourceStoreUri, baseUrl, reservation, storedName, fullPath, parsedQuery, gmail, csvHeaders, writeStream, headerLine, totalRows, nextPageToken, started, _exec_metadata, remainingItems, pageSize, exec, csvRows, rowsContent, durationMs, truncated, uri, result, error, _cleanupError, message;
|
|
251
251
|
return _ts_generator(this, function(_state) {
|
|
252
252
|
switch(_state.label){
|
|
253
253
|
case 0:
|
|
@@ -255,12 +255,6 @@ var config = {
|
|
|
255
255
|
logger = extra.logger;
|
|
256
256
|
storageContext = extra.storageContext;
|
|
257
257
|
transport = storageContext.transport, resourceStoreUri = storageContext.resourceStoreUri, baseUrl = storageContext.baseUrl;
|
|
258
|
-
logger.info('gmail.messages.export-csv called', {
|
|
259
|
-
query: query,
|
|
260
|
-
maxItems: maxItems,
|
|
261
|
-
filename: filename,
|
|
262
|
-
accountId: extra.authContext.accountId
|
|
263
|
-
});
|
|
264
258
|
return [
|
|
265
259
|
4,
|
|
266
260
|
(0, _server.reserveFile)(filename, {
|
|
@@ -282,6 +276,13 @@ var config = {
|
|
|
282
276
|
,
|
|
283
277
|
12
|
|
284
278
|
]);
|
|
279
|
+
parsedQuery = (0, _gmailqueryschemats.parseGmailQueryParameter)(query);
|
|
280
|
+
logger.info('gmail.messages.export-csv called', {
|
|
281
|
+
query: parsedQuery,
|
|
282
|
+
maxItems: maxItems,
|
|
283
|
+
filename: filename,
|
|
284
|
+
accountId: extra.authContext.accountId
|
|
285
|
+
});
|
|
285
286
|
gmail = _googleapis.google.gmail({
|
|
286
287
|
version: 'v1',
|
|
287
288
|
auth: extra.authContext.auth
|
|
@@ -328,7 +329,7 @@ var config = {
|
|
|
328
329
|
pageSize = Math.min(remainingItems, _constantsts.DEFAULT_PAGE_SIZE);
|
|
329
330
|
return [
|
|
330
331
|
4,
|
|
331
|
-
(0, _executequeryts.executeQuery)(
|
|
332
|
+
(0, _executequeryts.executeQuery)(parsedQuery, _object_spread_props(_object_spread({
|
|
332
333
|
client: gmail,
|
|
333
334
|
logger: logger,
|
|
334
335
|
pageSize: pageSize
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n logger.info('gmail.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["createTool","AuthRequiredBranchSchema","schemas","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","z","object","query","GmailQuerySchema","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","gmail","csvHeaders","writeStream","headerLine","totalRows","nextPageToken","started","exec","remainingItems","pageSize","csvRows","rowsContent","durationMs","error","_cleanupError","message","info","accountId","authContext","reserveFile","path","google","version","auth","createWriteStream","encoding","stringify","header","quoted","quote","escape","write","Date","now","Math","DEFAULT_PAGE_SIZE","executeGmailQuery","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","extractBodyFromPayload","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","items","row","length","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","getFileUri","endpoint","content","text","JSON","structuredContent","unlink","debug","Error","McpError","ErrorCode","InternalError","stack"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n\n logger.info('gmail.messages.export-csv called', {\n query: parsedQuery,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["createTool","AuthRequiredBranchSchema","schemas","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","z","object","query","GmailQueryParameterSchema","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","parsedQuery","gmail","csvHeaders","writeStream","headerLine","totalRows","nextPageToken","started","exec","remainingItems","pageSize","csvRows","rowsContent","durationMs","error","_cleanupError","message","reserveFile","info","path","parseGmailQueryParameter","accountId","authContext","google","version","auth","createWriteStream","encoding","stringify","header","quoted","quote","escape","write","Date","now","Math","DEFAULT_PAGE_SIZE","executeGmailQuery","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","extractBodyFromPayload","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","items","row","length","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","getFileUri","endpoint","content","text","JSON","structuredContent","unlink","debug","Error","McpError","ErrorCode","InternalError","stack"],"mappings":";;;;+BAsQA;;;eAAwBA;;;qBAtQ2C;2BAE3C;sBAIiC;qBACrB;oBAEV;kBACQ;wBACX;0BACe;mBACpB;2BACgB;gCACK;8BACW;kCACkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAbpE,IAAM,AAAEC,2BAA6BC,oBAAO,CAApCD;AAgBR,IAAME,oBAAoB;AAC1B,IAAMC,mBAAmB;AAsBzB,IAAMC,cAAcC,MAAC,CAACC,MAAM,CAAC;IAC3BC,OAAOC,6CAAyB,CAACC,QAAQ,GAAGC,QAAQ,CAAC;IACrDC,UAAUN,MAAC,CAACO,MAAM,GAAGC,GAAG,GAAGC,QAAQ,GAAGC,GAAG,CAACZ,kBAAkBa,OAAO,CAACd,mBAAmBQ,QAAQ,CAAC,AAAC,wCAAkEP,OAA3BD,mBAAkB,WAA0B,OAAjBC,kBAAiB;IACpLc,UAAUZ,MAAC,CAACa,MAAM,GAAGC,IAAI,GAAGC,GAAG,CAAC,GAAGJ,OAAO,CAAC,sBAAsBN,QAAQ,CAAC;IAC1EW,aAAaC,6BAAsB;IACnCC,sBAAsBC,iCAA0B;AAClD;AAEA,IAAMC,sBAAsBpB,MAAC,CAACC,MAAM,CAAC;IACnCoB,MAAMrB,MAAC,CAACsB,OAAO,CAAC;IAChBC,KAAKvB,MAAC,CAACa,MAAM,GAAGR,QAAQ,CAAC;IACzBO,UAAUZ,MAAC,CAACa,MAAM,GAAGR,QAAQ,CAAC;IAC9BmB,UAAUxB,MAAC,CAACO,MAAM,GAAGF,QAAQ,CAAC;IAC9BoB,WAAWzB,MAAC,CAAC0B,OAAO,GAAGrB,QAAQ,CAAC;AAClC;AAEA,IAAMsB,eAAe3B,MAAC,CAAC4B,kBAAkB,CAAC,QAAQ;IAACR;IAAqBzB;CAAyB;AAEjG,IAAMkC,SAAS;IACbC,aAAa;IACb/B,aAAaA;IACb4B,cAAc3B,MAAC,CAACC,MAAM,CAAC;QACrB8B,QAAQJ;IACV;AACF;AAKA;;;;;;;;;CASC,GACD,SAAeK;wCAAQ,KAAuE,EAAEC,KAAmC;YAA1G/B,OAAOI,UAAUM,UAAUI,aAAaE,sBACzDgB,QACEC,gBACAC,WAAWC,kBAAkBC,SAG/BC,aAGEC,YAAYC,UAKZC,aASAC,OAGAC,YAGAC,aACAC,YAKFC,WACAC,eACEC,SAuEYC,gBApEVC,gBACAC,UAEAF,MAsDAG,SAMEC,aAyBJC,YACA9B,WAUAF,KAMAQ,QAiBCyB,OAKEC,eAIHC;;;;oBA3KexD,QAAF,MAAEA,OAAOI,WAAT,MAASA,UAAUM,WAAnB,MAAmBA,UAAUI,cAA7B,MAA6BA,aAAaE,uBAA1C,MAA0CA;oBACzDgB,SAASD,MAAMC,MAAM;oBACnBC,iBAAmBF,MAAnBE;oBACAC,YAAyCD,eAAzCC,WAAWC,mBAA8BF,eAA9BE,kBAAkBC,UAAYH,eAAZG;oBAGjB;;wBAAMqB,IAAAA,mBAAW,EAAC/C,UAAU;4BAC9CyB,kBAAAA;wBACF;;;oBAFME,cAAc;oBAGZC,aAAyBD,YAAzBC,YAAYC,WAAaF,YAAbE;oBAEpBP,OAAO0B,IAAI,CAAC,uDAAuD;wBAAEC,MAAMpB;wBAAUnC,UAAAA;oBAAS;;;;;;;;;oBAGtFoC,cAAcoB,IAAAA,4CAAwB,EAAC5D;oBAE7CgC,OAAO0B,IAAI,CAAC,oCAAoC;wBAC9C1D,OAAOwC;wBACPpC,UAAAA;wBACAM,UAAAA;wBACAmD,WAAW9B,MAAM+B,WAAW,CAACD,SAAS;oBACxC;oBAEMpB,QAAQsB,kBAAM,CAACtB,KAAK,CAAC;wBAAEuB,SAAS;wBAAMC,MAAMlC,MAAM+B,WAAW,CAACG,IAAI;oBAAC;oBAEzE,wCAAwC;oBAClCvB;wBAAc;wBAAM;wBAAY;wBAAQ;wBAAM;wBAAM;wBAAO;wBAAW;wBAAQ;wBAAW;wBAAQ;wBAAY;;oBAEnH,oDAAoD;oBAC9CC,cAAcuB,IAAAA,qBAAiB,EAAC3B,UAAU;wBAAE4B,UAAU;oBAAQ;oBAC9DvB,aAAawB,IAAAA,eAAS;wBAAE1B;uBAAa;wBAAE2B,QAAQ;wBAAOC,QAAQ;wBAAMC,OAAO;wBAAKC,QAAQ;oBAAI;oBAClG7B,YAAY8B,KAAK,CAAC7B;oBAElB,2DAA2D;oBAC3D,yEAAyE;oBACrEC,YAAY;oBAEVE,UAAU2B,KAAKC,GAAG;;;yBAEjB9B,CAAAA,YAAYzC,QAAO;;;;oBAClB6C,iBAAiB7C,WAAWyC;oBAC5BK,WAAW0B,KAAK/D,GAAG,CAACoC,gBAAgB4B,8BAAiB;oBAKvD;;wBAAMC,IAAAA,4BAAiB,EACzBtC,aACA;4BACEuC,QAAQtC;4BACRT,QAAAA;4BACAkB,UAAAA;2BACIJ,kBAAkBkC,aAAa;4BAAEC,WAAWnC;wBAAc;4BAC9DoC,aAAa;4BAEf,SAACC;;gCAUoCC;4BATnC,wCAAwC;4BACxC,IAAMA,WAAWD;4BAQjB,IAAME,eAAeC,MAAMC,OAAO,CAACH,qBAAAA,gCAAAA,oBAAAA,SAAUI,OAAO,cAAjBJ,wCAAAA,kBAAmBK,OAAO,IAAIL,SAASI,OAAO,CAACC,OAAO,GAAG,EAAE;4BAC9F,IAAMA,UAAUC,OAAOC,WAAW,CAChCN,aAAaO,GAAG,CAAC,SAACC;oCAEDxB,cAA2BA;gCAD1C,IAAMA,SAASwB;gCACf,OAAO;oCAACC,QAAOzB,eAAAA,OAAO0B,IAAI,cAAX1B,0BAAAA,eAAe;oCAAKyB,QAAOzB,gBAAAA,OAAO2B,KAAK,cAAZ3B,2BAAAA,gBAAgB;iCAAI;4BAChE;4BAGF,IAAMmB,UAAUJ,qBAAAA,+BAAAA,SAAUI,OAAO;4BACjC,wDAAwD;4BACxD,IAAMS,OAAOT,UAAUU,IAAAA,wCAAsB,EAACV,SAAwC;gCAAE1E,aAAAA;gCAAaE,sBAAAA;4BAAqB,KAAK;4BAE/H,IAAMmF,WAAWb,MAAMC,OAAO,CAACH,qBAAAA,+BAAAA,SAAUe,QAAQ,IAAIf,SAASe,QAAQ,CAACP,GAAG,CAAC,SAACQ;uCAAON,OAAOM,eAAAA,gBAAAA,KAAM;iCAAO,EAAE;4BAEzG,OAAO;gCACLA,IAAIN,eAAOV,qBAAAA,+BAAAA,SAAUgB,EAAE,uCAAI;gCAC3BC,UAAUjB,CAAAA,qBAAAA,+BAAAA,SAAUiB,QAAQ,IAAGP,OAAOV,SAASiB,QAAQ,IAAI;gCAC3DC,MAAMb,CAAAA,oBAAAA,8BAAAA,QAASc,IAAI,KAAI;gCACvBC,IAAIf,CAAAA,oBAAAA,8BAAAA,QAASgB,EAAE,KAAI;gCACnBC,IAAIjB,CAAAA,oBAAAA,8BAAAA,QAASkB,EAAE,KAAI;gCACnBC,KAAKnB,CAAAA,oBAAAA,8BAAAA,QAASoB,GAAG,KAAI;gCACrBC,SAASrB,CAAAA,oBAAAA,8BAAAA,QAASsB,OAAO,KAAI;gCAC7BC,MAAMvB,CAAAA,oBAAAA,8BAAAA,QAASf,IAAI,KAAI;gCACvBuC,SAAS7B,CAAAA,qBAAAA,+BAAAA,SAAU6B,OAAO,IAAGnB,OAAOV,SAAS6B,OAAO,IAAI;gCACxDhB,MAAAA;gCACAiB,UAAU;gCACVC,QAAQhB,SAASiB,IAAI,CAAC;4BACxB;wBACF;;;oBAlDIpE,OAGF;oBAkDJ,4BAA4B;oBACtBG,UAAUH,KAAKqE,KAAK,CAACzB,GAAG,CAAC,SAAC0B;wBAC9B,OAAO;4BAACA,IAAIlB,EAAE;4BAAEkB,IAAIjB,QAAQ;4BAAEiB,IAAIhB,IAAI;4BAAEgB,IAAId,EAAE;4BAAEc,IAAIZ,EAAE;4BAAEY,IAAIV,GAAG;4BAAEU,IAAIR,OAAO;4BAAEQ,IAAIN,IAAI;4BAAEM,IAAIL,OAAO;4BAAEK,IAAIrB,IAAI;4BAAEqB,IAAIJ,QAAQ;4BAAEI,IAAIH,MAAM;yBAAC;oBAC1I;oBAEA,sCAAsC;oBACtC,IAAIhE,QAAQoE,MAAM,GAAG,GAAG;wBAChBnE,cAAcgB,IAAAA,eAAS,EAACjB,SAAS;4BAAEkB,QAAQ;4BAAOC,QAAQ;4BAAMC,OAAO;4BAAKC,QAAQ;wBAAI;wBAC9F7B,YAAY8B,KAAK,CAACrB;oBACpB;oBAEAP,aAAaG,KAAKqE,KAAK,CAACE,MAAM;oBAC9BzE,iBAAgBE,iBAAAA,KAAKwE,QAAQ,cAAbxE,qCAAAA,eAAeF,aAAa;oBAE5Cd,OAAO0B,IAAI,CAAC,2CAA2C;wBACrD+D,WAAWzE,KAAKqE,KAAK,CAACE,MAAM;wBAC5B1E,WAAAA;wBACA6E,SAASC,QAAQ7E;oBACnB;oBAEA,8CAA8C;oBAC9C,IAAI,CAACA,iBAAiBE,KAAKqE,KAAK,CAACE,MAAM,KAAK,GAAG;wBAC7C;;;;oBACF;;;;;;oBAGF,qBAAqB;oBACrB;;wBAAM,IAAIK,QAAc,SAACC,SAASC;4BAChCnF,YAAYoF,GAAG,CAAC;uCAAMF;;4BACtBlF,YAAYqF,EAAE,CAAC,SAASF;wBAC1B;;;oBAHA;oBAKMzE,aAAaqB,KAAKC,GAAG,KAAK5B;oBAC1BxB,YAAYsB,aAAazC,YAAYuH,QAAQ7E;oBAEnDd,OAAO0B,IAAI,CAAC,uCAAuC;wBACjDpC,UAAUuB;wBACVtB,WAAAA;wBACA8B,YAAAA;wBACA3C,UAAU4B;oBACZ;oBAEA,uEAAuE;oBACjEjB,MAAM4G,IAAAA,kBAAU,EAAC3F,YAAYJ,WAAW;wBAC5CC,kBAAAA;uBACIC,WAAW;wBAAEA,SAAAA;oBAAQ;wBACzB8F,UAAU;;oBAGNrG,SAAiB;wBACrBV,MAAM;wBACNE,KAAAA;wBACAX,UAAU4B;wBACVhB,UAAUuB;wBACVtB,WAAAA;oBACF;oBAEA;;wBAAO;4BACL4G,OAAO;gCACL;oCACEhH,MAAM;oCACNiH,MAAMC,KAAKjE,SAAS,CAACvC;gCACvB;;4BAEFyG,mBAAmB;gCAAEzG,QAAAA;4BAAO;wBAC9B;;;oBACOyB;;;;;;;;;oBAGL;;wBAAMiF,IAAAA,gBAAM,EAAChG;;;oBAAb;oBACAP,OAAOwG,KAAK,CAAC,2CAA2C;wBAAE7E,MAAMpB;oBAAS;;;;;;oBAClEgB;oBACPvB,OAAOwG,KAAK,CAAC,+CAA+C;wBAAE7E,MAAMpB;oBAAS;;;;;;oBAGzEiB,UAAUF,AAAK,YAALA,OAAiBmF,SAAQnF,MAAME,OAAO,GAAGsC,OAAOxC;oBAChEtB,OAAOsB,KAAK,CAAC,mCAAmC;wBAAEA,OAAOE;oBAAQ;oBAEjE,MAAM,IAAIkF,eAAQ,CAACC,gBAAS,CAACC,aAAa,EAAE,AAAC,oCAA2C,OAARpF,UAAW;wBACzFqF,OAAOvF,AAAK,YAALA,OAAiBmF,SAAQnF,MAAMuF,KAAK,GAAG7D;oBAChD;;;;;;;IAEJ;;AAEe,SAASxF;IACtB,OAAO;QACLuG,MAAM;QACNpE,QAAAA;QACAG,SAAAA;IACF;AACF"}
|
|
@@ -21,6 +21,9 @@ import { z } from 'zod';
|
|
|
21
21
|
* TypeScript sees the strict GmailQuery type everywhere the schema is used.
|
|
22
22
|
*/
|
|
23
23
|
export declare const GmailQuerySchema: z.ZodType<GmailQuery>;
|
|
24
|
+
export declare const GmailQueryParameterSchema: z.ZodType<GmailQuery | string>;
|
|
25
|
+
export type GmailQueryParameter = z.infer<typeof GmailQueryParameterSchema>;
|
|
26
|
+
export declare function parseGmailQueryParameter(input: GmailQuery | string | undefined): GmailQuery | undefined;
|
|
24
27
|
export type GmailQuery = BaseEmailQueryFields & {
|
|
25
28
|
$and?: GmailQuery[];
|
|
26
29
|
$or?: GmailQuery[];
|
|
@@ -21,6 +21,9 @@ import { z } from 'zod';
|
|
|
21
21
|
* TypeScript sees the strict GmailQuery type everywhere the schema is used.
|
|
22
22
|
*/
|
|
23
23
|
export declare const GmailQuerySchema: z.ZodType<GmailQuery>;
|
|
24
|
+
export declare const GmailQueryParameterSchema: z.ZodType<GmailQuery | string>;
|
|
25
|
+
export type GmailQueryParameter = z.infer<typeof GmailQueryParameterSchema>;
|
|
26
|
+
export declare function parseGmailQueryParameter(input: GmailQuery | string | undefined): GmailQuery | undefined;
|
|
24
27
|
export type GmailQuery = BaseEmailQueryFields & {
|
|
25
28
|
$and?: GmailQuery[];
|
|
26
29
|
$or?: GmailQuery[];
|
|
@@ -2,10 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 GmailQueryParameterSchema () {
|
|
13
|
+
return GmailQueryParameterSchema;
|
|
14
|
+
},
|
|
15
|
+
get GmailQuerySchema () {
|
|
8
16
|
return GmailQuerySchema;
|
|
17
|
+
},
|
|
18
|
+
get parseGmailQueryParameter () {
|
|
19
|
+
return parseGmailQueryParameter;
|
|
9
20
|
}
|
|
10
21
|
});
|
|
11
22
|
var _email = require("@mcp-z/email");
|
|
@@ -23,6 +34,13 @@ function _define_property(obj, key, value) {
|
|
|
23
34
|
}
|
|
24
35
|
return obj;
|
|
25
36
|
}
|
|
37
|
+
function _instanceof(left, right) {
|
|
38
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
39
|
+
return !!right[Symbol.hasInstance](left);
|
|
40
|
+
} else {
|
|
41
|
+
return left instanceof right;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
26
44
|
function _object_spread(target) {
|
|
27
45
|
for(var i = 1; i < arguments.length; i++){
|
|
28
46
|
var source = arguments[i] != null ? arguments[i] : {};
|
|
@@ -114,4 +132,25 @@ var GmailQuerySchema = _zod.z.lazy(function() {
|
|
|
114
132
|
rawGmailQuery: _zod.z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.')
|
|
115
133
|
})).strict();
|
|
116
134
|
});
|
|
135
|
+
var GmailQueryParameterSchema = _zod.z.union([
|
|
136
|
+
GmailQuerySchema,
|
|
137
|
+
_zod.z.string().min(1)
|
|
138
|
+
]);
|
|
139
|
+
function parseGmailQueryParameter(input) {
|
|
140
|
+
if (input === undefined) return undefined;
|
|
141
|
+
var raw = typeof input === 'string' ? safeJsonParse(input, 'rawGmailQuery') : input;
|
|
142
|
+
var validated = GmailQuerySchema.safeParse(raw);
|
|
143
|
+
if (!validated.success) {
|
|
144
|
+
throw new Error("Invalid query JSON: ".concat(validated.error.message, '. Use {"rawGmailQuery":"<query>"} for Gmail syntax.'));
|
|
145
|
+
}
|
|
146
|
+
return validated.data;
|
|
147
|
+
}
|
|
148
|
+
function safeJsonParse(value, rawField) {
|
|
149
|
+
try {
|
|
150
|
+
return JSON.parse(value);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
var message = _instanceof(error, Error) ? error.message : 'Invalid JSON';
|
|
153
|
+
throw new Error("Query must be valid JSON. ".concat(message, '. Wrap Gmail syntax in {"').concat(rawField, '":"<query>"} if needed.'));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
117
156
|
/* 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; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/schemas/gmail-query-schema.ts"],"sourcesContent":["import { type BaseEmailQueryFields, baseEmailQueryFields, type FieldOperator, FieldOperatorSchema } from '@mcp-z/email';\nimport { z } from 'zod';\n\n/**\n * Gmail-specific query schema with recursive operators and Gmail features.\n *\n * Includes Gmail-specific features:\n * - fuzzyPhrase: Approximate phrase matching (Gmail's quoted string behavior with relevance ranking)\n * - categories: Gmail system categories (primary, social, promotions, updates, forums)\n * - label: User-created Gmail labels (case-sensitive, discovered via gmail-labels-list)\n * - rawGmailQuery: Escape hatch for advanced Gmail query syntax\n *\n * Plus all base fields from baseEmailQueryFields:\n * - Email addresses: from, to, cc, bcc (support string or field operators)\n * - Content: subject, body, text\n * - Flags: hasAttachment, isRead\n * - Date range: date { $gte, $lt }\n * - Logical operators: $and, $or, $not (recursive)\n *\n * Note: Cast through unknown to work around Zod's lazy schema type inference issue\n * with exactOptionalPropertyTypes. The runtime schema is correct; this cast ensures\n * TypeScript sees the strict GmailQuery type everywhere the schema is used.\n */\nexport const GmailQuerySchema = z.lazy(() =>\n z\n .object({\n // Logical operators for combining conditions (recursive)\n $and: z.array(GmailQuerySchema).optional().describe('Array of conditions that must ALL match'),\n $or: z.array(GmailQuerySchema).optional().describe('Array of conditions where ANY must match'),\n $not: GmailQuerySchema.optional().describe('Nested condition that must NOT match'),\n\n // Spread base email query fields (from, to, subject, body, etc.)\n ...baseEmailQueryFields,\n\n // Gmail-specific features\n\n // Fuzzy phrase matching - Gmail's approximate search using quoted strings\n fuzzyPhrase: z.string().min(1).optional().describe('Fuzzy phrase matching - words should appear together (approximate matching). Gmail uses relevance-based matching.'),\n\n // Gmail system categories with field operator support\n categories: z\n .union([\n z.enum(['primary', 'social', 'promotions', 'updates', 'forums']),\n z\n .object({\n $any: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $all: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $none: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n })\n .strict(),\n ])\n .optional()\n .describe('Filter by Gmail system categories (primary, social, promotions, updates, forums)'),\n\n // User-created labels\n label: z\n .union([z.string().min(1), FieldOperatorSchema])\n .optional()\n .describe('Filter by user-created labels (case-sensitive). Use gmail-labels-list to see available labels'),\n\n // Raw Gmail query string - escape hatch for advanced syntax\n rawGmailQuery: z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.'),\n })\n .strict()\n) as unknown as z.ZodType<GmailQuery>;\n\nexport type GmailQuery = BaseEmailQueryFields & {\n $and?: GmailQuery[];\n $or?: GmailQuery[];\n $not?: GmailQuery;\n fuzzyPhrase?: string;\n categories?:\n | 'primary'\n | 'social'\n | 'promotions'\n | 'updates'\n | 'forums'\n | {\n $any?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $all?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $none?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n };\n label?: string | FieldOperator;\n rawGmailQuery?: string;\n};\n"],"names":["GmailQuerySchema","z","lazy","object","$and","array","optional","describe","$or","$not","baseEmailQueryFields","fuzzyPhrase","string","min","categories","union","enum","$any","$all","$none","strict","label","FieldOperatorSchema","rawGmailQuery"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/schemas/gmail-query-schema.ts"],"sourcesContent":["import { type BaseEmailQueryFields, baseEmailQueryFields, type FieldOperator, FieldOperatorSchema } from '@mcp-z/email';\nimport { z } from 'zod';\n\n/**\n * Gmail-specific query schema with recursive operators and Gmail features.\n *\n * Includes Gmail-specific features:\n * - fuzzyPhrase: Approximate phrase matching (Gmail's quoted string behavior with relevance ranking)\n * - categories: Gmail system categories (primary, social, promotions, updates, forums)\n * - label: User-created Gmail labels (case-sensitive, discovered via gmail-labels-list)\n * - rawGmailQuery: Escape hatch for advanced Gmail query syntax\n *\n * Plus all base fields from baseEmailQueryFields:\n * - Email addresses: from, to, cc, bcc (support string or field operators)\n * - Content: subject, body, text\n * - Flags: hasAttachment, isRead\n * - Date range: date { $gte, $lt }\n * - Logical operators: $and, $or, $not (recursive)\n *\n * Note: Cast through unknown to work around Zod's lazy schema type inference issue\n * with exactOptionalPropertyTypes. The runtime schema is correct; this cast ensures\n * TypeScript sees the strict GmailQuery type everywhere the schema is used.\n */\nexport const GmailQuerySchema = z.lazy(() =>\n z\n .object({\n // Logical operators for combining conditions (recursive)\n $and: z.array(GmailQuerySchema).optional().describe('Array of conditions that must ALL match'),\n $or: z.array(GmailQuerySchema).optional().describe('Array of conditions where ANY must match'),\n $not: GmailQuerySchema.optional().describe('Nested condition that must NOT match'),\n\n // Spread base email query fields (from, to, subject, body, etc.)\n ...baseEmailQueryFields,\n\n // Gmail-specific features\n\n // Fuzzy phrase matching - Gmail's approximate search using quoted strings\n fuzzyPhrase: z.string().min(1).optional().describe('Fuzzy phrase matching - words should appear together (approximate matching). Gmail uses relevance-based matching.'),\n\n // Gmail system categories with field operator support\n categories: z\n .union([\n z.enum(['primary', 'social', 'promotions', 'updates', 'forums']),\n z\n .object({\n $any: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $all: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $none: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n })\n .strict(),\n ])\n .optional()\n .describe('Filter by Gmail system categories (primary, social, promotions, updates, forums)'),\n\n // User-created labels\n label: z\n .union([z.string().min(1), FieldOperatorSchema])\n .optional()\n .describe('Filter by user-created labels (case-sensitive). Use gmail-labels-list to see available labels'),\n\n // Raw Gmail query string - escape hatch for advanced syntax\n rawGmailQuery: z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.'),\n })\n .strict()\n) as unknown as z.ZodType<GmailQuery>;\n\nexport const GmailQueryParameterSchema = z.union([GmailQuerySchema, z.string().min(1)]) as z.ZodType<GmailQuery | string>;\nexport type GmailQueryParameter = z.infer<typeof GmailQueryParameterSchema>;\n\nexport function parseGmailQueryParameter(input: GmailQuery | string | undefined): GmailQuery | undefined {\n if (input === undefined) return undefined;\n const raw = typeof input === 'string' ? safeJsonParse(input, 'rawGmailQuery') : input;\n const validated = GmailQuerySchema.safeParse(raw);\n if (!validated.success) {\n throw new Error(`Invalid query JSON: ${validated.error.message}. Use {\"rawGmailQuery\":\"<query>\"} for Gmail syntax.`);\n }\n return validated.data;\n}\n\nfunction safeJsonParse(value: string, rawField: 'rawGmailQuery'): unknown {\n try {\n return JSON.parse(value);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid JSON';\n throw new Error(`Query must be valid JSON. ${message}. Wrap Gmail syntax in {\"${rawField}\":\"<query>\"} if needed.`);\n }\n}\n\nexport type GmailQuery = BaseEmailQueryFields & {\n $and?: GmailQuery[];\n $or?: GmailQuery[];\n $not?: GmailQuery;\n fuzzyPhrase?: string;\n categories?:\n | 'primary'\n | 'social'\n | 'promotions'\n | 'updates'\n | 'forums'\n | {\n $any?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $all?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $none?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n };\n label?: string | FieldOperator;\n rawGmailQuery?: string;\n};\n"],"names":["GmailQueryParameterSchema","GmailQuerySchema","parseGmailQueryParameter","z","lazy","object","$and","array","optional","describe","$or","$not","baseEmailQueryFields","fuzzyPhrase","string","min","categories","union","enum","$any","$all","$none","strict","label","FieldOperatorSchema","rawGmailQuery","input","undefined","raw","safeJsonParse","validated","safeParse","success","Error","error","message","data","value","rawField","JSON","parse"],"mappings":";;;;;;;;;;;QAkEaA;eAAAA;;QA3CAC;eAAAA;;QA8CGC;eAAAA;;;qBArEyF;mBACvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBX,IAAMD,mBAAmBE,MAAC,CAACC,IAAI,CAAC;WACrCD,MAAC,CACEE,MAAM,CAAC;QACN,yDAAyD;QACzDC,MAAMH,MAAC,CAACI,KAAK,CAACN,kBAAkBO,QAAQ,GAAGC,QAAQ,CAAC;QACpDC,KAAKP,MAAC,CAACI,KAAK,CAACN,kBAAkBO,QAAQ,GAAGC,QAAQ,CAAC;QACnDE,MAAMV,iBAAiBO,QAAQ,GAAGC,QAAQ,CAAC;OAGxCG,2BAAoB;QAEvB,0BAA0B;QAE1B,0EAA0E;QAC1EC,aAAaV,MAAC,CAACW,MAAM,GAAGC,GAAG,CAAC,GAAGP,QAAQ,GAAGC,QAAQ,CAAC;QAEnD,sDAAsD;QACtDO,YAAYb,MAAC,CACVc,KAAK,CAAC;YACLd,MAAC,CAACe,IAAI,CAAC;gBAAC;gBAAW;gBAAU;gBAAc;gBAAW;aAAS;YAC/Df,MAAC,CACEE,MAAM,CAAC;gBACNc,MAAMhB,MAAC,CAACI,KAAK,CAACJ,MAAC,CAACe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGV,QAAQ;gBACxFY,MAAMjB,MAAC,CAACI,KAAK,CAACJ,MAAC,CAACe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGV,QAAQ;gBACxFa,OAAOlB,MAAC,CAACI,KAAK,CAACJ,MAAC,CAACe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGV,QAAQ;YAC3F,GACCc,MAAM;SACV,EACAd,QAAQ,GACRC,QAAQ,CAAC;QAEZ,sBAAsB;QACtBc,OAAOpB,MAAC,CACLc,KAAK,CAAC;YAACd,MAAC,CAACW,MAAM,GAAGC,GAAG,CAAC;YAAIS,0BAAmB;SAAC,EAC9ChB,QAAQ,GACRC,QAAQ,CAAC;QAEZ,4DAA4D;QAC5DgB,eAAetB,MAAC,CAACW,MAAM,GAAGC,GAAG,CAAC,GAAGP,QAAQ,GAAGC,QAAQ,CAAC;QAEtDa,MAAM;;AAGJ,IAAMtB,4BAA4BG,MAAC,CAACc,KAAK,CAAC;IAAChB;IAAkBE,MAAC,CAACW,MAAM,GAAGC,GAAG,CAAC;CAAG;AAG/E,SAASb,yBAAyBwB,KAAsC;IAC7E,IAAIA,UAAUC,WAAW,OAAOA;IAChC,IAAMC,MAAM,OAAOF,UAAU,WAAWG,cAAcH,OAAO,mBAAmBA;IAChF,IAAMI,YAAY7B,iBAAiB8B,SAAS,CAACH;IAC7C,IAAI,CAACE,UAAUE,OAAO,EAAE;QACtB,MAAM,IAAIC,MAAM,AAAC,uBAA8C,OAAxBH,UAAUI,KAAK,CAACC,OAAO,EAAC;IACjE;IACA,OAAOL,UAAUM,IAAI;AACvB;AAEA,SAASP,cAAcQ,KAAa,EAAEC,QAAyB;IAC7D,IAAI;QACF,OAAOC,KAAKC,KAAK,CAACH;IACpB,EAAE,OAAOH,OAAO;QACd,IAAMC,UAAUD,AAAK,YAALA,OAAiBD,SAAQC,MAAMC,OAAO,GAAG;QACzD,MAAM,IAAIF,MAAM,AAAC,6BAA+DK,OAAnCH,SAAQ,6BAAoC,OAATG,UAAS;IAC3F;AACF"}
|
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
}
|
|
30
30
|
export function toGmailQuery(query, options = {}) {
|
|
31
31
|
const slashDates = options.dateSlash !== false;
|
|
32
|
+
if (query.rawGmailQuery) {
|
|
33
|
+
return {
|
|
34
|
+
q: query.rawGmailQuery,
|
|
35
|
+
filters: {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
32
38
|
const subjectIncludes = [];
|
|
33
39
|
const bodyIncludes = [];
|
|
34
40
|
const textIncludes = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/email/querying/query-builder.ts"],"sourcesContent":["import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.ts';\n\n/**\n * Field operator interface for query filters\n */\nexport interface FieldOperator {\n $any?: string[];\n $all?: string[];\n $none?: string[];\n}\n\n/**\n * Field query interface with support for all email fields including categories and labels\n */\nexport interface FieldQuery {\n from?: FieldOperator | string;\n to?: FieldOperator | string;\n cc?: FieldOperator | string;\n bcc?: FieldOperator | string;\n subject?: FieldOperator | string;\n text?: FieldOperator | string;\n body?: FieldOperator | string;\n categories?: FieldOperator | string;\n label?: FieldOperator | string;\n}\n\n/**\n * Filter extraction result with all collected values from a query\n */\nexport interface Filters {\n subjectIncludes?: string[];\n bodyIncludes?: string[];\n textIncludes?: string[];\n fromIncludes?: string[];\n toIncludes?: string[];\n ccIncludes?: string[];\n bccIncludes?: string[];\n categoriesIncludes?: string[];\n labelIncludes?: string[];\n hasAttachment?: boolean;\n since?: string;\n before?: string;\n}\n\n/**\n * Gmail category mappings - case insensitive input to exact system labels\n */\nconst GMAIL_CATEGORIES = {\n primary: 'CATEGORY_PERSONAL',\n social: 'CATEGORY_SOCIAL',\n promotions: 'CATEGORY_PROMOTIONS',\n updates: 'CATEGORY_UPDATES',\n forums: 'CATEGORY_FORUMS',\n} as const;\n\n/**\n * Validate and map category name to Gmail system label\n * Throws error for invalid categories (fail fast principle)\n */\nfunction mapCategoryToLabel(category: string): string {\n // Input validation - fail fast on invalid input\n if (!category || typeof category !== 'string') {\n throw new Error(`Invalid category: expected non-empty string, got ${typeof category}`);\n }\n\n const trimmed = category.trim();\n if (trimmed === '') {\n throw new Error('Invalid category: empty string after trimming');\n }\n\n // Fail fast on unknown categories\n const normalizedCategory = trimmed.toLowerCase();\n const systemLabel = GMAIL_CATEGORIES[normalizedCategory as keyof typeof GMAIL_CATEGORIES];\n\n if (!systemLabel) {\n throw new Error(`Invalid Gmail category: \"${category}\". Valid categories: ${Object.keys(GMAIL_CATEGORIES).join(', ')}`);\n }\n\n return systemLabel;\n}\n\nexport function toGmailQuery(query: QueryNode, options: { dateSlash?: boolean } = {}) {\n const slashDates = options.dateSlash !== false;\n const subjectIncludes: string[] = [];\n const bodyIncludes: string[] = [];\n const textIncludes: string[] = [];\n const fromIncludes: string[] = [];\n const toIncludes: string[] = [];\n const ccIncludes: string[] = [];\n const bccIncludes: string[] = [];\n const categoriesIncludes: string[] = [];\n const labelIncludes: string[] = [];\n let hasAttachment: boolean | undefined;\n\n function p(s: unknown) {\n return `(${String(s ?? '')})`;\n }\n function fmt(d: unknown) {\n const str = String(d ?? '');\n return slashDates ? str.replace(/-/g, '/') : str;\n }\n\n function fv(field: string, raw?: unknown) {\n const rawVal = String(raw ?? '');\n if (rawVal.trim() === '') {\n throw new Error(`Invalid ${field} value: empty string`);\n }\n const v = quote(rawVal);\n if (field === 'subject') subjectIncludes.push(rawVal);\n if (field === 'body') bodyIncludes.push(rawVal);\n if (field === 'text') {\n textIncludes.push(rawVal);\n bodyIncludes.push(rawVal);\n }\n if (field === 'from') fromIncludes.push(rawVal);\n if (field === 'to') toIncludes.push(rawVal);\n if (field === 'cc') ccIncludes.push(rawVal);\n if (field === 'bcc') bccIncludes.push(rawVal);\n if (field === 'categories') {\n const systemLabel = mapCategoryToLabel(rawVal);\n categoriesIncludes.push(rawVal);\n return `label:${systemLabel}`;\n }\n if (field === 'label') {\n // Direct passthrough to Gmail's label syntax (case-sensitive)\n labelIncludes.push(rawVal);\n return `label:${quote(rawVal)}`;\n }\n if (field === 'text' || field === 'body') return p(`subject:${v} OR ${v}`);\n return `${field}:${v}`;\n }\n\n function chain(op: 'AND' | 'OR', arr: string[]) {\n if (arr.length === 0) throw new Error(`chain: empty array for ${op} operation`);\n if (arr.length === 1) {\n const first = arr[0] ?? '';\n return first;\n }\n return p(arr.join(` ${op} `));\n }\n\n function fieldExpr(field: string, op: FieldOperator) {\n if (op.$any) {\n const results = op.$any.map((v: string) => fv(field, String(v ?? '')));\n return chain('OR', results);\n }\n if (op.$all) {\n const results = op.$all.map((v: string) => fv(field, String(v ?? '')));\n return chain('AND', results);\n }\n if (op.$none) {\n const results = op.$none.map((v: string) => fv(field, String(v ?? '')));\n return `NOT ${p(chain('OR', results))}`;\n }\n throw new Error(`Unknown field operator ${JSON.stringify(op)}`);\n }\n\n function dateExpr(d: unknown) {\n const parts: string[] = [];\n if (d && typeof d === 'object' && '$gte' in d) {\n parts.push(`after:${fmt(d.$gte)}`);\n }\n if (d && typeof d === 'object' && '$lt' in d) {\n parts.push(`before:${fmt(d.$lt)}`);\n }\n return parts.length > 1 ? p(parts.join(' AND ')) : (parts[0] ?? '');\n }\n\n function fieldKeys() {\n return ['from', 'to', 'cc', 'bcc', 'subject', 'text', 'body', 'categories', 'label'];\n }\n\n function quote(s?: unknown) {\n const str = String(s ?? '');\n return /[\\s\"()]/.test(str) ? `\"${str.replace(/[\"\\\\]/g, (m) => `\\\\${m}`)}\"` : str;\n }\n\n function emit(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return p(n.$and.map(emit).join(' AND '));\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return p(n.$or.map(emit).join(' OR '));\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n // Example: { fuzzyPhrase: \"quarterly report\" } -> \"quarterly report\"\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n\n // Handle empty objects\n const keys = Object.keys(n);\n if (keys.length === 0) return '';\n\n if (keys.length === 1) {\n const k = String(keys[0] ?? '');\n if (fieldKeys().includes(k)) {\n const op = (n as Record<string, unknown>)[k];\n // Handle string-only category queries properly (C2 fix)\n const normalizedOp: FieldOperator = typeof op === 'string' ? { $any: [op] } : (op ?? {});\n return fieldExpr(k, normalizedOp);\n }\n }\n throw new Error(`Unknown node: ${JSON.stringify(n)}`);\n }\n\n function emitTop(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n // Handle empty objects\n if (Object.keys(n).length === 0) return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return n.$and.map(emit).join(' ');\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return n.$or.map(emit).join(' OR ');\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n return emit(n);\n }\n\n const q = emitTop(query);\n const filters: Record<string, unknown> = {};\n if (subjectIncludes.length) filters.subjectIncludes = subjectIncludes;\n if (bodyIncludes.length) filters.bodyIncludes = bodyIncludes;\n if (textIncludes.length) filters.textIncludes = textIncludes;\n if (fromIncludes.length) filters.fromIncludes = fromIncludes;\n if (toIncludes.length) filters.toIncludes = toIncludes;\n if (ccIncludes.length) filters.ccIncludes = ccIncludes;\n if (bccIncludes.length) filters.bccIncludes = bccIncludes;\n if (categoriesIncludes.length) filters.categoriesIncludes = categoriesIncludes;\n if (labelIncludes.length) filters.labelIncludes = labelIncludes;\n if (typeof hasAttachment === 'boolean') filters.hasAttachment = hasAttachment;\n return { q: q ?? '', filters };\n}\n\nexport function extractFiltersFromParsed(parsed: QueryNode): Filters {\n const filters: Filters = {\n subjectIncludes: [],\n bodyIncludes: [],\n textIncludes: [],\n categoriesIncludes: [],\n labelIncludes: [],\n };\n\n function walk(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n\n if ('$and' in node && Array.isArray(node.$and)) {\n node.$and.forEach(walk);\n return;\n }\n if ('$or' in node && Array.isArray(node.$or)) {\n node.$or.forEach(walk);\n return;\n }\n if ('$not' in node) {\n walk(node.$not);\n return;\n }\n if ('hasAttachment' in node) {\n filters.hasAttachment = node.hasAttachment === true;\n return;\n }\n if ('date' in node) {\n const dateObj = node.date;\n if (dateObj && typeof dateObj === 'object') {\n if ('$gte' in dateObj) {\n filters.since = String(dateObj.$gte);\n }\n if ('$lt' in dateObj) {\n filters.before = String(dateObj.$lt);\n }\n }\n return;\n }\n\n const keys = Object.keys(node || {});\n for (const k of keys) {\n const v = (node as Record<string, unknown>)[k];\n if (!v || typeof v !== 'object') continue;\n\n if (k === 'subject') {\n if ('$any' in v && Array.isArray(v.$any)) filters.subjectIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.subjectIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.subjectIncludes?.push(...v.$none);\n } else if (k === 'body') {\n if ('$any' in v && Array.isArray(v.$any)) filters.bodyIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.bodyIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.bodyIncludes?.push(...v.$none);\n } else if (k === 'text') {\n if ('$any' in v && Array.isArray(v.$any)) filters.textIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.textIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.textIncludes?.push(...v.$none);\n } else if (k === 'categories') {\n // Validate all categories (will throw on invalid)\n if ('$any' in v && Array.isArray(v.$any)) {\n v.$any.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$any.map(String));\n }\n if ('$all' in v && Array.isArray(v.$all)) {\n v.$all.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$all.map(String));\n }\n if ('$none' in v && Array.isArray(v.$none)) {\n v.$none.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$none.map(String));\n }\n } else if (k === 'label') {\n // Direct passthrough for labels (case-sensitive)\n if ('$any' in v && Array.isArray(v.$any)) filters.labelIncludes?.push(...v.$any.map(String));\n if ('$all' in v && Array.isArray(v.$all)) filters.labelIncludes?.push(...v.$all.map(String));\n if ('$none' in v && Array.isArray(v.$none)) filters.labelIncludes?.push(...v.$none.map(String));\n }\n }\n }\n walk(parsed);\n return filters;\n}\n"],"names":["GMAIL_CATEGORIES","primary","social","promotions","updates","forums","mapCategoryToLabel","category","Error","trimmed","trim","normalizedCategory","toLowerCase","systemLabel","Object","keys","join","toGmailQuery","query","options","slashDates","dateSlash","subjectIncludes","bodyIncludes","textIncludes","fromIncludes","toIncludes","ccIncludes","bccIncludes","categoriesIncludes","labelIncludes","hasAttachment","p","s","String","fmt","d","str","replace","fv","field","raw","rawVal","v","quote","push","chain","op","arr","length","first","fieldExpr","$any","results","map","$all","$none","JSON","stringify","dateExpr","parts","$gte","$lt","fieldKeys","test","m","emit","n","Array","isArray","$and","$or","$not","fuzzyPhrase","date","k","includes","normalizedOp","emitTop","q","filters","extractFiltersFromParsed","parsed","walk","node","forEach","dateObj","since","before","cat"],"mappings":"AA4CA;;CAEC,GACD,MAAMA,mBAAmB;IACvBC,SAAS;IACTC,QAAQ;IACRC,YAAY;IACZC,SAAS;IACTC,QAAQ;AACV;AAEA;;;CAGC,GACD,SAASC,mBAAmBC,QAAgB;IAC1C,gDAAgD;IAChD,IAAI,CAACA,YAAY,OAAOA,aAAa,UAAU;QAC7C,MAAM,IAAIC,MAAM,CAAC,iDAAiD,EAAE,OAAOD,UAAU;IACvF;IAEA,MAAME,UAAUF,SAASG,IAAI;IAC7B,IAAID,YAAY,IAAI;QAClB,MAAM,IAAID,MAAM;IAClB;IAEA,kCAAkC;IAClC,MAAMG,qBAAqBF,QAAQG,WAAW;IAC9C,MAAMC,cAAcb,gBAAgB,CAACW,mBAAoD;IAEzF,IAAI,CAACE,aAAa;QAChB,MAAM,IAAIL,MAAM,CAAC,yBAAyB,EAAED,SAAS,qBAAqB,EAAEO,OAAOC,IAAI,CAACf,kBAAkBgB,IAAI,CAAC,OAAO;IACxH;IAEA,OAAOH;AACT;AAEA,OAAO,SAASI,aAAaC,KAAgB,EAAEC,UAAmC,CAAC,CAAC;IAClF,MAAMC,aAAaD,QAAQE,SAAS,KAAK;IACzC,MAAMC,kBAA4B,EAAE;IACpC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,aAAuB,EAAE;IAC/B,MAAMC,aAAuB,EAAE;IAC/B,MAAMC,cAAwB,EAAE;IAChC,MAAMC,qBAA+B,EAAE;IACvC,MAAMC,gBAA0B,EAAE;IAClC,IAAIC;IAEJ,SAASC,EAAEC,CAAU;QACnB,OAAO,CAAC,CAAC,EAAEC,OAAOD,cAAAA,eAAAA,IAAK,IAAI,CAAC,CAAC;IAC/B;IACA,SAASE,IAAIC,CAAU;QACrB,MAAMC,MAAMH,OAAOE,cAAAA,eAAAA,IAAK;QACxB,OAAOhB,aAAaiB,IAAIC,OAAO,CAAC,MAAM,OAAOD;IAC/C;IAEA,SAASE,GAAGC,KAAa,EAAEC,GAAa;QACtC,MAAMC,SAASR,OAAOO,gBAAAA,iBAAAA,MAAO;QAC7B,IAAIC,OAAOhC,IAAI,OAAO,IAAI;YACxB,MAAM,IAAIF,MAAM,CAAC,QAAQ,EAAEgC,MAAM,oBAAoB,CAAC;QACxD;QACA,MAAMG,IAAIC,MAAMF;QAChB,IAAIF,UAAU,WAAWlB,gBAAgBuB,IAAI,CAACH;QAC9C,IAAIF,UAAU,QAAQjB,aAAasB,IAAI,CAACH;QACxC,IAAIF,UAAU,QAAQ;YACpBhB,aAAaqB,IAAI,CAACH;YAClBnB,aAAasB,IAAI,CAACH;QACpB;QACA,IAAIF,UAAU,QAAQf,aAAaoB,IAAI,CAACH;QACxC,IAAIF,UAAU,MAAMd,WAAWmB,IAAI,CAACH;QACpC,IAAIF,UAAU,MAAMb,WAAWkB,IAAI,CAACH;QACpC,IAAIF,UAAU,OAAOZ,YAAYiB,IAAI,CAACH;QACtC,IAAIF,UAAU,cAAc;YAC1B,MAAM3B,cAAcP,mBAAmBoC;YACvCb,mBAAmBgB,IAAI,CAACH;YACxB,OAAO,CAAC,MAAM,EAAE7B,aAAa;QAC/B;QACA,IAAI2B,UAAU,SAAS;YACrB,8DAA8D;YAC9DV,cAAce,IAAI,CAACH;YACnB,OAAO,CAAC,MAAM,EAAEE,MAAMF,SAAS;QACjC;QACA,IAAIF,UAAU,UAAUA,UAAU,QAAQ,OAAOR,EAAE,CAAC,QAAQ,EAAEW,EAAE,IAAI,EAAEA,GAAG;QACzE,OAAO,GAAGH,MAAM,CAAC,EAAEG,GAAG;IACxB;IAEA,SAASG,MAAMC,EAAgB,EAAEC,GAAa;QAC5C,IAAIA,IAAIC,MAAM,KAAK,GAAG,MAAM,IAAIzC,MAAM,CAAC,uBAAuB,EAAEuC,GAAG,UAAU,CAAC;QAC9E,IAAIC,IAAIC,MAAM,KAAK,GAAG;gBACND;YAAd,MAAME,SAAQF,QAAAA,GAAG,CAAC,EAAE,cAANA,mBAAAA,QAAU;YACxB,OAAOE;QACT;QACA,OAAOlB,EAAEgB,IAAIhC,IAAI,CAAC,CAAC,CAAC,EAAE+B,GAAG,CAAC,CAAC;IAC7B;IAEA,SAASI,UAAUX,KAAa,EAAEO,EAAiB;QACjD,IAAIA,GAAGK,IAAI,EAAE;YACX,MAAMC,UAAUN,GAAGK,IAAI,CAACE,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YACjE,OAAOG,MAAM,MAAMO;QACrB;QACA,IAAIN,GAAGQ,IAAI,EAAE;YACX,MAAMF,UAAUN,GAAGQ,IAAI,CAACD,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YACjE,OAAOG,MAAM,OAAOO;QACtB;QACA,IAAIN,GAAGS,KAAK,EAAE;YACZ,MAAMH,UAAUN,GAAGS,KAAK,CAACF,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YAClE,OAAO,CAAC,IAAI,EAAEX,EAAEc,MAAM,MAAMO,WAAW;QACzC;QACA,MAAM,IAAI7C,MAAM,CAAC,uBAAuB,EAAEiD,KAAKC,SAAS,CAACX,KAAK;IAChE;IAEA,SAASY,SAASvB,CAAU;YAQ0BwB;QAPpD,MAAMA,QAAkB,EAAE;QAC1B,IAAIxB,KAAK,OAAOA,MAAM,YAAY,UAAUA,GAAG;YAC7CwB,MAAMf,IAAI,CAAC,CAAC,MAAM,EAAEV,IAAIC,EAAEyB,IAAI,GAAG;QACnC;QACA,IAAIzB,KAAK,OAAOA,MAAM,YAAY,SAASA,GAAG;YAC5CwB,MAAMf,IAAI,CAAC,CAAC,OAAO,EAAEV,IAAIC,EAAE0B,GAAG,GAAG;QACnC;QACA,OAAOF,MAAMX,MAAM,GAAG,IAAIjB,EAAE4B,MAAM5C,IAAI,CAAC,aAAa4C,UAAAA,KAAK,CAAC,EAAE,cAARA,qBAAAA,UAAY;IAClE;IAEA,SAASG;QACP,OAAO;YAAC;YAAQ;YAAM;YAAM;YAAO;YAAW;YAAQ;YAAQ;YAAc;SAAQ;IACtF;IAEA,SAASnB,MAAMX,CAAW;QACxB,MAAMI,MAAMH,OAAOD,cAAAA,eAAAA,IAAK;QACxB,OAAO,UAAU+B,IAAI,CAAC3B,OAAO,CAAC,CAAC,EAAEA,IAAIC,OAAO,CAAC,UAAU,CAAC2B,IAAM,CAAC,EAAE,EAAEA,GAAG,EAAE,CAAC,CAAC,GAAG5B;IAC/E;IAEA,SAAS6B,KAAKC,CAAU;QACtB,IAAI,CAACA,KAAK,OAAOA,MAAM,UAAU,OAAO;QAExC,IAAI,UAAUA,KAAKC,MAAMC,OAAO,CAACF,EAAEG,IAAI,GAAG;YACxC,OAAOtC,EAAEmC,EAAEG,IAAI,CAAChB,GAAG,CAACY,MAAMlD,IAAI,CAAC;QACjC;QACA,IAAI,SAASmD,KAAKC,MAAMC,OAAO,CAACF,EAAEI,GAAG,GAAG;YACtC,OAAOvC,EAAEmC,EAAEI,GAAG,CAACjB,GAAG,CAACY,MAAMlD,IAAI,CAAC;QAChC;QACA,IAAI,UAAUmD,GAAG;YACf,OAAO,CAAC,IAAI,EAAED,KAAKC,EAAEK,IAAI,GAAG;QAC9B;QACA,IAAI,mBAAmBL,GAAG;YACxBpC,gBAAgB;YAChB,OAAO;QACT;QACA,IAAI,iBAAiBoC,GAAG;YACtB,mDAAmD;YACnD,qEAAqE;YACrE,OAAOvB,MAAMuB,EAAEM,WAAW;QAC5B;QACA,IAAI,UAAUN,GAAG;YACf,OAAOR,SAASQ,EAAEO,IAAI;QACxB;QAEA,uBAAuB;QACvB,MAAM3D,OAAOD,OAAOC,IAAI,CAACoD;QACzB,IAAIpD,KAAKkC,MAAM,KAAK,GAAG,OAAO;QAE9B,IAAIlC,KAAKkC,MAAM,KAAK,GAAG;gBACJlC;YAAjB,MAAM4D,IAAIzC,QAAOnB,SAAAA,IAAI,CAAC,EAAE,cAAPA,oBAAAA,SAAW;YAC5B,IAAIgD,YAAYa,QAAQ,CAACD,IAAI;gBAC3B,MAAM5B,KAAK,AAACoB,CAA6B,CAACQ,EAAE;gBAC5C,wDAAwD;gBACxD,MAAME,eAA8B,OAAO9B,OAAO,WAAW;oBAAEK,MAAM;wBAACL;qBAAG;gBAAC,IAAKA,eAAAA,gBAAAA,KAAM,CAAC;gBACtF,OAAOI,UAAUwB,GAAGE;YACtB;QACF;QACA,MAAM,IAAIrE,MAAM,CAAC,cAAc,EAAEiD,KAAKC,SAAS,CAACS,IAAI;IACtD;IAEA,SAASW,QAAQX,CAAU;QACzB,IAAI,CAACA,KAAK,OAAOA,MAAM,UAAU,OAAO;QAExC,uBAAuB;QACvB,IAAIrD,OAAOC,IAAI,CAACoD,GAAGlB,MAAM,KAAK,GAAG,OAAO;QAExC,IAAI,UAAUkB,KAAKC,MAAMC,OAAO,CAACF,EAAEG,IAAI,GAAG;YACxC,OAAOH,EAAEG,IAAI,CAAChB,GAAG,CAACY,MAAMlD,IAAI,CAAC;QAC/B;QACA,IAAI,SAASmD,KAAKC,MAAMC,OAAO,CAACF,EAAEI,GAAG,GAAG;YACtC,OAAOJ,EAAEI,GAAG,CAACjB,GAAG,CAACY,MAAMlD,IAAI,CAAC;QAC9B;QACA,IAAI,UAAUmD,GAAG;YACf,OAAO,CAAC,IAAI,EAAED,KAAKC,EAAEK,IAAI,GAAG;QAC9B;QACA,IAAI,mBAAmBL,GAAG;YACxBpC,gBAAgB;YAChB,OAAO;QACT;QACA,IAAI,iBAAiBoC,GAAG;YACtB,mDAAmD;YACnD,OAAOvB,MAAMuB,EAAEM,WAAW;QAC5B;QACA,IAAI,UAAUN,GAAG;YACf,OAAOR,SAASQ,EAAEO,IAAI;QACxB;QACA,OAAOR,KAAKC;IACd;IAEA,MAAMY,IAAID,QAAQ5D;IAClB,MAAM8D,UAAmC,CAAC;IAC1C,IAAI1D,gBAAgB2B,MAAM,EAAE+B,QAAQ1D,eAAe,GAAGA;IACtD,IAAIC,aAAa0B,MAAM,EAAE+B,QAAQzD,YAAY,GAAGA;IAChD,IAAIC,aAAayB,MAAM,EAAE+B,QAAQxD,YAAY,GAAGA;IAChD,IAAIC,aAAawB,MAAM,EAAE+B,QAAQvD,YAAY,GAAGA;IAChD,IAAIC,WAAWuB,MAAM,EAAE+B,QAAQtD,UAAU,GAAGA;IAC5C,IAAIC,WAAWsB,MAAM,EAAE+B,QAAQrD,UAAU,GAAGA;IAC5C,IAAIC,YAAYqB,MAAM,EAAE+B,QAAQpD,WAAW,GAAGA;IAC9C,IAAIC,mBAAmBoB,MAAM,EAAE+B,QAAQnD,kBAAkB,GAAGA;IAC5D,IAAIC,cAAcmB,MAAM,EAAE+B,QAAQlD,aAAa,GAAGA;IAClD,IAAI,OAAOC,kBAAkB,WAAWiD,QAAQjD,aAAa,GAAGA;IAChE,OAAO;QAAEgD,CAAC,EAAEA,cAAAA,eAAAA,IAAK;QAAIC;IAAQ;AAC/B;AAEA,OAAO,SAASC,yBAAyBC,MAAiB;IACxD,MAAMF,UAAmB;QACvB1D,iBAAiB,EAAE;QACnBC,cAAc,EAAE;QAChBC,cAAc,EAAE;QAChBK,oBAAoB,EAAE;QACtBC,eAAe,EAAE;IACnB;IAEA,SAASqD,KAAKC,IAAa;QACzB,IAAI,CAACA,QAAQ,OAAOA,SAAS,UAAU;QAEvC,IAAI,UAAUA,QAAQhB,MAAMC,OAAO,CAACe,KAAKd,IAAI,GAAG;YAC9Cc,KAAKd,IAAI,CAACe,OAAO,CAACF;YAClB;QACF;QACA,IAAI,SAASC,QAAQhB,MAAMC,OAAO,CAACe,KAAKb,GAAG,GAAG;YAC5Ca,KAAKb,GAAG,CAACc,OAAO,CAACF;YACjB;QACF;QACA,IAAI,UAAUC,MAAM;YAClBD,KAAKC,KAAKZ,IAAI;YACd;QACF;QACA,IAAI,mBAAmBY,MAAM;YAC3BJ,QAAQjD,aAAa,GAAGqD,KAAKrD,aAAa,KAAK;YAC/C;QACF;QACA,IAAI,UAAUqD,MAAM;YAClB,MAAME,UAAUF,KAAKV,IAAI;YACzB,IAAIY,WAAW,OAAOA,YAAY,UAAU;gBAC1C,IAAI,UAAUA,SAAS;oBACrBN,QAAQO,KAAK,GAAGrD,OAAOoD,QAAQzB,IAAI;gBACrC;gBACA,IAAI,SAASyB,SAAS;oBACpBN,QAAQQ,MAAM,GAAGtD,OAAOoD,QAAQxB,GAAG;gBACrC;YACF;YACA;QACF;QAEA,MAAM/C,OAAOD,OAAOC,IAAI,CAACqE,QAAQ,CAAC;QAClC,KAAK,MAAMT,KAAK5D,KAAM;YACpB,MAAM4B,IAAI,AAACyC,IAAgC,CAACT,EAAE;YAC9C,IAAI,CAAChC,KAAK,OAAOA,MAAM,UAAU;YAEjC,IAAIgC,MAAM,WAAW;oBACuBK,0BACAA,2BACEA;gBAF5C,IAAI,UAAUrC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG4B,2BAAAA,QAAQ1D,eAAe,cAAvB0D,+CAAAA,yBAAyBnC,IAAI,IAAIF,EAAES,IAAI;gBACjF,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGyB,4BAAAA,QAAQ1D,eAAe,cAAvB0D,gDAAAA,0BAAyBnC,IAAI,IAAIF,EAAEY,IAAI;gBACjF,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGwB,4BAAAA,QAAQ1D,eAAe,cAAvB0D,gDAAAA,0BAAyBnC,IAAI,IAAIF,EAAEa,KAAK;YACtF,OAAO,IAAImB,MAAM,QAAQ;oBACmBK,uBACAA,wBACEA;gBAF5C,IAAI,UAAUrC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG4B,wBAAAA,QAAQzD,YAAY,cAApByD,4CAAAA,sBAAsBnC,IAAI,IAAIF,EAAES,IAAI;gBAC9E,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGyB,yBAAAA,QAAQzD,YAAY,cAApByD,6CAAAA,uBAAsBnC,IAAI,IAAIF,EAAEY,IAAI;gBAC9E,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGwB,yBAAAA,QAAQzD,YAAY,cAApByD,6CAAAA,uBAAsBnC,IAAI,IAAIF,EAAEa,KAAK;YACnF,OAAO,IAAImB,MAAM,QAAQ;oBACmBK,uBACAA,wBACEA;gBAF5C,IAAI,UAAUrC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG4B,wBAAAA,QAAQxD,YAAY,cAApBwD,4CAAAA,sBAAsBnC,IAAI,IAAIF,EAAES,IAAI;gBAC9E,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGyB,yBAAAA,QAAQxD,YAAY,cAApBwD,6CAAAA,uBAAsBnC,IAAI,IAAIF,EAAEY,IAAI;gBAC9E,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGwB,yBAAAA,QAAQxD,YAAY,cAApBwD,6CAAAA,uBAAsBnC,IAAI,IAAIF,EAAEa,KAAK;YACnF,OAAO,IAAImB,MAAM,cAAc;gBAC7B,kDAAkD;gBAClD,IAAI,UAAUhC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,GAAG;wBAIxC4B;oBAHArC,EAAES,IAAI,CAACiC,OAAO,CAAC,CAACI;wBACdnF,mBAAmB4B,OAAOuD;oBAC5B;qBACAT,8BAAAA,QAAQnD,kBAAkB,cAA1BmD,kDAAAA,4BAA4BnC,IAAI,IAAIF,EAAES,IAAI,CAACE,GAAG,CAACpB;gBACjD;gBACA,IAAI,UAAUS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,GAAG;wBAIxCyB;oBAHArC,EAAEY,IAAI,CAAC8B,OAAO,CAAC,CAACI;wBACdnF,mBAAmB4B,OAAOuD;oBAC5B;qBACAT,+BAAAA,QAAQnD,kBAAkB,cAA1BmD,mDAAAA,6BAA4BnC,IAAI,IAAIF,EAAEY,IAAI,CAACD,GAAG,CAACpB;gBACjD;gBACA,IAAI,WAAWS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,GAAG;wBAI1CwB;oBAHArC,EAAEa,KAAK,CAAC6B,OAAO,CAAC,CAACI;wBACfnF,mBAAmB4B,OAAOuD;oBAC5B;qBACAT,+BAAAA,QAAQnD,kBAAkB,cAA1BmD,mDAAAA,6BAA4BnC,IAAI,IAAIF,EAAEa,KAAK,CAACF,GAAG,CAACpB;gBAClD;YACF,OAAO,IAAIyC,MAAM,SAAS;oBAEkBK,wBACAA,yBACEA;gBAH5C,iDAAiD;gBACjD,IAAI,UAAUrC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG4B,yBAAAA,QAAQlD,aAAa,cAArBkD,6CAAAA,uBAAuBnC,IAAI,IAAIF,EAAES,IAAI,CAACE,GAAG,CAACpB;gBACpF,IAAI,UAAUS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGyB,0BAAAA,QAAQlD,aAAa,cAArBkD,8CAAAA,wBAAuBnC,IAAI,IAAIF,EAAEY,IAAI,CAACD,GAAG,CAACpB;gBACpF,IAAI,WAAWS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGwB,0BAAAA,QAAQlD,aAAa,cAArBkD,8CAAAA,wBAAuBnC,IAAI,IAAIF,EAAEa,KAAK,CAACF,GAAG,CAACpB;YACzF;QACF;IACF;IACAiD,KAAKD;IACL,OAAOF;AACT"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/email/querying/query-builder.ts"],"sourcesContent":["import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.ts';\n\n/**\n * Field operator interface for query filters\n */\nexport interface FieldOperator {\n $any?: string[];\n $all?: string[];\n $none?: string[];\n}\n\n/**\n * Field query interface with support for all email fields including categories and labels\n */\nexport interface FieldQuery {\n from?: FieldOperator | string;\n to?: FieldOperator | string;\n cc?: FieldOperator | string;\n bcc?: FieldOperator | string;\n subject?: FieldOperator | string;\n text?: FieldOperator | string;\n body?: FieldOperator | string;\n categories?: FieldOperator | string;\n label?: FieldOperator | string;\n}\n\n/**\n * Filter extraction result with all collected values from a query\n */\nexport interface Filters {\n subjectIncludes?: string[];\n bodyIncludes?: string[];\n textIncludes?: string[];\n fromIncludes?: string[];\n toIncludes?: string[];\n ccIncludes?: string[];\n bccIncludes?: string[];\n categoriesIncludes?: string[];\n labelIncludes?: string[];\n hasAttachment?: boolean;\n since?: string;\n before?: string;\n}\n\n/**\n * Gmail category mappings - case insensitive input to exact system labels\n */\nconst GMAIL_CATEGORIES = {\n primary: 'CATEGORY_PERSONAL',\n social: 'CATEGORY_SOCIAL',\n promotions: 'CATEGORY_PROMOTIONS',\n updates: 'CATEGORY_UPDATES',\n forums: 'CATEGORY_FORUMS',\n} as const;\n\n/**\n * Validate and map category name to Gmail system label\n * Throws error for invalid categories (fail fast principle)\n */\nfunction mapCategoryToLabel(category: string): string {\n // Input validation - fail fast on invalid input\n if (!category || typeof category !== 'string') {\n throw new Error(`Invalid category: expected non-empty string, got ${typeof category}`);\n }\n\n const trimmed = category.trim();\n if (trimmed === '') {\n throw new Error('Invalid category: empty string after trimming');\n }\n\n // Fail fast on unknown categories\n const normalizedCategory = trimmed.toLowerCase();\n const systemLabel = GMAIL_CATEGORIES[normalizedCategory as keyof typeof GMAIL_CATEGORIES];\n\n if (!systemLabel) {\n throw new Error(`Invalid Gmail category: \"${category}\". Valid categories: ${Object.keys(GMAIL_CATEGORIES).join(', ')}`);\n }\n\n return systemLabel;\n}\n\nexport function toGmailQuery(query: QueryNode, options: { dateSlash?: boolean } = {}) {\n const slashDates = options.dateSlash !== false;\n if (query.rawGmailQuery) {\n return { q: query.rawGmailQuery, filters: {} };\n }\n const subjectIncludes: string[] = [];\n const bodyIncludes: string[] = [];\n const textIncludes: string[] = [];\n const fromIncludes: string[] = [];\n const toIncludes: string[] = [];\n const ccIncludes: string[] = [];\n const bccIncludes: string[] = [];\n const categoriesIncludes: string[] = [];\n const labelIncludes: string[] = [];\n let hasAttachment: boolean | undefined;\n\n function p(s: unknown) {\n return `(${String(s ?? '')})`;\n }\n function fmt(d: unknown) {\n const str = String(d ?? '');\n return slashDates ? str.replace(/-/g, '/') : str;\n }\n\n function fv(field: string, raw?: unknown) {\n const rawVal = String(raw ?? '');\n if (rawVal.trim() === '') {\n throw new Error(`Invalid ${field} value: empty string`);\n }\n const v = quote(rawVal);\n if (field === 'subject') subjectIncludes.push(rawVal);\n if (field === 'body') bodyIncludes.push(rawVal);\n if (field === 'text') {\n textIncludes.push(rawVal);\n bodyIncludes.push(rawVal);\n }\n if (field === 'from') fromIncludes.push(rawVal);\n if (field === 'to') toIncludes.push(rawVal);\n if (field === 'cc') ccIncludes.push(rawVal);\n if (field === 'bcc') bccIncludes.push(rawVal);\n if (field === 'categories') {\n const systemLabel = mapCategoryToLabel(rawVal);\n categoriesIncludes.push(rawVal);\n return `label:${systemLabel}`;\n }\n if (field === 'label') {\n // Direct passthrough to Gmail's label syntax (case-sensitive)\n labelIncludes.push(rawVal);\n return `label:${quote(rawVal)}`;\n }\n if (field === 'text' || field === 'body') return p(`subject:${v} OR ${v}`);\n return `${field}:${v}`;\n }\n\n function chain(op: 'AND' | 'OR', arr: string[]) {\n if (arr.length === 0) throw new Error(`chain: empty array for ${op} operation`);\n if (arr.length === 1) {\n const first = arr[0] ?? '';\n return first;\n }\n return p(arr.join(` ${op} `));\n }\n\n function fieldExpr(field: string, op: FieldOperator) {\n if (op.$any) {\n const results = op.$any.map((v: string) => fv(field, String(v ?? '')));\n return chain('OR', results);\n }\n if (op.$all) {\n const results = op.$all.map((v: string) => fv(field, String(v ?? '')));\n return chain('AND', results);\n }\n if (op.$none) {\n const results = op.$none.map((v: string) => fv(field, String(v ?? '')));\n return `NOT ${p(chain('OR', results))}`;\n }\n throw new Error(`Unknown field operator ${JSON.stringify(op)}`);\n }\n\n function dateExpr(d: unknown) {\n const parts: string[] = [];\n if (d && typeof d === 'object' && '$gte' in d) {\n parts.push(`after:${fmt(d.$gte)}`);\n }\n if (d && typeof d === 'object' && '$lt' in d) {\n parts.push(`before:${fmt(d.$lt)}`);\n }\n return parts.length > 1 ? p(parts.join(' AND ')) : (parts[0] ?? '');\n }\n\n function fieldKeys() {\n return ['from', 'to', 'cc', 'bcc', 'subject', 'text', 'body', 'categories', 'label'];\n }\n\n function quote(s?: unknown) {\n const str = String(s ?? '');\n return /[\\s\"()]/.test(str) ? `\"${str.replace(/[\"\\\\]/g, (m) => `\\\\${m}`)}\"` : str;\n }\n\n function emit(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return p(n.$and.map(emit).join(' AND '));\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return p(n.$or.map(emit).join(' OR '));\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n // Example: { fuzzyPhrase: \"quarterly report\" } -> \"quarterly report\"\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n\n // Handle empty objects\n const keys = Object.keys(n);\n if (keys.length === 0) return '';\n\n if (keys.length === 1) {\n const k = String(keys[0] ?? '');\n if (fieldKeys().includes(k)) {\n const op = (n as Record<string, unknown>)[k];\n // Handle string-only category queries properly (C2 fix)\n const normalizedOp: FieldOperator = typeof op === 'string' ? { $any: [op] } : (op ?? {});\n return fieldExpr(k, normalizedOp);\n }\n }\n throw new Error(`Unknown node: ${JSON.stringify(n)}`);\n }\n\n function emitTop(n: unknown): string {\n if (!n || typeof n !== 'object') return '';\n\n // Handle empty objects\n if (Object.keys(n).length === 0) return '';\n\n if ('$and' in n && Array.isArray(n.$and)) {\n return n.$and.map(emit).join(' ');\n }\n if ('$or' in n && Array.isArray(n.$or)) {\n return n.$or.map(emit).join(' OR ');\n }\n if ('$not' in n) {\n return `NOT ${emit(n.$not)}`;\n }\n if ('hasAttachment' in n) {\n hasAttachment = true;\n return 'has:attachment';\n }\n if ('fuzzyPhrase' in n) {\n // Gmail fuzzy phrase matching using quoted strings\n return quote(n.fuzzyPhrase);\n }\n if ('date' in n) {\n return dateExpr(n.date);\n }\n return emit(n);\n }\n\n const q = emitTop(query);\n const filters: Record<string, unknown> = {};\n if (subjectIncludes.length) filters.subjectIncludes = subjectIncludes;\n if (bodyIncludes.length) filters.bodyIncludes = bodyIncludes;\n if (textIncludes.length) filters.textIncludes = textIncludes;\n if (fromIncludes.length) filters.fromIncludes = fromIncludes;\n if (toIncludes.length) filters.toIncludes = toIncludes;\n if (ccIncludes.length) filters.ccIncludes = ccIncludes;\n if (bccIncludes.length) filters.bccIncludes = bccIncludes;\n if (categoriesIncludes.length) filters.categoriesIncludes = categoriesIncludes;\n if (labelIncludes.length) filters.labelIncludes = labelIncludes;\n if (typeof hasAttachment === 'boolean') filters.hasAttachment = hasAttachment;\n return { q: q ?? '', filters };\n}\n\nexport function extractFiltersFromParsed(parsed: QueryNode): Filters {\n const filters: Filters = {\n subjectIncludes: [],\n bodyIncludes: [],\n textIncludes: [],\n categoriesIncludes: [],\n labelIncludes: [],\n };\n\n function walk(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n\n if ('$and' in node && Array.isArray(node.$and)) {\n node.$and.forEach(walk);\n return;\n }\n if ('$or' in node && Array.isArray(node.$or)) {\n node.$or.forEach(walk);\n return;\n }\n if ('$not' in node) {\n walk(node.$not);\n return;\n }\n if ('hasAttachment' in node) {\n filters.hasAttachment = node.hasAttachment === true;\n return;\n }\n if ('date' in node) {\n const dateObj = node.date;\n if (dateObj && typeof dateObj === 'object') {\n if ('$gte' in dateObj) {\n filters.since = String(dateObj.$gte);\n }\n if ('$lt' in dateObj) {\n filters.before = String(dateObj.$lt);\n }\n }\n return;\n }\n\n const keys = Object.keys(node || {});\n for (const k of keys) {\n const v = (node as Record<string, unknown>)[k];\n if (!v || typeof v !== 'object') continue;\n\n if (k === 'subject') {\n if ('$any' in v && Array.isArray(v.$any)) filters.subjectIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.subjectIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.subjectIncludes?.push(...v.$none);\n } else if (k === 'body') {\n if ('$any' in v && Array.isArray(v.$any)) filters.bodyIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.bodyIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.bodyIncludes?.push(...v.$none);\n } else if (k === 'text') {\n if ('$any' in v && Array.isArray(v.$any)) filters.textIncludes?.push(...v.$any);\n if ('$all' in v && Array.isArray(v.$all)) filters.textIncludes?.push(...v.$all);\n if ('$none' in v && Array.isArray(v.$none)) filters.textIncludes?.push(...v.$none);\n } else if (k === 'categories') {\n // Validate all categories (will throw on invalid)\n if ('$any' in v && Array.isArray(v.$any)) {\n v.$any.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$any.map(String));\n }\n if ('$all' in v && Array.isArray(v.$all)) {\n v.$all.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$all.map(String));\n }\n if ('$none' in v && Array.isArray(v.$none)) {\n v.$none.forEach((cat: unknown) => {\n mapCategoryToLabel(String(cat));\n });\n filters.categoriesIncludes?.push(...v.$none.map(String));\n }\n } else if (k === 'label') {\n // Direct passthrough for labels (case-sensitive)\n if ('$any' in v && Array.isArray(v.$any)) filters.labelIncludes?.push(...v.$any.map(String));\n if ('$all' in v && Array.isArray(v.$all)) filters.labelIncludes?.push(...v.$all.map(String));\n if ('$none' in v && Array.isArray(v.$none)) filters.labelIncludes?.push(...v.$none.map(String));\n }\n }\n }\n walk(parsed);\n return filters;\n}\n"],"names":["GMAIL_CATEGORIES","primary","social","promotions","updates","forums","mapCategoryToLabel","category","Error","trimmed","trim","normalizedCategory","toLowerCase","systemLabel","Object","keys","join","toGmailQuery","query","options","slashDates","dateSlash","rawGmailQuery","q","filters","subjectIncludes","bodyIncludes","textIncludes","fromIncludes","toIncludes","ccIncludes","bccIncludes","categoriesIncludes","labelIncludes","hasAttachment","p","s","String","fmt","d","str","replace","fv","field","raw","rawVal","v","quote","push","chain","op","arr","length","first","fieldExpr","$any","results","map","$all","$none","JSON","stringify","dateExpr","parts","$gte","$lt","fieldKeys","test","m","emit","n","Array","isArray","$and","$or","$not","fuzzyPhrase","date","k","includes","normalizedOp","emitTop","extractFiltersFromParsed","parsed","walk","node","forEach","dateObj","since","before","cat"],"mappings":"AA4CA;;CAEC,GACD,MAAMA,mBAAmB;IACvBC,SAAS;IACTC,QAAQ;IACRC,YAAY;IACZC,SAAS;IACTC,QAAQ;AACV;AAEA;;;CAGC,GACD,SAASC,mBAAmBC,QAAgB;IAC1C,gDAAgD;IAChD,IAAI,CAACA,YAAY,OAAOA,aAAa,UAAU;QAC7C,MAAM,IAAIC,MAAM,CAAC,iDAAiD,EAAE,OAAOD,UAAU;IACvF;IAEA,MAAME,UAAUF,SAASG,IAAI;IAC7B,IAAID,YAAY,IAAI;QAClB,MAAM,IAAID,MAAM;IAClB;IAEA,kCAAkC;IAClC,MAAMG,qBAAqBF,QAAQG,WAAW;IAC9C,MAAMC,cAAcb,gBAAgB,CAACW,mBAAoD;IAEzF,IAAI,CAACE,aAAa;QAChB,MAAM,IAAIL,MAAM,CAAC,yBAAyB,EAAED,SAAS,qBAAqB,EAAEO,OAAOC,IAAI,CAACf,kBAAkBgB,IAAI,CAAC,OAAO;IACxH;IAEA,OAAOH;AACT;AAEA,OAAO,SAASI,aAAaC,KAAgB,EAAEC,UAAmC,CAAC,CAAC;IAClF,MAAMC,aAAaD,QAAQE,SAAS,KAAK;IACzC,IAAIH,MAAMI,aAAa,EAAE;QACvB,OAAO;YAAEC,GAAGL,MAAMI,aAAa;YAAEE,SAAS,CAAC;QAAE;IAC/C;IACA,MAAMC,kBAA4B,EAAE;IACpC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,eAAyB,EAAE;IACjC,MAAMC,aAAuB,EAAE;IAC/B,MAAMC,aAAuB,EAAE;IAC/B,MAAMC,cAAwB,EAAE;IAChC,MAAMC,qBAA+B,EAAE;IACvC,MAAMC,gBAA0B,EAAE;IAClC,IAAIC;IAEJ,SAASC,EAAEC,CAAU;QACnB,OAAO,CAAC,CAAC,EAAEC,OAAOD,cAAAA,eAAAA,IAAK,IAAI,CAAC,CAAC;IAC/B;IACA,SAASE,IAAIC,CAAU;QACrB,MAAMC,MAAMH,OAAOE,cAAAA,eAAAA,IAAK;QACxB,OAAOnB,aAAaoB,IAAIC,OAAO,CAAC,MAAM,OAAOD;IAC/C;IAEA,SAASE,GAAGC,KAAa,EAAEC,GAAa;QACtC,MAAMC,SAASR,OAAOO,gBAAAA,iBAAAA,MAAO;QAC7B,IAAIC,OAAOnC,IAAI,OAAO,IAAI;YACxB,MAAM,IAAIF,MAAM,CAAC,QAAQ,EAAEmC,MAAM,oBAAoB,CAAC;QACxD;QACA,MAAMG,IAAIC,MAAMF;QAChB,IAAIF,UAAU,WAAWlB,gBAAgBuB,IAAI,CAACH;QAC9C,IAAIF,UAAU,QAAQjB,aAAasB,IAAI,CAACH;QACxC,IAAIF,UAAU,QAAQ;YACpBhB,aAAaqB,IAAI,CAACH;YAClBnB,aAAasB,IAAI,CAACH;QACpB;QACA,IAAIF,UAAU,QAAQf,aAAaoB,IAAI,CAACH;QACxC,IAAIF,UAAU,MAAMd,WAAWmB,IAAI,CAACH;QACpC,IAAIF,UAAU,MAAMb,WAAWkB,IAAI,CAACH;QACpC,IAAIF,UAAU,OAAOZ,YAAYiB,IAAI,CAACH;QACtC,IAAIF,UAAU,cAAc;YAC1B,MAAM9B,cAAcP,mBAAmBuC;YACvCb,mBAAmBgB,IAAI,CAACH;YACxB,OAAO,CAAC,MAAM,EAAEhC,aAAa;QAC/B;QACA,IAAI8B,UAAU,SAAS;YACrB,8DAA8D;YAC9DV,cAAce,IAAI,CAACH;YACnB,OAAO,CAAC,MAAM,EAAEE,MAAMF,SAAS;QACjC;QACA,IAAIF,UAAU,UAAUA,UAAU,QAAQ,OAAOR,EAAE,CAAC,QAAQ,EAAEW,EAAE,IAAI,EAAEA,GAAG;QACzE,OAAO,GAAGH,MAAM,CAAC,EAAEG,GAAG;IACxB;IAEA,SAASG,MAAMC,EAAgB,EAAEC,GAAa;QAC5C,IAAIA,IAAIC,MAAM,KAAK,GAAG,MAAM,IAAI5C,MAAM,CAAC,uBAAuB,EAAE0C,GAAG,UAAU,CAAC;QAC9E,IAAIC,IAAIC,MAAM,KAAK,GAAG;gBACND;YAAd,MAAME,SAAQF,QAAAA,GAAG,CAAC,EAAE,cAANA,mBAAAA,QAAU;YACxB,OAAOE;QACT;QACA,OAAOlB,EAAEgB,IAAInC,IAAI,CAAC,CAAC,CAAC,EAAEkC,GAAG,CAAC,CAAC;IAC7B;IAEA,SAASI,UAAUX,KAAa,EAAEO,EAAiB;QACjD,IAAIA,GAAGK,IAAI,EAAE;YACX,MAAMC,UAAUN,GAAGK,IAAI,CAACE,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YACjE,OAAOG,MAAM,MAAMO;QACrB;QACA,IAAIN,GAAGQ,IAAI,EAAE;YACX,MAAMF,UAAUN,GAAGQ,IAAI,CAACD,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YACjE,OAAOG,MAAM,OAAOO;QACtB;QACA,IAAIN,GAAGS,KAAK,EAAE;YACZ,MAAMH,UAAUN,GAAGS,KAAK,CAACF,GAAG,CAAC,CAACX,IAAcJ,GAAGC,OAAON,OAAOS,cAAAA,eAAAA,IAAK;YAClE,OAAO,CAAC,IAAI,EAAEX,EAAEc,MAAM,MAAMO,WAAW;QACzC;QACA,MAAM,IAAIhD,MAAM,CAAC,uBAAuB,EAAEoD,KAAKC,SAAS,CAACX,KAAK;IAChE;IAEA,SAASY,SAASvB,CAAU;YAQ0BwB;QAPpD,MAAMA,QAAkB,EAAE;QAC1B,IAAIxB,KAAK,OAAOA,MAAM,YAAY,UAAUA,GAAG;YAC7CwB,MAAMf,IAAI,CAAC,CAAC,MAAM,EAAEV,IAAIC,EAAEyB,IAAI,GAAG;QACnC;QACA,IAAIzB,KAAK,OAAOA,MAAM,YAAY,SAASA,GAAG;YAC5CwB,MAAMf,IAAI,CAAC,CAAC,OAAO,EAAEV,IAAIC,EAAE0B,GAAG,GAAG;QACnC;QACA,OAAOF,MAAMX,MAAM,GAAG,IAAIjB,EAAE4B,MAAM/C,IAAI,CAAC,aAAa+C,UAAAA,KAAK,CAAC,EAAE,cAARA,qBAAAA,UAAY;IAClE;IAEA,SAASG;QACP,OAAO;YAAC;YAAQ;YAAM;YAAM;YAAO;YAAW;YAAQ;YAAQ;YAAc;SAAQ;IACtF;IAEA,SAASnB,MAAMX,CAAW;QACxB,MAAMI,MAAMH,OAAOD,cAAAA,eAAAA,IAAK;QACxB,OAAO,UAAU+B,IAAI,CAAC3B,OAAO,CAAC,CAAC,EAAEA,IAAIC,OAAO,CAAC,UAAU,CAAC2B,IAAM,CAAC,EAAE,EAAEA,GAAG,EAAE,CAAC,CAAC,GAAG5B;IAC/E;IAEA,SAAS6B,KAAKC,CAAU;QACtB,IAAI,CAACA,KAAK,OAAOA,MAAM,UAAU,OAAO;QAExC,IAAI,UAAUA,KAAKC,MAAMC,OAAO,CAACF,EAAEG,IAAI,GAAG;YACxC,OAAOtC,EAAEmC,EAAEG,IAAI,CAAChB,GAAG,CAACY,MAAMrD,IAAI,CAAC;QACjC;QACA,IAAI,SAASsD,KAAKC,MAAMC,OAAO,CAACF,EAAEI,GAAG,GAAG;YACtC,OAAOvC,EAAEmC,EAAEI,GAAG,CAACjB,GAAG,CAACY,MAAMrD,IAAI,CAAC;QAChC;QACA,IAAI,UAAUsD,GAAG;YACf,OAAO,CAAC,IAAI,EAAED,KAAKC,EAAEK,IAAI,GAAG;QAC9B;QACA,IAAI,mBAAmBL,GAAG;YACxBpC,gBAAgB;YAChB,OAAO;QACT;QACA,IAAI,iBAAiBoC,GAAG;YACtB,mDAAmD;YACnD,qEAAqE;YACrE,OAAOvB,MAAMuB,EAAEM,WAAW;QAC5B;QACA,IAAI,UAAUN,GAAG;YACf,OAAOR,SAASQ,EAAEO,IAAI;QACxB;QAEA,uBAAuB;QACvB,MAAM9D,OAAOD,OAAOC,IAAI,CAACuD;QACzB,IAAIvD,KAAKqC,MAAM,KAAK,GAAG,OAAO;QAE9B,IAAIrC,KAAKqC,MAAM,KAAK,GAAG;gBACJrC;YAAjB,MAAM+D,IAAIzC,QAAOtB,SAAAA,IAAI,CAAC,EAAE,cAAPA,oBAAAA,SAAW;YAC5B,IAAImD,YAAYa,QAAQ,CAACD,IAAI;gBAC3B,MAAM5B,KAAK,AAACoB,CAA6B,CAACQ,EAAE;gBAC5C,wDAAwD;gBACxD,MAAME,eAA8B,OAAO9B,OAAO,WAAW;oBAAEK,MAAM;wBAACL;qBAAG;gBAAC,IAAKA,eAAAA,gBAAAA,KAAM,CAAC;gBACtF,OAAOI,UAAUwB,GAAGE;YACtB;QACF;QACA,MAAM,IAAIxE,MAAM,CAAC,cAAc,EAAEoD,KAAKC,SAAS,CAACS,IAAI;IACtD;IAEA,SAASW,QAAQX,CAAU;QACzB,IAAI,CAACA,KAAK,OAAOA,MAAM,UAAU,OAAO;QAExC,uBAAuB;QACvB,IAAIxD,OAAOC,IAAI,CAACuD,GAAGlB,MAAM,KAAK,GAAG,OAAO;QAExC,IAAI,UAAUkB,KAAKC,MAAMC,OAAO,CAACF,EAAEG,IAAI,GAAG;YACxC,OAAOH,EAAEG,IAAI,CAAChB,GAAG,CAACY,MAAMrD,IAAI,CAAC;QAC/B;QACA,IAAI,SAASsD,KAAKC,MAAMC,OAAO,CAACF,EAAEI,GAAG,GAAG;YACtC,OAAOJ,EAAEI,GAAG,CAACjB,GAAG,CAACY,MAAMrD,IAAI,CAAC;QAC9B;QACA,IAAI,UAAUsD,GAAG;YACf,OAAO,CAAC,IAAI,EAAED,KAAKC,EAAEK,IAAI,GAAG;QAC9B;QACA,IAAI,mBAAmBL,GAAG;YACxBpC,gBAAgB;YAChB,OAAO;QACT;QACA,IAAI,iBAAiBoC,GAAG;YACtB,mDAAmD;YACnD,OAAOvB,MAAMuB,EAAEM,WAAW;QAC5B;QACA,IAAI,UAAUN,GAAG;YACf,OAAOR,SAASQ,EAAEO,IAAI;QACxB;QACA,OAAOR,KAAKC;IACd;IAEA,MAAM/C,IAAI0D,QAAQ/D;IAClB,MAAMM,UAAmC,CAAC;IAC1C,IAAIC,gBAAgB2B,MAAM,EAAE5B,QAAQC,eAAe,GAAGA;IACtD,IAAIC,aAAa0B,MAAM,EAAE5B,QAAQE,YAAY,GAAGA;IAChD,IAAIC,aAAayB,MAAM,EAAE5B,QAAQG,YAAY,GAAGA;IAChD,IAAIC,aAAawB,MAAM,EAAE5B,QAAQI,YAAY,GAAGA;IAChD,IAAIC,WAAWuB,MAAM,EAAE5B,QAAQK,UAAU,GAAGA;IAC5C,IAAIC,WAAWsB,MAAM,EAAE5B,QAAQM,UAAU,GAAGA;IAC5C,IAAIC,YAAYqB,MAAM,EAAE5B,QAAQO,WAAW,GAAGA;IAC9C,IAAIC,mBAAmBoB,MAAM,EAAE5B,QAAQQ,kBAAkB,GAAGA;IAC5D,IAAIC,cAAcmB,MAAM,EAAE5B,QAAQS,aAAa,GAAGA;IAClD,IAAI,OAAOC,kBAAkB,WAAWV,QAAQU,aAAa,GAAGA;IAChE,OAAO;QAAEX,CAAC,EAAEA,cAAAA,eAAAA,IAAK;QAAIC;IAAQ;AAC/B;AAEA,OAAO,SAAS0D,yBAAyBC,MAAiB;IACxD,MAAM3D,UAAmB;QACvBC,iBAAiB,EAAE;QACnBC,cAAc,EAAE;QAChBC,cAAc,EAAE;QAChBK,oBAAoB,EAAE;QACtBC,eAAe,EAAE;IACnB;IAEA,SAASmD,KAAKC,IAAa;QACzB,IAAI,CAACA,QAAQ,OAAOA,SAAS,UAAU;QAEvC,IAAI,UAAUA,QAAQd,MAAMC,OAAO,CAACa,KAAKZ,IAAI,GAAG;YAC9CY,KAAKZ,IAAI,CAACa,OAAO,CAACF;YAClB;QACF;QACA,IAAI,SAASC,QAAQd,MAAMC,OAAO,CAACa,KAAKX,GAAG,GAAG;YAC5CW,KAAKX,GAAG,CAACY,OAAO,CAACF;YACjB;QACF;QACA,IAAI,UAAUC,MAAM;YAClBD,KAAKC,KAAKV,IAAI;YACd;QACF;QACA,IAAI,mBAAmBU,MAAM;YAC3B7D,QAAQU,aAAa,GAAGmD,KAAKnD,aAAa,KAAK;YAC/C;QACF;QACA,IAAI,UAAUmD,MAAM;YAClB,MAAME,UAAUF,KAAKR,IAAI;YACzB,IAAIU,WAAW,OAAOA,YAAY,UAAU;gBAC1C,IAAI,UAAUA,SAAS;oBACrB/D,QAAQgE,KAAK,GAAGnD,OAAOkD,QAAQvB,IAAI;gBACrC;gBACA,IAAI,SAASuB,SAAS;oBACpB/D,QAAQiE,MAAM,GAAGpD,OAAOkD,QAAQtB,GAAG;gBACrC;YACF;YACA;QACF;QAEA,MAAMlD,OAAOD,OAAOC,IAAI,CAACsE,QAAQ,CAAC;QAClC,KAAK,MAAMP,KAAK/D,KAAM;YACpB,MAAM+B,IAAI,AAACuC,IAAgC,CAACP,EAAE;YAC9C,IAAI,CAAChC,KAAK,OAAOA,MAAM,UAAU;YAEjC,IAAIgC,MAAM,WAAW;oBACuBtD,0BACAA,2BACEA;gBAF5C,IAAI,UAAUsB,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG/B,2BAAAA,QAAQC,eAAe,cAAvBD,+CAAAA,yBAAyBwB,IAAI,IAAIF,EAAES,IAAI;gBACjF,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGlC,4BAAAA,QAAQC,eAAe,cAAvBD,gDAAAA,0BAAyBwB,IAAI,IAAIF,EAAEY,IAAI;gBACjF,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGnC,4BAAAA,QAAQC,eAAe,cAAvBD,gDAAAA,0BAAyBwB,IAAI,IAAIF,EAAEa,KAAK;YACtF,OAAO,IAAImB,MAAM,QAAQ;oBACmBtD,uBACAA,wBACEA;gBAF5C,IAAI,UAAUsB,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG/B,wBAAAA,QAAQE,YAAY,cAApBF,4CAAAA,sBAAsBwB,IAAI,IAAIF,EAAES,IAAI;gBAC9E,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGlC,yBAAAA,QAAQE,YAAY,cAApBF,6CAAAA,uBAAsBwB,IAAI,IAAIF,EAAEY,IAAI;gBAC9E,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGnC,yBAAAA,QAAQE,YAAY,cAApBF,6CAAAA,uBAAsBwB,IAAI,IAAIF,EAAEa,KAAK;YACnF,OAAO,IAAImB,MAAM,QAAQ;oBACmBtD,uBACAA,wBACEA;gBAF5C,IAAI,UAAUsB,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG/B,wBAAAA,QAAQG,YAAY,cAApBH,4CAAAA,sBAAsBwB,IAAI,IAAIF,EAAES,IAAI;gBAC9E,IAAI,UAAUT,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGlC,yBAAAA,QAAQG,YAAY,cAApBH,6CAAAA,uBAAsBwB,IAAI,IAAIF,EAAEY,IAAI;gBAC9E,IAAI,WAAWZ,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGnC,yBAAAA,QAAQG,YAAY,cAApBH,6CAAAA,uBAAsBwB,IAAI,IAAIF,EAAEa,KAAK;YACnF,OAAO,IAAImB,MAAM,cAAc;gBAC7B,kDAAkD;gBAClD,IAAI,UAAUhC,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,GAAG;wBAIxC/B;oBAHAsB,EAAES,IAAI,CAAC+B,OAAO,CAAC,CAACI;wBACdpF,mBAAmB+B,OAAOqD;oBAC5B;qBACAlE,8BAAAA,QAAQQ,kBAAkB,cAA1BR,kDAAAA,4BAA4BwB,IAAI,IAAIF,EAAES,IAAI,CAACE,GAAG,CAACpB;gBACjD;gBACA,IAAI,UAAUS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,GAAG;wBAIxClC;oBAHAsB,EAAEY,IAAI,CAAC4B,OAAO,CAAC,CAACI;wBACdpF,mBAAmB+B,OAAOqD;oBAC5B;qBACAlE,+BAAAA,QAAQQ,kBAAkB,cAA1BR,mDAAAA,6BAA4BwB,IAAI,IAAIF,EAAEY,IAAI,CAACD,GAAG,CAACpB;gBACjD;gBACA,IAAI,WAAWS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,GAAG;wBAI1CnC;oBAHAsB,EAAEa,KAAK,CAAC2B,OAAO,CAAC,CAACI;wBACfpF,mBAAmB+B,OAAOqD;oBAC5B;qBACAlE,+BAAAA,QAAQQ,kBAAkB,cAA1BR,mDAAAA,6BAA4BwB,IAAI,IAAIF,EAAEa,KAAK,CAACF,GAAG,CAACpB;gBAClD;YACF,OAAO,IAAIyC,MAAM,SAAS;oBAEkBtD,wBACAA,yBACEA;gBAH5C,iDAAiD;gBACjD,IAAI,UAAUsB,KAAKyB,MAAMC,OAAO,CAAC1B,EAAES,IAAI,IAAG/B,yBAAAA,QAAQS,aAAa,cAArBT,6CAAAA,uBAAuBwB,IAAI,IAAIF,EAAES,IAAI,CAACE,GAAG,CAACpB;gBACpF,IAAI,UAAUS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEY,IAAI,IAAGlC,0BAAAA,QAAQS,aAAa,cAArBT,8CAAAA,wBAAuBwB,IAAI,IAAIF,EAAEY,IAAI,CAACD,GAAG,CAACpB;gBACpF,IAAI,WAAWS,KAAKyB,MAAMC,OAAO,CAAC1B,EAAEa,KAAK,IAAGnC,0BAAAA,QAAQS,aAAa,cAArBT,8CAAAA,wBAAuBwB,IAAI,IAAIF,EAAEa,KAAK,CAACF,GAAG,CAACpB;YACzF;QACF;IACF;IACA+C,KAAKD;IACL,OAAO3D;AACT"}
|
|
@@ -12,7 +12,7 @@ declare const inputSchema: z.ZodObject<{
|
|
|
12
12
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
13
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
14
14
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
15
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
15
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
16
16
|
fields: z.ZodOptional<z.ZodString>;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
declare const outputSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -125,7 +125,7 @@ export default function createTool(): {
|
|
|
125
125
|
excludeThreadHistory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
126
126
|
pageSize: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
127
127
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
128
|
-
query: z.ZodOptional<z.ZodType<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
128
|
+
query: z.ZodOptional<z.ZodType<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../schemas/gmail-query-schema.js").GmailQuery, unknown>>>;
|
|
129
129
|
fields: z.ZodOptional<z.ZodString>;
|
|
130
130
|
}, z.core.$strip>;
|
|
131
131
|
readonly outputSchema: z.ZodObject<{
|
|
@@ -8,9 +8,9 @@ import { z } from 'zod';
|
|
|
8
8
|
import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.js';
|
|
9
9
|
import { extractBodyFromPayload } from '../../email/parsing/html-processing.js';
|
|
10
10
|
import { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.js';
|
|
11
|
-
import {
|
|
11
|
+
import { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.js';
|
|
12
12
|
const inputSchema = z.object({
|
|
13
|
-
query:
|
|
13
|
+
query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),
|
|
14
14
|
fields: createFieldsSchema({
|
|
15
15
|
availableFields: EMAIL_FIELDS,
|
|
16
16
|
fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,
|
|
@@ -56,23 +56,24 @@ const config = {
|
|
|
56
56
|
};
|
|
57
57
|
async function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }, extra) {
|
|
58
58
|
const logger = extra.logger;
|
|
59
|
-
const requestedFields = parseFields(fields, EMAIL_FIELDS);
|
|
60
|
-
const includeBody = requestedFields === 'all' || requestedFields.has('body');
|
|
61
|
-
logger.info('gmail.message.search called', {
|
|
62
|
-
query,
|
|
63
|
-
pageSize,
|
|
64
|
-
pageToken: pageToken ? '[provided]' : undefined,
|
|
65
|
-
fields,
|
|
66
|
-
includeBody,
|
|
67
|
-
accountId: extra.authContext.accountId
|
|
68
|
-
});
|
|
69
59
|
try {
|
|
60
|
+
const parsedQuery = parseGmailQueryParameter(query);
|
|
61
|
+
const requestedFields = parseFields(fields, EMAIL_FIELDS);
|
|
62
|
+
const includeBody = requestedFields === 'all' || requestedFields.has('body');
|
|
63
|
+
logger.info('gmail.message.search called', {
|
|
64
|
+
query: parsedQuery,
|
|
65
|
+
pageSize,
|
|
66
|
+
pageToken: pageToken ? '[provided]' : undefined,
|
|
67
|
+
fields,
|
|
68
|
+
includeBody,
|
|
69
|
+
accountId: extra.authContext.accountId
|
|
70
|
+
});
|
|
70
71
|
const gmail = google.gmail({
|
|
71
72
|
version: 'v1',
|
|
72
73
|
auth: extra.authContext.auth
|
|
73
74
|
});
|
|
74
75
|
const started = Date.now();
|
|
75
|
-
const exec = await executeGmailQuery(
|
|
76
|
+
const exec = await executeGmailQuery(parsedQuery, {
|
|
76
77
|
client: gmail,
|
|
77
78
|
logger,
|
|
78
79
|
pageSize,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ErrorCode","McpError","EMAIL_COMMON_PATTERNS","EMAIL_FIELD_DESCRIPTIONS","EMAIL_FIELDS","EmailContentTypeSchema","EmailDetailSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","parseFields","toColumnarFormat","google","z","DEFAULT_PAGE_SIZE","MAX_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQuerySchema","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","commonPatterns","resourceName","defaultPageSize","maxPageSize","provider","shape","contentType","excludeThreadHistory","successObjectsBranchSchema","type","literal","items","array","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","pageSize","pageToken","extra","logger","requestedFields","includeBody","has","info","undefined","accountId","authContext","gmail","version","auth","started","Date","now","exec","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","bodyContentType","metadata","durationMs","filteredItems","item","resultCount","length","metadataObj","content","text","JSON","stringify","structuredContent","error","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query: parsedQuery,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ErrorCode","McpError","EMAIL_COMMON_PATTERNS","EMAIL_FIELD_DESCRIPTIONS","EMAIL_FIELDS","EmailContentTypeSchema","EmailDetailSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","parseFields","toColumnarFormat","google","z","DEFAULT_PAGE_SIZE","MAX_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQueryParameterSchema","parseGmailQueryParameter","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","commonPatterns","resourceName","defaultPageSize","maxPageSize","provider","shape","contentType","excludeThreadHistory","successObjectsBranchSchema","type","literal","items","array","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","pageSize","pageToken","extra","logger","parsedQuery","requestedFields","includeBody","has","info","undefined","accountId","authContext","gmail","version","auth","started","Date","now","exec","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","bodyContentType","metadata","durationMs","filteredItems","item","resultCount","length","metadataObj","content","text","JSON","stringify","structuredContent","error","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { EnrichedExtra } from '@mcp-z/oauth-google';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { StorageExtra } from '../../types.js';
|
|
4
4
|
declare const inputSchema: z.ZodObject<{
|
|
5
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
5
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
6
6
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
filename: z.ZodDefault<z.ZodString>;
|
|
8
8
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -55,7 +55,7 @@ export default function createTool(): {
|
|
|
55
55
|
config: {
|
|
56
56
|
readonly description: "Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.";
|
|
57
57
|
readonly inputSchema: z.ZodObject<{
|
|
58
|
-
query: z.ZodOptional<z.ZodType<import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<import("../../types.js").GmailQuery, unknown>>>;
|
|
58
|
+
query: z.ZodOptional<z.ZodType<string | import("../../types.js").GmailQuery, unknown, z.core.$ZodTypeInternals<string | import("../../types.js").GmailQuery, unknown>>>;
|
|
59
59
|
maxItems: z.ZodDefault<z.ZodNumber>;
|
|
60
60
|
filename: z.ZodDefault<z.ZodString>;
|
|
61
61
|
contentType: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -11,11 +11,11 @@ import { z } from 'zod';
|
|
|
11
11
|
import { DEFAULT_PAGE_SIZE } from '../../constants.js';
|
|
12
12
|
import { extractBodyFromPayload } from '../../email/parsing/html-processing.js';
|
|
13
13
|
import { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.js';
|
|
14
|
-
import {
|
|
14
|
+
import { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.js';
|
|
15
15
|
const DEFAULT_MAX_ITEMS = 10000;
|
|
16
16
|
const MAX_EXPORT_ITEMS = 50000;
|
|
17
17
|
const inputSchema = z.object({
|
|
18
|
-
query:
|
|
18
|
+
query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),
|
|
19
19
|
maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),
|
|
20
20
|
filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),
|
|
21
21
|
contentType: EmailContentTypeSchema,
|
|
@@ -52,12 +52,6 @@ const config = {
|
|
|
52
52
|
const logger = extra.logger;
|
|
53
53
|
const { storageContext } = extra;
|
|
54
54
|
const { transport, resourceStoreUri, baseUrl } = storageContext;
|
|
55
|
-
logger.info('gmail.messages.export-csv called', {
|
|
56
|
-
query,
|
|
57
|
-
maxItems,
|
|
58
|
-
filename,
|
|
59
|
-
accountId: extra.authContext.accountId
|
|
60
|
-
});
|
|
61
55
|
// Reserve file location for streaming write (creates directory, generates ID, formats filename)
|
|
62
56
|
const reservation = await reserveFile(filename, {
|
|
63
57
|
resourceStoreUri
|
|
@@ -68,6 +62,13 @@ const config = {
|
|
|
68
62
|
maxItems
|
|
69
63
|
});
|
|
70
64
|
try {
|
|
65
|
+
const parsedQuery = parseGmailQueryParameter(query);
|
|
66
|
+
logger.info('gmail.messages.export-csv called', {
|
|
67
|
+
query: parsedQuery,
|
|
68
|
+
maxItems,
|
|
69
|
+
filename,
|
|
70
|
+
accountId: extra.authContext.accountId
|
|
71
|
+
});
|
|
71
72
|
const gmail = google.gmail({
|
|
72
73
|
version: 'v1',
|
|
73
74
|
auth: extra.authContext.auth
|
|
@@ -109,7 +110,7 @@ const config = {
|
|
|
109
110
|
var _exec_metadata;
|
|
110
111
|
const remainingItems = maxItems - totalRows;
|
|
111
112
|
const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);
|
|
112
|
-
const exec = await executeGmailQuery(
|
|
113
|
+
const exec = await executeGmailQuery(parsedQuery, {
|
|
113
114
|
client: gmail,
|
|
114
115
|
logger,
|
|
115
116
|
pageSize,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n logger.info('gmail.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","ErrorCode","McpError","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQuerySchema","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","info","accountId","authContext","reservation","storedName","fullPath","path","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n\n logger.info('gmail.messages.export-csv called', {\n query: parsedQuery,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","ErrorCode","McpError","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQueryParameterSchema","parseGmailQueryParameter","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","info","path","parsedQuery","accountId","authContext","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
@@ -21,6 +21,9 @@ import { z } from 'zod';
|
|
|
21
21
|
* TypeScript sees the strict GmailQuery type everywhere the schema is used.
|
|
22
22
|
*/
|
|
23
23
|
export declare const GmailQuerySchema: z.ZodType<GmailQuery>;
|
|
24
|
+
export declare const GmailQueryParameterSchema: z.ZodType<GmailQuery | string>;
|
|
25
|
+
export type GmailQueryParameter = z.infer<typeof GmailQueryParameterSchema>;
|
|
26
|
+
export declare function parseGmailQueryParameter(input: GmailQuery | string | undefined): GmailQuery | undefined;
|
|
24
27
|
export type GmailQuery = BaseEmailQueryFields & {
|
|
25
28
|
$and?: GmailQuery[];
|
|
26
29
|
$or?: GmailQuery[];
|
|
@@ -70,3 +70,24 @@ import { z } from 'zod';
|
|
|
70
70
|
// Raw Gmail query string - escape hatch for advanced syntax
|
|
71
71
|
rawGmailQuery: z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.')
|
|
72
72
|
}).strict());
|
|
73
|
+
export const GmailQueryParameterSchema = z.union([
|
|
74
|
+
GmailQuerySchema,
|
|
75
|
+
z.string().min(1)
|
|
76
|
+
]);
|
|
77
|
+
export function parseGmailQueryParameter(input) {
|
|
78
|
+
if (input === undefined) return undefined;
|
|
79
|
+
const raw = typeof input === 'string' ? safeJsonParse(input, 'rawGmailQuery') : input;
|
|
80
|
+
const validated = GmailQuerySchema.safeParse(raw);
|
|
81
|
+
if (!validated.success) {
|
|
82
|
+
throw new Error(`Invalid query JSON: ${validated.error.message}. Use {"rawGmailQuery":"<query>"} for Gmail syntax.`);
|
|
83
|
+
}
|
|
84
|
+
return validated.data;
|
|
85
|
+
}
|
|
86
|
+
function safeJsonParse(value, rawField) {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(value);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : 'Invalid JSON';
|
|
91
|
+
throw new Error(`Query must be valid JSON. ${message}. Wrap Gmail syntax in {"${rawField}":"<query>"} if needed.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/schemas/gmail-query-schema.ts"],"sourcesContent":["import { type BaseEmailQueryFields, baseEmailQueryFields, type FieldOperator, FieldOperatorSchema } from '@mcp-z/email';\nimport { z } from 'zod';\n\n/**\n * Gmail-specific query schema with recursive operators and Gmail features.\n *\n * Includes Gmail-specific features:\n * - fuzzyPhrase: Approximate phrase matching (Gmail's quoted string behavior with relevance ranking)\n * - categories: Gmail system categories (primary, social, promotions, updates, forums)\n * - label: User-created Gmail labels (case-sensitive, discovered via gmail-labels-list)\n * - rawGmailQuery: Escape hatch for advanced Gmail query syntax\n *\n * Plus all base fields from baseEmailQueryFields:\n * - Email addresses: from, to, cc, bcc (support string or field operators)\n * - Content: subject, body, text\n * - Flags: hasAttachment, isRead\n * - Date range: date { $gte, $lt }\n * - Logical operators: $and, $or, $not (recursive)\n *\n * Note: Cast through unknown to work around Zod's lazy schema type inference issue\n * with exactOptionalPropertyTypes. The runtime schema is correct; this cast ensures\n * TypeScript sees the strict GmailQuery type everywhere the schema is used.\n */\nexport const GmailQuerySchema = z.lazy(() =>\n z\n .object({\n // Logical operators for combining conditions (recursive)\n $and: z.array(GmailQuerySchema).optional().describe('Array of conditions that must ALL match'),\n $or: z.array(GmailQuerySchema).optional().describe('Array of conditions where ANY must match'),\n $not: GmailQuerySchema.optional().describe('Nested condition that must NOT match'),\n\n // Spread base email query fields (from, to, subject, body, etc.)\n ...baseEmailQueryFields,\n\n // Gmail-specific features\n\n // Fuzzy phrase matching - Gmail's approximate search using quoted strings\n fuzzyPhrase: z.string().min(1).optional().describe('Fuzzy phrase matching - words should appear together (approximate matching). Gmail uses relevance-based matching.'),\n\n // Gmail system categories with field operator support\n categories: z\n .union([\n z.enum(['primary', 'social', 'promotions', 'updates', 'forums']),\n z\n .object({\n $any: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $all: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $none: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n })\n .strict(),\n ])\n .optional()\n .describe('Filter by Gmail system categories (primary, social, promotions, updates, forums)'),\n\n // User-created labels\n label: z\n .union([z.string().min(1), FieldOperatorSchema])\n .optional()\n .describe('Filter by user-created labels (case-sensitive). Use gmail-labels-list to see available labels'),\n\n // Raw Gmail query string - escape hatch for advanced syntax\n rawGmailQuery: z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.'),\n })\n .strict()\n) as unknown as z.ZodType<GmailQuery>;\n\nexport type GmailQuery = BaseEmailQueryFields & {\n $and?: GmailQuery[];\n $or?: GmailQuery[];\n $not?: GmailQuery;\n fuzzyPhrase?: string;\n categories?:\n | 'primary'\n | 'social'\n | 'promotions'\n | 'updates'\n | 'forums'\n | {\n $any?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $all?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $none?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n };\n label?: string | FieldOperator;\n rawGmailQuery?: string;\n};\n"],"names":["baseEmailQueryFields","FieldOperatorSchema","z","GmailQuerySchema","lazy","object","$and","array","optional","describe","$or","$not","fuzzyPhrase","string","min","categories","union","enum","$any","$all","$none","strict","label","rawGmailQuery"],"mappings":"AAAA,SAAoCA,oBAAoB,EAAsBC,mBAAmB,QAAQ,eAAe;AACxH,SAASC,CAAC,QAAQ,MAAM;AAExB;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,MAAMC,mBAAmBD,EAAEE,IAAI,CAAC,IACrCF,EACGG,MAAM,CAAC;QACN,yDAAyD;QACzDC,MAAMJ,EAAEK,KAAK,CAACJ,kBAAkBK,QAAQ,GAAGC,QAAQ,CAAC;QACpDC,KAAKR,EAAEK,KAAK,CAACJ,kBAAkBK,QAAQ,GAAGC,QAAQ,CAAC;QACnDE,MAAMR,iBAAiBK,QAAQ,GAAGC,QAAQ,CAAC;QAE3C,iEAAiE;QACjE,GAAGT,oBAAoB;QAEvB,0BAA0B;QAE1B,0EAA0E;QAC1EY,aAAaV,EAAEW,MAAM,GAAGC,GAAG,CAAC,GAAGN,QAAQ,GAAGC,QAAQ,CAAC;QAEnD,sDAAsD;QACtDM,YAAYb,EACTc,KAAK,CAAC;YACLd,EAAEe,IAAI,CAAC;gBAAC;gBAAW;gBAAU;gBAAc;gBAAW;aAAS;YAC/Df,EACGG,MAAM,CAAC;gBACNa,MAAMhB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;gBACxFW,MAAMjB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;gBACxFY,OAAOlB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;YAC3F,GACCa,MAAM;SACV,EACAb,QAAQ,GACRC,QAAQ,CAAC;QAEZ,sBAAsB;QACtBa,OAAOpB,EACJc,KAAK,CAAC;YAACd,EAAEW,MAAM,GAAGC,GAAG,CAAC;YAAIb;SAAoB,EAC9CO,QAAQ,GACRC,QAAQ,CAAC;QAEZ,4DAA4D;QAC5Dc,eAAerB,EAAEW,MAAM,GAAGC,GAAG,CAAC,GAAGN,QAAQ,GAAGC,QAAQ,CAAC;IACvD,GACCY,MAAM,IAC2B"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/schemas/gmail-query-schema.ts"],"sourcesContent":["import { type BaseEmailQueryFields, baseEmailQueryFields, type FieldOperator, FieldOperatorSchema } from '@mcp-z/email';\nimport { z } from 'zod';\n\n/**\n * Gmail-specific query schema with recursive operators and Gmail features.\n *\n * Includes Gmail-specific features:\n * - fuzzyPhrase: Approximate phrase matching (Gmail's quoted string behavior with relevance ranking)\n * - categories: Gmail system categories (primary, social, promotions, updates, forums)\n * - label: User-created Gmail labels (case-sensitive, discovered via gmail-labels-list)\n * - rawGmailQuery: Escape hatch for advanced Gmail query syntax\n *\n * Plus all base fields from baseEmailQueryFields:\n * - Email addresses: from, to, cc, bcc (support string or field operators)\n * - Content: subject, body, text\n * - Flags: hasAttachment, isRead\n * - Date range: date { $gte, $lt }\n * - Logical operators: $and, $or, $not (recursive)\n *\n * Note: Cast through unknown to work around Zod's lazy schema type inference issue\n * with exactOptionalPropertyTypes. The runtime schema is correct; this cast ensures\n * TypeScript sees the strict GmailQuery type everywhere the schema is used.\n */\nexport const GmailQuerySchema = z.lazy(() =>\n z\n .object({\n // Logical operators for combining conditions (recursive)\n $and: z.array(GmailQuerySchema).optional().describe('Array of conditions that must ALL match'),\n $or: z.array(GmailQuerySchema).optional().describe('Array of conditions where ANY must match'),\n $not: GmailQuerySchema.optional().describe('Nested condition that must NOT match'),\n\n // Spread base email query fields (from, to, subject, body, etc.)\n ...baseEmailQueryFields,\n\n // Gmail-specific features\n\n // Fuzzy phrase matching - Gmail's approximate search using quoted strings\n fuzzyPhrase: z.string().min(1).optional().describe('Fuzzy phrase matching - words should appear together (approximate matching). Gmail uses relevance-based matching.'),\n\n // Gmail system categories with field operator support\n categories: z\n .union([\n z.enum(['primary', 'social', 'promotions', 'updates', 'forums']),\n z\n .object({\n $any: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $all: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n $none: z.array(z.enum(['primary', 'social', 'promotions', 'updates', 'forums'])).optional(),\n })\n .strict(),\n ])\n .optional()\n .describe('Filter by Gmail system categories (primary, social, promotions, updates, forums)'),\n\n // User-created labels\n label: z\n .union([z.string().min(1), FieldOperatorSchema])\n .optional()\n .describe('Filter by user-created labels (case-sensitive). Use gmail-labels-list to see available labels'),\n\n // Raw Gmail query string - escape hatch for advanced syntax\n rawGmailQuery: z.string().min(1).optional().describe('Raw Gmail query syntax for advanced use cases. Bypasses schema validation - use sparingly.'),\n })\n .strict()\n) as unknown as z.ZodType<GmailQuery>;\n\nexport const GmailQueryParameterSchema = z.union([GmailQuerySchema, z.string().min(1)]) as z.ZodType<GmailQuery | string>;\nexport type GmailQueryParameter = z.infer<typeof GmailQueryParameterSchema>;\n\nexport function parseGmailQueryParameter(input: GmailQuery | string | undefined): GmailQuery | undefined {\n if (input === undefined) return undefined;\n const raw = typeof input === 'string' ? safeJsonParse(input, 'rawGmailQuery') : input;\n const validated = GmailQuerySchema.safeParse(raw);\n if (!validated.success) {\n throw new Error(`Invalid query JSON: ${validated.error.message}. Use {\"rawGmailQuery\":\"<query>\"} for Gmail syntax.`);\n }\n return validated.data;\n}\n\nfunction safeJsonParse(value: string, rawField: 'rawGmailQuery'): unknown {\n try {\n return JSON.parse(value);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid JSON';\n throw new Error(`Query must be valid JSON. ${message}. Wrap Gmail syntax in {\"${rawField}\":\"<query>\"} if needed.`);\n }\n}\n\nexport type GmailQuery = BaseEmailQueryFields & {\n $and?: GmailQuery[];\n $or?: GmailQuery[];\n $not?: GmailQuery;\n fuzzyPhrase?: string;\n categories?:\n | 'primary'\n | 'social'\n | 'promotions'\n | 'updates'\n | 'forums'\n | {\n $any?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $all?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n $none?: ('primary' | 'social' | 'promotions' | 'updates' | 'forums')[];\n };\n label?: string | FieldOperator;\n rawGmailQuery?: string;\n};\n"],"names":["baseEmailQueryFields","FieldOperatorSchema","z","GmailQuerySchema","lazy","object","$and","array","optional","describe","$or","$not","fuzzyPhrase","string","min","categories","union","enum","$any","$all","$none","strict","label","rawGmailQuery","GmailQueryParameterSchema","parseGmailQueryParameter","input","undefined","raw","safeJsonParse","validated","safeParse","success","Error","error","message","data","value","rawField","JSON","parse"],"mappings":"AAAA,SAAoCA,oBAAoB,EAAsBC,mBAAmB,QAAQ,eAAe;AACxH,SAASC,CAAC,QAAQ,MAAM;AAExB;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,MAAMC,mBAAmBD,EAAEE,IAAI,CAAC,IACrCF,EACGG,MAAM,CAAC;QACN,yDAAyD;QACzDC,MAAMJ,EAAEK,KAAK,CAACJ,kBAAkBK,QAAQ,GAAGC,QAAQ,CAAC;QACpDC,KAAKR,EAAEK,KAAK,CAACJ,kBAAkBK,QAAQ,GAAGC,QAAQ,CAAC;QACnDE,MAAMR,iBAAiBK,QAAQ,GAAGC,QAAQ,CAAC;QAE3C,iEAAiE;QACjE,GAAGT,oBAAoB;QAEvB,0BAA0B;QAE1B,0EAA0E;QAC1EY,aAAaV,EAAEW,MAAM,GAAGC,GAAG,CAAC,GAAGN,QAAQ,GAAGC,QAAQ,CAAC;QAEnD,sDAAsD;QACtDM,YAAYb,EACTc,KAAK,CAAC;YACLd,EAAEe,IAAI,CAAC;gBAAC;gBAAW;gBAAU;gBAAc;gBAAW;aAAS;YAC/Df,EACGG,MAAM,CAAC;gBACNa,MAAMhB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;gBACxFW,MAAMjB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;gBACxFY,OAAOlB,EAAEK,KAAK,CAACL,EAAEe,IAAI,CAAC;oBAAC;oBAAW;oBAAU;oBAAc;oBAAW;iBAAS,GAAGT,QAAQ;YAC3F,GACCa,MAAM;SACV,EACAb,QAAQ,GACRC,QAAQ,CAAC;QAEZ,sBAAsB;QACtBa,OAAOpB,EACJc,KAAK,CAAC;YAACd,EAAEW,MAAM,GAAGC,GAAG,CAAC;YAAIb;SAAoB,EAC9CO,QAAQ,GACRC,QAAQ,CAAC;QAEZ,4DAA4D;QAC5Dc,eAAerB,EAAEW,MAAM,GAAGC,GAAG,CAAC,GAAGN,QAAQ,GAAGC,QAAQ,CAAC;IACvD,GACCY,MAAM,IAC2B;AAEtC,OAAO,MAAMG,4BAA4BtB,EAAEc,KAAK,CAAC;IAACb;IAAkBD,EAAEW,MAAM,GAAGC,GAAG,CAAC;CAAG,EAAoC;AAG1H,OAAO,SAASW,yBAAyBC,KAAsC;IAC7E,IAAIA,UAAUC,WAAW,OAAOA;IAChC,MAAMC,MAAM,OAAOF,UAAU,WAAWG,cAAcH,OAAO,mBAAmBA;IAChF,MAAMI,YAAY3B,iBAAiB4B,SAAS,CAACH;IAC7C,IAAI,CAACE,UAAUE,OAAO,EAAE;QACtB,MAAM,IAAIC,MAAM,CAAC,oBAAoB,EAAEH,UAAUI,KAAK,CAACC,OAAO,CAAC,mDAAmD,CAAC;IACrH;IACA,OAAOL,UAAUM,IAAI;AACvB;AAEA,SAASP,cAAcQ,KAAa,EAAEC,QAAyB;IAC7D,IAAI;QACF,OAAOC,KAAKC,KAAK,CAACH;IACpB,EAAE,OAAOH,OAAO;QACd,MAAMC,UAAUD,iBAAiBD,QAAQC,MAAMC,OAAO,GAAG;QACzD,MAAM,IAAIF,MAAM,CAAC,0BAA0B,EAAEE,QAAQ,yBAAyB,EAAEG,SAAS,uBAAuB,CAAC;IACnH;AACF"}
|
package/package.json
CHANGED