@mcp-z/mcp-gmail 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/bin/server.js +5 -0
- package/dist/cjs/constants.d.cts +11 -0
- package/dist/cjs/constants.d.ts +11 -0
- package/dist/cjs/constants.js +39 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/email/composition/rfc822-builder.d.cts +11 -0
- package/dist/cjs/email/composition/rfc822-builder.d.ts +11 -0
- package/dist/cjs/email/composition/rfc822-builder.js +24 -0
- package/dist/cjs/email/composition/rfc822-builder.js.map +1 -0
- package/dist/cjs/email/messages/fetch-message.d.cts +24 -0
- package/dist/cjs/email/messages/fetch-message.d.ts +24 -0
- package/dist/cjs/email/messages/fetch-message.js +367 -0
- package/dist/cjs/email/messages/fetch-message.js.map +1 -0
- package/dist/cjs/email/messages/messages.d.cts +7 -0
- package/dist/cjs/email/messages/messages.d.ts +7 -0
- package/dist/cjs/email/messages/messages.js +146 -0
- package/dist/cjs/email/messages/messages.js.map +1 -0
- package/dist/cjs/email/parsing/header-parsing.d.cts +1 -0
- package/dist/cjs/email/parsing/header-parsing.d.ts +1 -0
- package/dist/cjs/email/parsing/header-parsing.js +20 -0
- package/dist/cjs/email/parsing/header-parsing.js.map +1 -0
- package/dist/cjs/email/parsing/headers-utils.d.cts +5 -0
- package/dist/cjs/email/parsing/headers-utils.d.ts +5 -0
- package/dist/cjs/email/parsing/headers-utils.js +46 -0
- package/dist/cjs/email/parsing/headers-utils.js.map +1 -0
- package/dist/cjs/email/parsing/html-processing.d.cts +8 -0
- package/dist/cjs/email/parsing/html-processing.d.ts +8 -0
- package/dist/cjs/email/parsing/html-processing.js +72 -0
- package/dist/cjs/email/parsing/html-processing.js.map +1 -0
- package/dist/cjs/email/parsing/message-extraction.d.cts +2 -0
- package/dist/cjs/email/parsing/message-extraction.d.ts +2 -0
- package/dist/cjs/email/parsing/message-extraction.js +25 -0
- package/dist/cjs/email/parsing/message-extraction.js.map +1 -0
- package/dist/cjs/email/querying/execute-query.d.cts +17 -0
- package/dist/cjs/email/querying/execute-query.d.ts +17 -0
- package/dist/cjs/email/querying/execute-query.js +265 -0
- package/dist/cjs/email/querying/execute-query.js.map +1 -0
- package/dist/cjs/email/querying/pagination.d.cts +27 -0
- package/dist/cjs/email/querying/pagination.d.ts +27 -0
- package/dist/cjs/email/querying/pagination.js +533 -0
- package/dist/cjs/email/querying/pagination.js.map +1 -0
- package/dist/cjs/email/querying/query-builder.d.cts +47 -0
- package/dist/cjs/email/querying/query-builder.d.ts +47 -0
- package/dist/cjs/email/querying/query-builder.js +387 -0
- package/dist/cjs/email/querying/query-builder.js.map +1 -0
- package/dist/cjs/email/querying/search-execution.d.cts +29 -0
- package/dist/cjs/email/querying/search-execution.d.ts +29 -0
- package/dist/cjs/email/querying/search-execution.js +190 -0
- package/dist/cjs/email/querying/search-execution.js.map +1 -0
- package/dist/cjs/index.d.cts +8 -0
- package/dist/cjs/index.d.ts +8 -0
- package/dist/cjs/index.js +314 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/labels/gmail-labels.d.cts +2 -0
- package/dist/cjs/labels/gmail-labels.d.ts +2 -0
- package/dist/cjs/labels/gmail-labels.js +206 -0
- package/dist/cjs/labels/gmail-labels.js.map +1 -0
- package/dist/cjs/lib/base64-encoding.d.cts +2 -0
- package/dist/cjs/lib/base64-encoding.d.ts +2 -0
- package/dist/cjs/lib/base64-encoding.js +32 -0
- package/dist/cjs/lib/base64-encoding.js.map +1 -0
- package/dist/cjs/lib/create-store.d.cts +2 -0
- package/dist/cjs/lib/create-store.d.ts +2 -0
- package/dist/cjs/lib/create-store.js +166 -0
- package/dist/cjs/lib/create-store.js.map +1 -0
- package/dist/cjs/lib/date-conversion.d.cts +1 -0
- package/dist/cjs/lib/date-conversion.d.ts +1 -0
- package/dist/cjs/lib/date-conversion.js +16 -0
- package/dist/cjs/lib/date-conversion.js.map +1 -0
- package/dist/cjs/lib/messages-to-row.d.cts +61 -0
- package/dist/cjs/lib/messages-to-row.d.ts +61 -0
- package/dist/cjs/lib/messages-to-row.js +243 -0
- package/dist/cjs/lib/messages-to-row.js.map +1 -0
- package/dist/cjs/mcp/index.d.cts +3 -0
- package/dist/cjs/mcp/index.d.ts +3 -0
- package/dist/cjs/mcp/index.js +66 -0
- package/dist/cjs/mcp/index.js.map +1 -0
- package/dist/cjs/mcp/prompts/draft-email.d.cts +30 -0
- package/dist/cjs/mcp/prompts/draft-email.d.ts +30 -0
- package/dist/cjs/mcp/prompts/draft-email.js +184 -0
- package/dist/cjs/mcp/prompts/draft-email.js.map +1 -0
- package/dist/cjs/mcp/prompts/index.d.cts +2 -0
- package/dist/cjs/mcp/prompts/index.d.ts +2 -0
- package/dist/cjs/mcp/prompts/index.js +26 -0
- package/dist/cjs/mcp/prompts/index.js.map +1 -0
- package/dist/cjs/mcp/prompts/query-syntax.d.cts +19 -0
- package/dist/cjs/mcp/prompts/query-syntax.d.ts +19 -0
- package/dist/cjs/mcp/prompts/query-syntax.js +169 -0
- package/dist/cjs/mcp/prompts/query-syntax.js.map +1 -0
- package/dist/cjs/mcp/resources/email.d.cts +11 -0
- package/dist/cjs/mcp/resources/email.d.ts +11 -0
- package/dist/cjs/mcp/resources/email.js +256 -0
- package/dist/cjs/mcp/resources/email.js.map +1 -0
- package/dist/cjs/mcp/resources/index.d.cts +1 -0
- package/dist/cjs/mcp/resources/index.d.ts +1 -0
- package/dist/cjs/mcp/resources/index.js +17 -0
- package/dist/cjs/mcp/resources/index.js.map +1 -0
- package/dist/cjs/mcp/tools/categories-list.d.cts +58 -0
- package/dist/cjs/mcp/tools/categories-list.d.ts +58 -0
- package/dist/cjs/mcp/tools/categories-list.js +298 -0
- package/dist/cjs/mcp/tools/categories-list.js.map +1 -0
- package/dist/cjs/mcp/tools/index.d.cts +11 -0
- package/dist/cjs/mcp/tools/index.d.ts +11 -0
- package/dist/cjs/mcp/tools/index.js +62 -0
- package/dist/cjs/mcp/tools/index.js.map +1 -0
- package/dist/cjs/mcp/tools/label-add.d.cts +61 -0
- package/dist/cjs/mcp/tools/label-add.d.ts +61 -0
- package/dist/cjs/mcp/tools/label-add.js +280 -0
- package/dist/cjs/mcp/tools/label-add.js.map +1 -0
- package/dist/cjs/mcp/tools/label-delete.d.cts +71 -0
- package/dist/cjs/mcp/tools/label-delete.d.ts +71 -0
- package/dist/cjs/mcp/tools/label-delete.js +476 -0
- package/dist/cjs/mcp/tools/label-delete.js.map +1 -0
- package/dist/cjs/mcp/tools/labels-list.d.cts +75 -0
- package/dist/cjs/mcp/tools/labels-list.d.ts +75 -0
- package/dist/cjs/mcp/tools/labels-list.js +298 -0
- package/dist/cjs/mcp/tools/labels-list.js.map +1 -0
- package/dist/cjs/mcp/tools/message-get.d.cts +146 -0
- package/dist/cjs/mcp/tools/message-get.d.ts +146 -0
- package/dist/cjs/mcp/tools/message-get.js +317 -0
- package/dist/cjs/mcp/tools/message-get.js.map +1 -0
- package/dist/cjs/mcp/tools/message-mark-read.d.cts +50 -0
- package/dist/cjs/mcp/tools/message-mark-read.d.ts +50 -0
- package/dist/cjs/mcp/tools/message-mark-read.js +254 -0
- package/dist/cjs/mcp/tools/message-mark-read.js.map +1 -0
- package/dist/cjs/mcp/tools/message-move-to-trash.d.cts +71 -0
- package/dist/cjs/mcp/tools/message-move-to-trash.d.ts +71 -0
- package/dist/cjs/mcp/tools/message-move-to-trash.js +450 -0
- package/dist/cjs/mcp/tools/message-move-to-trash.js.map +1 -0
- package/dist/cjs/mcp/tools/message-respond.d.cts +60 -0
- package/dist/cjs/mcp/tools/message-respond.d.ts +60 -0
- package/dist/cjs/mcp/tools/message-respond.js +367 -0
- package/dist/cjs/mcp/tools/message-respond.js.map +1 -0
- package/dist/cjs/mcp/tools/message-search.d.cts +182 -0
- package/dist/cjs/mcp/tools/message-search.d.ts +182 -0
- package/dist/cjs/mcp/tools/message-search.js +405 -0
- package/dist/cjs/mcp/tools/message-search.js.map +1 -0
- package/dist/cjs/mcp/tools/message-send.d.cts +87 -0
- package/dist/cjs/mcp/tools/message-send.d.ts +87 -0
- package/dist/cjs/mcp/tools/message-send.js +288 -0
- package/dist/cjs/mcp/tools/message-send.js.map +1 -0
- package/dist/cjs/mcp/tools/messages-export-csv.d.cts +84 -0
- package/dist/cjs/mcp/tools/messages-export-csv.d.ts +84 -0
- package/dist/cjs/mcp/tools/messages-export-csv.js +530 -0
- package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/schemas/gmail-query-schema.d.cts +36 -0
- package/dist/cjs/schemas/gmail-query-schema.d.ts +36 -0
- package/dist/cjs/schemas/gmail-query-schema.js +117 -0
- package/dist/cjs/schemas/gmail-query-schema.js.map +1 -0
- package/dist/cjs/schemas/index.d.cts +1 -0
- package/dist/cjs/schemas/index.d.ts +1 -0
- package/dist/cjs/schemas/index.js +19 -0
- package/dist/cjs/schemas/index.js.map +1 -0
- package/dist/cjs/setup/config.d.cts +48 -0
- package/dist/cjs/setup/config.d.ts +48 -0
- package/dist/cjs/setup/config.js +217 -0
- package/dist/cjs/setup/config.js.map +1 -0
- package/dist/cjs/setup/http.d.cts +8 -0
- package/dist/cjs/setup/http.d.ts +8 -0
- package/dist/cjs/setup/http.js +267 -0
- package/dist/cjs/setup/http.js.map +1 -0
- package/dist/cjs/setup/index.d.cts +5 -0
- package/dist/cjs/setup/index.d.ts +5 -0
- package/dist/cjs/setup/index.js +46 -0
- package/dist/cjs/setup/index.js.map +1 -0
- package/dist/cjs/setup/oauth-google.d.cts +54 -0
- package/dist/cjs/setup/oauth-google.d.ts +54 -0
- package/dist/cjs/setup/oauth-google.js +332 -0
- package/dist/cjs/setup/oauth-google.js.map +1 -0
- package/dist/cjs/setup/runtime.d.cts +12 -0
- package/dist/cjs/setup/runtime.d.ts +12 -0
- package/dist/cjs/setup/runtime.js +489 -0
- package/dist/cjs/setup/runtime.js.map +1 -0
- package/dist/cjs/setup/stdio.d.cts +7 -0
- package/dist/cjs/setup/stdio.d.ts +7 -0
- package/dist/cjs/setup/stdio.js +239 -0
- package/dist/cjs/setup/stdio.js.map +1 -0
- package/dist/cjs/types.d.cts +54 -0
- package/dist/cjs/types.d.ts +54 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/constants.d.ts +11 -0
- package/dist/esm/constants.js +14 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/email/composition/rfc822-builder.d.ts +11 -0
- package/dist/esm/email/composition/rfc822-builder.js +13 -0
- package/dist/esm/email/composition/rfc822-builder.js.map +1 -0
- package/dist/esm/email/messages/fetch-message.d.ts +24 -0
- package/dist/esm/email/messages/fetch-message.js +123 -0
- package/dist/esm/email/messages/fetch-message.js.map +1 -0
- package/dist/esm/email/messages/messages.d.ts +7 -0
- package/dist/esm/email/messages/messages.js +91 -0
- package/dist/esm/email/messages/messages.js.map +1 -0
- package/dist/esm/email/parsing/header-parsing.d.ts +1 -0
- package/dist/esm/email/parsing/header-parsing.js +1 -0
- package/dist/esm/email/parsing/header-parsing.js.map +1 -0
- package/dist/esm/email/parsing/headers-utils.d.ts +5 -0
- package/dist/esm/email/parsing/headers-utils.js +25 -0
- package/dist/esm/email/parsing/headers-utils.js.map +1 -0
- package/dist/esm/email/parsing/html-processing.d.ts +8 -0
- package/dist/esm/email/parsing/html-processing.js +39 -0
- package/dist/esm/email/parsing/html-processing.js.map +1 -0
- package/dist/esm/email/parsing/message-extraction.d.ts +2 -0
- package/dist/esm/email/parsing/message-extraction.js +3 -0
- package/dist/esm/email/parsing/message-extraction.js.map +1 -0
- package/dist/esm/email/querying/execute-query.d.ts +17 -0
- package/dist/esm/email/querying/execute-query.js +45 -0
- package/dist/esm/email/querying/execute-query.js.map +1 -0
- package/dist/esm/email/querying/pagination.d.ts +27 -0
- package/dist/esm/email/querying/pagination.js +152 -0
- package/dist/esm/email/querying/pagination.js.map +1 -0
- package/dist/esm/email/querying/query-builder.d.ts +47 -0
- package/dist/esm/email/querying/query-builder.js +306 -0
- package/dist/esm/email/querying/query-builder.js.map +1 -0
- package/dist/esm/email/querying/search-execution.d.ts +29 -0
- package/dist/esm/email/querying/search-execution.js +35 -0
- package/dist/esm/email/querying/search-execution.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.js +34 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/labels/gmail-labels.d.ts +2 -0
- package/dist/esm/labels/gmail-labels.js +43 -0
- package/dist/esm/labels/gmail-labels.js.map +1 -0
- package/dist/esm/lib/base64-encoding.d.ts +2 -0
- package/dist/esm/lib/base64-encoding.js +13 -0
- package/dist/esm/lib/base64-encoding.js.map +1 -0
- package/dist/esm/lib/create-store.d.ts +2 -0
- package/dist/esm/lib/create-store.js +6 -0
- package/dist/esm/lib/create-store.js.map +1 -0
- package/dist/esm/lib/date-conversion.d.ts +1 -0
- package/dist/esm/lib/date-conversion.js +5 -0
- package/dist/esm/lib/date-conversion.js.map +1 -0
- package/dist/esm/lib/messages-to-row.d.ts +61 -0
- package/dist/esm/lib/messages-to-row.js +188 -0
- package/dist/esm/lib/messages-to-row.js.map +1 -0
- package/dist/esm/mcp/index.d.ts +3 -0
- package/dist/esm/mcp/index.js +6 -0
- package/dist/esm/mcp/index.js.map +1 -0
- package/dist/esm/mcp/prompts/draft-email.d.ts +30 -0
- package/dist/esm/mcp/prompts/draft-email.js +37 -0
- package/dist/esm/mcp/prompts/draft-email.js.map +1 -0
- package/dist/esm/mcp/prompts/index.d.ts +2 -0
- package/dist/esm/mcp/prompts/index.js +2 -0
- package/dist/esm/mcp/prompts/index.js.map +1 -0
- package/dist/esm/mcp/prompts/query-syntax.d.ts +19 -0
- package/dist/esm/mcp/prompts/query-syntax.js +74 -0
- package/dist/esm/mcp/prompts/query-syntax.js.map +1 -0
- package/dist/esm/mcp/resources/email.d.ts +11 -0
- package/dist/esm/mcp/resources/email.js +92 -0
- package/dist/esm/mcp/resources/email.js.map +1 -0
- package/dist/esm/mcp/resources/index.d.ts +1 -0
- package/dist/esm/mcp/resources/index.js +1 -0
- package/dist/esm/mcp/resources/index.js.map +1 -0
- package/dist/esm/mcp/tools/categories-list.d.ts +58 -0
- package/dist/esm/mcp/tools/categories-list.js +124 -0
- package/dist/esm/mcp/tools/categories-list.js.map +1 -0
- package/dist/esm/mcp/tools/index.d.ts +11 -0
- package/dist/esm/mcp/tools/index.js +11 -0
- package/dist/esm/mcp/tools/index.js.map +1 -0
- package/dist/esm/mcp/tools/label-add.d.ts +61 -0
- package/dist/esm/mcp/tools/label-add.js +101 -0
- package/dist/esm/mcp/tools/label-add.js.map +1 -0
- package/dist/esm/mcp/tools/label-delete.d.ts +71 -0
- package/dist/esm/mcp/tools/label-delete.js +186 -0
- package/dist/esm/mcp/tools/label-delete.js.map +1 -0
- package/dist/esm/mcp/tools/labels-list.d.ts +75 -0
- package/dist/esm/mcp/tools/labels-list.js +122 -0
- package/dist/esm/mcp/tools/labels-list.js.map +1 -0
- package/dist/esm/mcp/tools/message-get.d.ts +146 -0
- package/dist/esm/mcp/tools/message-get.js +145 -0
- package/dist/esm/mcp/tools/message-get.js.map +1 -0
- package/dist/esm/mcp/tools/message-mark-read.d.ts +50 -0
- package/dist/esm/mcp/tools/message-mark-read.js +80 -0
- package/dist/esm/mcp/tools/message-mark-read.js.map +1 -0
- package/dist/esm/mcp/tools/message-move-to-trash.d.ts +71 -0
- package/dist/esm/mcp/tools/message-move-to-trash.js +167 -0
- package/dist/esm/mcp/tools/message-move-to-trash.js.map +1 -0
- package/dist/esm/mcp/tools/message-respond.d.ts +60 -0
- package/dist/esm/mcp/tools/message-respond.js +152 -0
- package/dist/esm/mcp/tools/message-respond.js.map +1 -0
- package/dist/esm/mcp/tools/message-search.d.ts +182 -0
- package/dist/esm/mcp/tools/message-search.js +180 -0
- package/dist/esm/mcp/tools/message-search.js.map +1 -0
- package/dist/esm/mcp/tools/message-send.d.ts +87 -0
- package/dist/esm/mcp/tools/message-send.js +115 -0
- package/dist/esm/mcp/tools/message-send.js.map +1 -0
- package/dist/esm/mcp/tools/messages-export-csv.d.ts +84 -0
- package/dist/esm/mcp/tools/messages-export-csv.js +261 -0
- package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/schemas/gmail-query-schema.d.ts +36 -0
- package/dist/esm/schemas/gmail-query-schema.js +72 -0
- package/dist/esm/schemas/gmail-query-schema.js.map +1 -0
- package/dist/esm/schemas/index.d.ts +1 -0
- package/dist/esm/schemas/index.js +1 -0
- package/dist/esm/schemas/index.js.map +1 -0
- package/dist/esm/setup/config.d.ts +48 -0
- package/dist/esm/setup/config.js +175 -0
- package/dist/esm/setup/config.js.map +1 -0
- package/dist/esm/setup/http.d.ts +8 -0
- package/dist/esm/setup/http.js +61 -0
- package/dist/esm/setup/http.js.map +1 -0
- package/dist/esm/setup/index.d.ts +5 -0
- package/dist/esm/setup/index.js +5 -0
- package/dist/esm/setup/index.js.map +1 -0
- package/dist/esm/setup/oauth-google.d.ts +54 -0
- package/dist/esm/setup/oauth-google.js +142 -0
- package/dist/esm/setup/oauth-google.js.map +1 -0
- package/dist/esm/setup/runtime.d.ts +12 -0
- package/dist/esm/setup/runtime.js +115 -0
- package/dist/esm/setup/runtime.js.map +1 -0
- package/dist/esm/setup/stdio.d.ts +7 -0
- package/dist/esm/setup/stdio.js +38 -0
- package/dist/esm/setup/stdio.js.map +1 -0
- package/dist/esm/types.d.ts +54 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { buildContentForItems } from '@mcp-z/email';
|
|
2
|
+
import { safeBase64Decode } from '../../lib/base64-encoding.js';
|
|
3
|
+
import { toIsoUtc } from '../../lib/date-conversion.js';
|
|
4
|
+
import { extractEmails, extractFrom } from '../parsing/headers-utils.js';
|
|
5
|
+
export { buildContentForItems };
|
|
6
|
+
// Convert a Gmail messages.get() response into canonical row shape used by sheets writer
|
|
7
|
+
// [id, provider, threadId, to, from, cc, bcc, date, subject, labels, snippet, body]
|
|
8
|
+
export function toRowFromGmail(msg = {}, opts = {
|
|
9
|
+
body: false,
|
|
10
|
+
addressFormat: 'email'
|
|
11
|
+
}) {
|
|
12
|
+
var _ref, _ref1, _headerObj_To, _headerObj_From, _ref2, _headerObj_Cc, _headerObj_Bcc, _ref3, _headerObj_Subject, _ref4;
|
|
13
|
+
var _msg_payload;
|
|
14
|
+
const headers = (msg === null || msg === void 0 ? void 0 : (_msg_payload = msg.payload) === null || _msg_payload === void 0 ? void 0 : _msg_payload.headers) || [];
|
|
15
|
+
const headerObj = Object.fromEntries((headers || []).map((h)=>{
|
|
16
|
+
var _ref, _ref1;
|
|
17
|
+
return [
|
|
18
|
+
String((_ref = h === null || h === void 0 ? void 0 : h.name) !== null && _ref !== void 0 ? _ref : ''),
|
|
19
|
+
String((_ref1 = h === null || h === void 0 ? void 0 : h.value) !== null && _ref1 !== void 0 ? _ref1 : '')
|
|
20
|
+
];
|
|
21
|
+
}));
|
|
22
|
+
const id = (_ref = msg === null || msg === void 0 ? void 0 : msg.id) !== null && _ref !== void 0 ? _ref : '';
|
|
23
|
+
const provider = 'gmail';
|
|
24
|
+
const threadId = (_ref1 = msg === null || msg === void 0 ? void 0 : msg.threadId) !== null && _ref1 !== void 0 ? _ref1 : '';
|
|
25
|
+
const to = extractEmails((_headerObj_To = headerObj.To) !== null && _headerObj_To !== void 0 ? _headerObj_To : '').join(', ');
|
|
26
|
+
const fromInfo = extractFrom((_headerObj_From = headerObj.From) !== null && _headerObj_From !== void 0 ? _headerObj_From : '');
|
|
27
|
+
const from = (_ref2 = fromInfo && fromInfo.address || headerObj.From) !== null && _ref2 !== void 0 ? _ref2 : '';
|
|
28
|
+
const cc = extractEmails((_headerObj_Cc = headerObj.Cc) !== null && _headerObj_Cc !== void 0 ? _headerObj_Cc : '').join(', ');
|
|
29
|
+
const bcc = extractEmails((_headerObj_Bcc = headerObj.Bcc) !== null && _headerObj_Bcc !== void 0 ? _headerObj_Bcc : '').join(', ');
|
|
30
|
+
const date = (_ref3 = toIsoUtc(headerObj.Date) || headerObj.Date) !== null && _ref3 !== void 0 ? _ref3 : '';
|
|
31
|
+
const subject = (_headerObj_Subject = headerObj.Subject) !== null && _headerObj_Subject !== void 0 ? _headerObj_Subject : '';
|
|
32
|
+
const labelIds = Array.isArray(msg === null || msg === void 0 ? void 0 : msg.labelIds) ? msg.labelIds : [];
|
|
33
|
+
const labels = labelIds.join(';');
|
|
34
|
+
const snippet = (_ref4 = msg === null || msg === void 0 ? void 0 : msg.snippet) !== null && _ref4 !== void 0 ? _ref4 : '';
|
|
35
|
+
let bodyFull = '';
|
|
36
|
+
if (opts === null || opts === void 0 ? void 0 : opts.body) {
|
|
37
|
+
var _msg_payload1, _msg_payload2;
|
|
38
|
+
const parts = (msg === null || msg === void 0 ? void 0 : (_msg_payload1 = msg.payload) === null || _msg_payload1 === void 0 ? void 0 : _msg_payload1.parts) || [];
|
|
39
|
+
const findText = (partsArr)=>{
|
|
40
|
+
for (const p of partsArr || []){
|
|
41
|
+
if (p && typeof p === 'object' && 'mimeType' in p && 'body' in p) {
|
|
42
|
+
if (p.mimeType === 'text/plain' && p.body && typeof p.body === 'object' && 'data' in p.body) {
|
|
43
|
+
return p.body.data;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (p && typeof p === 'object' && 'parts' in p) {
|
|
47
|
+
const nested = findText(p.parts);
|
|
48
|
+
if (nested) return nested;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
};
|
|
53
|
+
const raw = findText(parts) || ((msg === null || msg === void 0 ? void 0 : (_msg_payload2 = msg.payload) === null || _msg_payload2 === void 0 ? void 0 : _msg_payload2.body) && typeof msg.payload.body === 'object' && 'data' in msg.payload.body ? msg.payload.body.data : null) || null;
|
|
54
|
+
if (raw) {
|
|
55
|
+
bodyFull = safeBase64Decode(raw);
|
|
56
|
+
} else {
|
|
57
|
+
const findHtml = (partsArr)=>{
|
|
58
|
+
for (const p of partsArr || []){
|
|
59
|
+
if (p && typeof p === 'object' && 'mimeType' in p && 'body' in p) {
|
|
60
|
+
if (p.mimeType === 'text/html' && p.body && typeof p.body === 'object' && 'data' in p.body) {
|
|
61
|
+
return p.body.data;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (p && typeof p === 'object' && 'parts' in p) {
|
|
65
|
+
const nested = findHtml(p.parts);
|
|
66
|
+
if (nested) return nested;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
const htmlPart = findHtml(parts);
|
|
72
|
+
if (htmlPart) {
|
|
73
|
+
bodyFull = safeBase64Decode(htmlPart).replace(/\r\n?/g, '\n');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return [
|
|
78
|
+
id,
|
|
79
|
+
provider,
|
|
80
|
+
threadId,
|
|
81
|
+
to,
|
|
82
|
+
from,
|
|
83
|
+
cc,
|
|
84
|
+
bcc,
|
|
85
|
+
date,
|
|
86
|
+
subject,
|
|
87
|
+
labels,
|
|
88
|
+
snippet,
|
|
89
|
+
bodyFull
|
|
90
|
+
];
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/messages/messages.ts"],"sourcesContent":["import { buildContentForItems } from '@mcp-z/email';\nimport type { gmail_v1 } from 'googleapis';\nimport { safeBase64Decode } from '../../lib/base64-encoding.js';\nimport { toIsoUtc } from '../../lib/date-conversion.js';\nimport { extractEmails, extractFrom } from '../parsing/headers-utils.js';\n\nexport { buildContentForItems };\n\n// Convert a Gmail messages.get() response into canonical row shape used by sheets writer\n// [id, provider, threadId, to, from, cc, bcc, date, subject, labels, snippet, body]\nexport function toRowFromGmail(msg: gmail_v1.Schema$Message = {}, opts: { body?: boolean; addressFormat?: 'email' | string } = { body: false, addressFormat: 'email' }) {\n const headers = msg?.payload?.headers || [];\n const headerObj: Record<string, string> = Object.fromEntries((headers || []).map((h) => [String(h?.name ?? ''), String(h?.value ?? '')]));\n const id = msg?.id ?? '';\n const provider = 'gmail';\n const threadId = msg?.threadId ?? '';\n const to = extractEmails(headerObj.To ?? '').join(', ');\n const fromInfo = extractFrom(headerObj.From ?? '');\n const from = ((fromInfo && fromInfo.address) || headerObj.From) ?? '';\n const cc = extractEmails(headerObj.Cc ?? '').join(', ');\n const bcc = extractEmails(headerObj.Bcc ?? '').join(', ');\n const date = (toIsoUtc(headerObj.Date) || headerObj.Date) ?? '';\n const subject = headerObj.Subject ?? '';\n const labelIds = Array.isArray(msg?.labelIds) ? (msg.labelIds as string[]) : [];\n const labels = labelIds.join(';');\n const snippet = msg?.snippet ?? '';\n\n let bodyFull = '';\n if (opts?.body) {\n const parts = msg?.payload?.parts || [];\n const findText = (partsArr: unknown[]): string | null => {\n for (const p of partsArr || []) {\n if (p && typeof p === 'object' && 'mimeType' in p && 'body' in p) {\n if (p.mimeType === 'text/plain' && p.body && typeof p.body === 'object' && 'data' in p.body) {\n return p.body.data as string;\n }\n }\n if (p && typeof p === 'object' && 'parts' in p) {\n const nested = findText(p.parts as unknown[]);\n if (nested) return nested;\n }\n }\n return null;\n };\n const raw = findText(parts as unknown[]) || (msg?.payload?.body && typeof msg.payload.body === 'object' && 'data' in msg.payload.body ? msg.payload.body.data : null) || null;\n if (raw) {\n bodyFull = safeBase64Decode(raw as string);\n } else {\n const findHtml = (partsArr: unknown[]): string | null => {\n for (const p of partsArr || []) {\n if (p && typeof p === 'object' && 'mimeType' in p && 'body' in p) {\n if (p.mimeType === 'text/html' && p.body && typeof p.body === 'object' && 'data' in p.body) {\n return p.body.data as string;\n }\n }\n if (p && typeof p === 'object' && 'parts' in p) {\n const nested = findHtml(p.parts as unknown[]);\n if (nested) return nested;\n }\n }\n return null;\n };\n const htmlPart = findHtml(parts as unknown[]);\n if (htmlPart) {\n bodyFull = safeBase64Decode(htmlPart).replace(/\\r\\n?/g, '\\n');\n }\n }\n }\n return [id, provider, threadId, to, from, cc, bcc, date, subject, labels, snippet, bodyFull];\n}\n"],"names":["buildContentForItems","safeBase64Decode","toIsoUtc","extractEmails","extractFrom","toRowFromGmail","msg","opts","body","addressFormat","headerObj","headers","payload","Object","fromEntries","map","h","String","name","value","id","provider","threadId","to","To","join","fromInfo","From","from","address","cc","Cc","bcc","Bcc","date","Date","subject","Subject","labelIds","Array","isArray","labels","snippet","bodyFull","parts","findText","partsArr","p","mimeType","data","nested","raw","findHtml","htmlPart","replace"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { extractEmails, extractFrom } from './headers-utils.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { extractEmails, extractFrom } from './headers-utils.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/parsing/header-parsing.ts"],"sourcesContent":["export { extractEmails, extractFrom } from './headers-utils.js';\n"],"names":["extractEmails","extractFrom"],"mappings":"AAAA,SAASA,aAAa,EAAEC,WAAW,QAAQ,qBAAqB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function extractEmails(header) {
|
|
2
|
+
if (!header) return [];
|
|
3
|
+
const matches = header.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi) || [];
|
|
4
|
+
return matches.map((s)=>s.trim());
|
|
5
|
+
}
|
|
6
|
+
export function extractFrom(header) {
|
|
7
|
+
if (!header) return undefined;
|
|
8
|
+
const m = header.match(/^(.*)<([^>]+)>/);
|
|
9
|
+
if (m) {
|
|
10
|
+
const rawName = m[1];
|
|
11
|
+
const name = rawName ? rawName.replace(/"/g, '').trim() : undefined;
|
|
12
|
+
const addr = m[2] ? m[2].trim() : undefined;
|
|
13
|
+
const result = {};
|
|
14
|
+
if (addr) result.address = addr;
|
|
15
|
+
if (name) result.name = name;
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
const emails = extractEmails(header);
|
|
19
|
+
if (emails[0]) return {
|
|
20
|
+
address: emails[0]
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
address: header.trim()
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/parsing/headers-utils.ts"],"sourcesContent":["export function extractEmails(header?: string): string[] {\n if (!header) return [];\n const matches = header.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/gi) || [];\n return matches.map((s: string) => s.trim());\n}\n\nexport function extractFrom(header?: string): { address?: string; name?: string } | undefined {\n if (!header) return undefined;\n const m = header.match(/^(.*)<([^>]+)>/);\n if (m) {\n const rawName = m[1];\n const name = rawName ? rawName.replace(/\"/g, '').trim() : undefined;\n const addr = m[2] ? m[2].trim() : undefined;\n const result: { address?: string; name?: string } = {};\n if (addr) result.address = addr;\n if (name) result.name = name;\n return result;\n }\n const emails = extractEmails(header);\n if (emails[0]) return { address: emails[0] };\n return { address: header.trim() };\n}\n"],"names":["extractEmails","header","matches","match","map","s","trim","extractFrom","undefined","m","rawName","name","replace","addr","result","address","emails"],"mappings":"AAAA,OAAO,SAASA,cAAcC,MAAe;IAC3C,IAAI,CAACA,QAAQ,OAAO,EAAE;IACtB,MAAMC,UAAUD,OAAOE,KAAK,CAAC,8CAA8C,EAAE;IAC7E,OAAOD,QAAQE,GAAG,CAAC,CAACC,IAAcA,EAAEC,IAAI;AAC1C;AAEA,OAAO,SAASC,YAAYN,MAAe;IACzC,IAAI,CAACA,QAAQ,OAAOO;IACpB,MAAMC,IAAIR,OAAOE,KAAK,CAAC;IACvB,IAAIM,GAAG;QACL,MAAMC,UAAUD,CAAC,CAAC,EAAE;QACpB,MAAME,OAAOD,UAAUA,QAAQE,OAAO,CAAC,MAAM,IAAIN,IAAI,KAAKE;QAC1D,MAAMK,OAAOJ,CAAC,CAAC,EAAE,GAAGA,CAAC,CAAC,EAAE,CAACH,IAAI,KAAKE;QAClC,MAAMM,SAA8C,CAAC;QACrD,IAAID,MAAMC,OAAOC,OAAO,GAAGF;QAC3B,IAAIF,MAAMG,OAAOH,IAAI,GAAGA;QACxB,OAAOG;IACT;IACA,MAAME,SAAShB,cAAcC;IAC7B,IAAIe,MAAM,CAAC,EAAE,EAAE,OAAO;QAAED,SAASC,MAAM,CAAC,EAAE;IAAC;IAC3C,OAAO;QAAED,SAASd,OAAOK,IAAI;IAAG;AAClC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { gmail_v1 } from 'googleapis';
|
|
2
|
+
export interface BodyExtractionOptions {
|
|
3
|
+
/** Format to return: 'text' extracts plain text, 'html' preserves HTML structure */
|
|
4
|
+
contentType?: 'text' | 'html';
|
|
5
|
+
/** When true, removes quoted thread history from HTML content */
|
|
6
|
+
excludeThreadHistory?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function extractBodyFromPayload(payload: gmail_v1.Schema$MessagePart, options?: BodyExtractionOptions): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { extractCurrentMessageFromHtml } from '@mcp-z/email';
|
|
2
|
+
import { parse } from 'node-html-parser';
|
|
3
|
+
export function extractBodyFromPayload(payload, options = {}) {
|
|
4
|
+
var _payload_body;
|
|
5
|
+
const { contentType = 'text', excludeThreadHistory = false } = options;
|
|
6
|
+
if (!payload) return '';
|
|
7
|
+
// If there's a direct body with data
|
|
8
|
+
if ((_payload_body = payload.body) === null || _payload_body === void 0 ? void 0 : _payload_body.data) {
|
|
9
|
+
return Buffer.from(payload.body.data, 'base64').toString('utf-8');
|
|
10
|
+
}
|
|
11
|
+
// If there are parts, look for text/plain or text/html
|
|
12
|
+
if (payload.parts && Array.isArray(payload.parts)) {
|
|
13
|
+
for (const part of payload.parts){
|
|
14
|
+
var _part_body, _part_body1;
|
|
15
|
+
if (part.mimeType === 'text/plain' && ((_part_body = part.body) === null || _part_body === void 0 ? void 0 : _part_body.data)) {
|
|
16
|
+
return Buffer.from(part.body.data, 'base64').toString('utf-8');
|
|
17
|
+
}
|
|
18
|
+
if (part.mimeType === 'text/html' && ((_part_body1 = part.body) === null || _part_body1 === void 0 ? void 0 : _part_body1.data)) {
|
|
19
|
+
let html = Buffer.from(part.body.data, 'base64').toString('utf-8');
|
|
20
|
+
// Remove thread history if requested
|
|
21
|
+
if (excludeThreadHistory) {
|
|
22
|
+
html = extractCurrentMessageFromHtml(html);
|
|
23
|
+
}
|
|
24
|
+
// Return HTML directly if requested
|
|
25
|
+
if (contentType === 'html') {
|
|
26
|
+
return html;
|
|
27
|
+
}
|
|
28
|
+
// Otherwise extract plain text from HTML
|
|
29
|
+
const doc = parse(html);
|
|
30
|
+
const docUnknown = doc;
|
|
31
|
+
if (docUnknown && typeof docUnknown === 'object' && 'text' in docUnknown) {
|
|
32
|
+
return docUnknown.text;
|
|
33
|
+
}
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/parsing/html-processing.ts"],"sourcesContent":["import { extractCurrentMessageFromHtml } from '@mcp-z/email';\nimport type { gmail_v1 } from 'googleapis';\nimport { parse } from 'node-html-parser';\n\nexport interface BodyExtractionOptions {\n /** Format to return: 'text' extracts plain text, 'html' preserves HTML structure */\n contentType?: 'text' | 'html';\n /** When true, removes quoted thread history from HTML content */\n excludeThreadHistory?: boolean;\n}\n\nexport function extractBodyFromPayload(payload: gmail_v1.Schema$MessagePart, options: BodyExtractionOptions = {}): string {\n const { contentType = 'text', excludeThreadHistory = false } = options;\n if (!payload) return '';\n\n // If there's a direct body with data\n if (payload.body?.data) {\n return Buffer.from(payload.body.data, 'base64').toString('utf-8');\n }\n\n // If there are parts, look for text/plain or text/html\n if (payload.parts && Array.isArray(payload.parts)) {\n for (const part of payload.parts) {\n if (part.mimeType === 'text/plain' && part.body?.data) {\n return Buffer.from(part.body.data, 'base64').toString('utf-8');\n }\n if (part.mimeType === 'text/html' && part.body?.data) {\n let html = Buffer.from(part.body.data, 'base64').toString('utf-8');\n\n // Remove thread history if requested\n if (excludeThreadHistory) {\n html = extractCurrentMessageFromHtml(html);\n }\n\n // Return HTML directly if requested\n if (contentType === 'html') {\n return html;\n }\n\n // Otherwise extract plain text from HTML\n const doc = parse(html);\n const docUnknown = doc as unknown;\n if (docUnknown && typeof docUnknown === 'object' && 'text' in docUnknown) {\n return docUnknown.text as string;\n }\n return '';\n }\n }\n }\n\n return '';\n}\n"],"names":["extractCurrentMessageFromHtml","parse","extractBodyFromPayload","payload","options","contentType","excludeThreadHistory","body","data","Buffer","from","toString","parts","Array","isArray","part","mimeType","html","doc","docUnknown","text"],"mappings":"AAAA,SAASA,6BAA6B,QAAQ,eAAe;AAE7D,SAASC,KAAK,QAAQ,mBAAmB;AASzC,OAAO,SAASC,uBAAuBC,OAAoC,EAAEC,UAAiC,CAAC,CAAC;QAK1GD;IAJJ,MAAM,EAAEE,cAAc,MAAM,EAAEC,uBAAuB,KAAK,EAAE,GAAGF;IAC/D,IAAI,CAACD,SAAS,OAAO;IAErB,qCAAqC;IACrC,KAAIA,gBAAAA,QAAQI,IAAI,cAAZJ,oCAAAA,cAAcK,IAAI,EAAE;QACtB,OAAOC,OAAOC,IAAI,CAACP,QAAQI,IAAI,CAACC,IAAI,EAAE,UAAUG,QAAQ,CAAC;IAC3D;IAEA,uDAAuD;IACvD,IAAIR,QAAQS,KAAK,IAAIC,MAAMC,OAAO,CAACX,QAAQS,KAAK,GAAG;QACjD,KAAK,MAAMG,QAAQZ,QAAQS,KAAK,CAAE;gBACMG,YAGDA;YAHrC,IAAIA,KAAKC,QAAQ,KAAK,kBAAgBD,aAAAA,KAAKR,IAAI,cAATQ,iCAAAA,WAAWP,IAAI,GAAE;gBACrD,OAAOC,OAAOC,IAAI,CAACK,KAAKR,IAAI,CAACC,IAAI,EAAE,UAAUG,QAAQ,CAAC;YACxD;YACA,IAAII,KAAKC,QAAQ,KAAK,iBAAeD,cAAAA,KAAKR,IAAI,cAATQ,kCAAAA,YAAWP,IAAI,GAAE;gBACpD,IAAIS,OAAOR,OAAOC,IAAI,CAACK,KAAKR,IAAI,CAACC,IAAI,EAAE,UAAUG,QAAQ,CAAC;gBAE1D,qCAAqC;gBACrC,IAAIL,sBAAsB;oBACxBW,OAAOjB,8BAA8BiB;gBACvC;gBAEA,oCAAoC;gBACpC,IAAIZ,gBAAgB,QAAQ;oBAC1B,OAAOY;gBACT;gBAEA,yCAAyC;gBACzC,MAAMC,MAAMjB,MAAMgB;gBAClB,MAAME,aAAaD;gBACnB,IAAIC,cAAc,OAAOA,eAAe,YAAY,UAAUA,YAAY;oBACxE,OAAOA,WAAWC,IAAI;gBACxB;gBACA,OAAO;YACT;QACF;IACF;IAEA,OAAO;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/parsing/message-extraction.ts"],"sourcesContent":["// Unified message extraction functionality\n\nexport { extractEmails, extractFrom } from './headers-utils.js';\nexport { extractBodyFromPayload } from './html-processing.js';\n"],"names":["extractEmails","extractFrom","extractBodyFromPayload"],"mappings":"AAAA,2CAA2C;AAE3C,SAASA,aAAa,EAAEC,WAAW,QAAQ,qBAAqB;AAChE,SAASC,sBAAsB,QAAQ,uBAAuB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExecutionResult } from '@mcp-z/email';
|
|
2
|
+
import type { gmail_v1 } from 'googleapis';
|
|
3
|
+
import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.js';
|
|
4
|
+
import type { Logger } from '../../types.js';
|
|
5
|
+
export interface ExecuteQueryOptions {
|
|
6
|
+
client: gmail_v1.Gmail;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
pageSize?: number;
|
|
9
|
+
pageToken?: string;
|
|
10
|
+
includeBody?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Execute a Gmail query with direct, single-attempt execution.
|
|
14
|
+
* No planning, no fallbacks, no retries.
|
|
15
|
+
* Provider errors are returned directly to the caller for actionable feedback.
|
|
16
|
+
*/
|
|
17
|
+
export declare function executeQuery<T>(query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MAX_PAGE_SIZE } from '../../constants.js';
|
|
2
|
+
import { searchMessages } from './search-execution.js';
|
|
3
|
+
/**
|
|
4
|
+
* Execute a Gmail query with direct, single-attempt execution.
|
|
5
|
+
* No planning, no fallbacks, no retries.
|
|
6
|
+
* Provider errors are returned directly to the caller for actionable feedback.
|
|
7
|
+
*/ export async function executeQuery(query, options, transform) {
|
|
8
|
+
const { client, logger, pageSize, pageToken, includeBody } = options;
|
|
9
|
+
// Validate pagination parameters
|
|
10
|
+
if (pageSize !== undefined && (pageSize < 1 || pageSize > MAX_PAGE_SIZE)) {
|
|
11
|
+
throw new Error(`pageSize must be between 1 and ${MAX_PAGE_SIZE}`);
|
|
12
|
+
}
|
|
13
|
+
if (pageToken !== undefined && typeof pageToken === 'string' && pageToken.trim().length === 0) {
|
|
14
|
+
logger.info('Empty pageToken provided, ignoring');
|
|
15
|
+
}
|
|
16
|
+
// Single execution - direct query to Gmail API
|
|
17
|
+
logger.info('executeQuery: executing direct Gmail query');
|
|
18
|
+
try {
|
|
19
|
+
const result = await searchMessages(client, {
|
|
20
|
+
...query !== undefined && {
|
|
21
|
+
query
|
|
22
|
+
},
|
|
23
|
+
pageSize: pageSize !== null && pageSize !== void 0 ? pageSize : 50,
|
|
24
|
+
pageToken: pageToken && pageToken.trim().length > 0 ? pageToken : undefined,
|
|
25
|
+
includeBody: includeBody !== null && includeBody !== void 0 ? includeBody : false,
|
|
26
|
+
logger
|
|
27
|
+
});
|
|
28
|
+
// Transform results
|
|
29
|
+
const transformedResults = result.messages.map(transform);
|
|
30
|
+
logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
items: transformedResults,
|
|
34
|
+
metadata: {
|
|
35
|
+
nextPageToken: result.nextPageToken
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Re-throw errors directly - no fallback logic
|
|
40
|
+
logger.error('executeQuery: failed', {
|
|
41
|
+
error: error instanceof Error ? error.message : String(error)
|
|
42
|
+
});
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/querying/execute-query.ts"],"sourcesContent":["import type { ExecutionResult } from '@mcp-z/email';\nimport type { gmail_v1 } from 'googleapis';\nimport { MAX_PAGE_SIZE } from '../../constants.ts';\nimport type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.js';\nimport type { Logger } from '../../types.js';\nimport { searchMessages } from './search-execution.js';\n\nexport interface ExecuteQueryOptions {\n client: gmail_v1.Gmail;\n logger: Logger;\n pageSize?: number;\n pageToken?: string;\n includeBody?: boolean;\n}\n\n/**\n * Execute a Gmail query with direct, single-attempt execution.\n * No planning, no fallbacks, no retries.\n * Provider errors are returned directly to the caller for actionable feedback.\n */\nexport async function executeQuery<T>(query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>> {\n const { client, logger, pageSize, pageToken, includeBody } = options;\n\n // Validate pagination parameters\n if (pageSize !== undefined && (pageSize < 1 || pageSize > MAX_PAGE_SIZE)) {\n throw new Error(`pageSize must be between 1 and ${MAX_PAGE_SIZE}`);\n }\n\n if (pageToken !== undefined && typeof pageToken === 'string' && pageToken.trim().length === 0) {\n logger.info('Empty pageToken provided, ignoring');\n }\n\n // Single execution - direct query to Gmail API\n logger.info('executeQuery: executing direct Gmail query');\n\n try {\n const result = await searchMessages(client, {\n ...(query !== undefined && { query }),\n pageSize: pageSize ?? 50,\n pageToken: pageToken && pageToken.trim().length > 0 ? pageToken : undefined,\n includeBody: includeBody ?? false,\n logger,\n });\n\n // Transform results\n const transformedResults = result.messages.map(transform);\n\n logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);\n\n return {\n success: true,\n items: transformedResults,\n metadata: {\n nextPageToken: result.nextPageToken,\n },\n };\n } catch (error) {\n // Re-throw errors directly - no fallback logic\n logger.error('executeQuery: failed', { error: error instanceof Error ? error.message : String(error) });\n throw error;\n }\n}\n"],"names":["MAX_PAGE_SIZE","searchMessages","executeQuery","query","options","transform","client","logger","pageSize","pageToken","includeBody","undefined","Error","trim","length","info","result","transformedResults","messages","map","success","items","metadata","nextPageToken","error","message","String"],"mappings":"AAEA,SAASA,aAAa,QAAQ,qBAAqB;AAGnD,SAASC,cAAc,QAAQ,wBAAwB;AAUvD;;;;CAIC,GACD,OAAO,eAAeC,aAAgBC,KAA4B,EAAEC,OAA4B,EAAEC,SAA+B;IAC/H,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,WAAW,EAAE,GAAGN;IAE7D,iCAAiC;IACjC,IAAII,aAAaG,aAAcH,CAAAA,WAAW,KAAKA,WAAWR,aAAY,GAAI;QACxE,MAAM,IAAIY,MAAM,CAAC,+BAA+B,EAAEZ,eAAe;IACnE;IAEA,IAAIS,cAAcE,aAAa,OAAOF,cAAc,YAAYA,UAAUI,IAAI,GAAGC,MAAM,KAAK,GAAG;QAC7FP,OAAOQ,IAAI,CAAC;IACd;IAEA,+CAA+C;IAC/CR,OAAOQ,IAAI,CAAC;IAEZ,IAAI;QACF,MAAMC,SAAS,MAAMf,eAAeK,QAAQ;YAC1C,GAAIH,UAAUQ,aAAa;gBAAER;YAAM,CAAC;YACpCK,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;YACtBC,WAAWA,aAAaA,UAAUI,IAAI,GAAGC,MAAM,GAAG,IAAIL,YAAYE;YAClED,WAAW,EAAEA,wBAAAA,yBAAAA,cAAe;YAC5BH;QACF;QAEA,oBAAoB;QACpB,MAAMU,qBAAqBD,OAAOE,QAAQ,CAACC,GAAG,CAACd;QAE/CE,OAAOQ,IAAI,CAAC,CAAC,6BAA6B,EAAEE,mBAAmBH,MAAM,CAAC,QAAQ,CAAC;QAE/E,OAAO;YACLM,SAAS;YACTC,OAAOJ;YACPK,UAAU;gBACRC,eAAeP,OAAOO,aAAa;YACrC;QACF;IACF,EAAE,OAAOC,OAAO;QACd,+CAA+C;QAC/CjB,OAAOiB,KAAK,CAAC,wBAAwB;YAAEA,OAAOA,iBAAiBZ,QAAQY,MAAMC,OAAO,GAAGC,OAAOF;QAAO;QACrG,MAAMA;IACR;AACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Gmail pagination helpers for single-page operations. */
|
|
2
|
+
import type { gmail_v1 } from 'googleapis';
|
|
3
|
+
import type { Logger } from '../../types.js';
|
|
4
|
+
export interface SinglePageResult {
|
|
5
|
+
readonly messages: gmail_v1.Schema$Message[];
|
|
6
|
+
readonly nextPageToken: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Fetch a single page of messages from Gmail
|
|
10
|
+
*/
|
|
11
|
+
export interface FetchMessagesPageParams {
|
|
12
|
+
readonly gmailQ: string;
|
|
13
|
+
readonly pageSize?: number;
|
|
14
|
+
readonly pageToken: string | undefined;
|
|
15
|
+
readonly body?: boolean;
|
|
16
|
+
readonly logger: Logger;
|
|
17
|
+
readonly metadataHeaders?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function fetchMessagesPage(gmail: gmail_v1.Gmail, params: FetchMessagesPageParams): Promise<SinglePageResult>;
|
|
20
|
+
export interface FetchMessagesConcurrentlyParams {
|
|
21
|
+
readonly items: readonly string[];
|
|
22
|
+
readonly concurrency?: number;
|
|
23
|
+
readonly body?: boolean;
|
|
24
|
+
readonly logger: Logger;
|
|
25
|
+
readonly metadataHeaders?: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
export declare function fetchMessagesConcurrently(gmail: gmail_v1.Gmail, params: FetchMessagesConcurrentlyParams): Promise<gmail_v1.Schema$Message[]>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/** Gmail pagination helpers for single-page operations. */ export async function fetchMessagesPage(gmail, params) {
|
|
2
|
+
const { gmailQ, pageSize = 50, pageToken, body = false, logger, metadataHeaders } = params;
|
|
3
|
+
// Secure resource bounds checking - prevent security bypasses
|
|
4
|
+
const maxPageSize = 500; // Gmail API maximum - enforced for security
|
|
5
|
+
const minPageSize = 1; // Minimum valid page size
|
|
6
|
+
// Validate input is a positive number to prevent bypass attempts
|
|
7
|
+
if (!Number.isInteger(pageSize) || pageSize < 0) {
|
|
8
|
+
throw new Error(`Invalid pageSize: must be a positive integer, got ${pageSize}`);
|
|
9
|
+
}
|
|
10
|
+
const safePageSize = Math.min(Math.max(minPageSize, pageSize), maxPageSize);
|
|
11
|
+
if (pageSize !== safePageSize && logger) {
|
|
12
|
+
logger.info('Page size bounded for API safety', {
|
|
13
|
+
requested: pageSize,
|
|
14
|
+
applied: safePageSize
|
|
15
|
+
});
|
|
16
|
+
// No fallback to console - would corrupt MCP stdio communication
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const listParams = {
|
|
20
|
+
userId: 'me',
|
|
21
|
+
q: gmailQ,
|
|
22
|
+
maxResults: safePageSize
|
|
23
|
+
};
|
|
24
|
+
const listResponse = pageToken && pageToken.trim().length > 0 ? await gmail.users.messages.list({
|
|
25
|
+
...listParams,
|
|
26
|
+
pageToken
|
|
27
|
+
}) : await gmail.users.messages.list(listParams);
|
|
28
|
+
const response = listResponse.data;
|
|
29
|
+
const messages = response.messages || [];
|
|
30
|
+
if (messages.length === 0) {
|
|
31
|
+
if (logger) logger.info('No messages found on page');
|
|
32
|
+
return {
|
|
33
|
+
messages: [],
|
|
34
|
+
nextPageToken: undefined
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const items = messages.map((m)=>m.id).filter(Boolean);
|
|
38
|
+
if (items.length === 0) {
|
|
39
|
+
if (logger) logger.info('No valid message ids on page');
|
|
40
|
+
return {
|
|
41
|
+
messages: [],
|
|
42
|
+
nextPageToken: response.nextPageToken && response.nextPageToken.trim().length > 0 ? response.nextPageToken : undefined
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const concurrentArgs = {
|
|
46
|
+
items,
|
|
47
|
+
concurrency: 5,
|
|
48
|
+
body,
|
|
49
|
+
...logger && {
|
|
50
|
+
logger
|
|
51
|
+
},
|
|
52
|
+
...metadataHeaders && {
|
|
53
|
+
metadataHeaders
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const detailedMessages = await fetchMessagesConcurrently(gmail, concurrentArgs);
|
|
57
|
+
if (logger) logger.info(`Fetched page with ${detailedMessages.length} messages`);
|
|
58
|
+
return {
|
|
59
|
+
messages: detailedMessages,
|
|
60
|
+
nextPageToken: response.nextPageToken && response.nextPageToken.trim().length > 0 ? response.nextPageToken : undefined
|
|
61
|
+
};
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Standardized error handling for pagination pipeline
|
|
64
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
65
|
+
if (logger) logger.error('Gmail pagination: single page fetch failed', {
|
|
66
|
+
error: errorMessage,
|
|
67
|
+
query: gmailQ,
|
|
68
|
+
pageSize: safePageSize,
|
|
69
|
+
hasPageToken: !!pageToken
|
|
70
|
+
});
|
|
71
|
+
// Preserve original error type for upstream handling
|
|
72
|
+
if (error instanceof Error) {
|
|
73
|
+
// Enhance error with pagination context
|
|
74
|
+
error.message = `Gmail pagination fetch failed: ${error.message}`;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
// Convert non-Error objects to proper Error instances
|
|
78
|
+
throw new Error(`Gmail pagination fetch failed: ${errorMessage}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export async function fetchMessagesConcurrently(gmail, params) {
|
|
82
|
+
const { items, concurrency = 2, body = false, logger, metadataHeaders } = params;
|
|
83
|
+
// Secure resource bounds checking for concurrent operations
|
|
84
|
+
const maxConcurrency = 10; // Conservative limit to prevent rate limiting and resource exhaustion
|
|
85
|
+
const minConcurrency = 1; // Minimum valid concurrency
|
|
86
|
+
// Validate input is a positive number to prevent bypass attempts
|
|
87
|
+
if (!Number.isInteger(concurrency) || concurrency < 0) {
|
|
88
|
+
throw new Error(`Invalid concurrency: must be a positive integer, got ${concurrency}`);
|
|
89
|
+
}
|
|
90
|
+
const safeConcurrency = Math.min(Math.max(minConcurrency, concurrency), maxConcurrency);
|
|
91
|
+
if (concurrency !== safeConcurrency && logger) {
|
|
92
|
+
logger.info('Concurrency bounded for API safety', {
|
|
93
|
+
requested: concurrency,
|
|
94
|
+
applied: safeConcurrency
|
|
95
|
+
});
|
|
96
|
+
// No fallback to console - would corrupt MCP stdio communication
|
|
97
|
+
}
|
|
98
|
+
if (items.length === 0) return [];
|
|
99
|
+
const results = new Array(items.length);
|
|
100
|
+
const format = body ? 'full' : 'metadata';
|
|
101
|
+
// Always pass metadataHeaders if provided - body doesn't replace headers, it's additional content
|
|
102
|
+
const metadataHeadersForRequest = metadataHeaders;
|
|
103
|
+
// Pre-build request parameters to avoid repeated object creation
|
|
104
|
+
const requestParams = items.map((id)=>{
|
|
105
|
+
const baseParams = {
|
|
106
|
+
userId: 'me',
|
|
107
|
+
id,
|
|
108
|
+
format
|
|
109
|
+
};
|
|
110
|
+
// Only include metadataHeaders if defined (exactOptionalPropertyTypes compliance)
|
|
111
|
+
return metadataHeadersForRequest ? {
|
|
112
|
+
...baseParams,
|
|
113
|
+
metadataHeaders: [
|
|
114
|
+
...metadataHeadersForRequest
|
|
115
|
+
]
|
|
116
|
+
} : baseParams;
|
|
117
|
+
});
|
|
118
|
+
// Optimize concurrent processing using batching
|
|
119
|
+
const batchSize = safeConcurrency;
|
|
120
|
+
const batches = [];
|
|
121
|
+
for(let i = 0; i < requestParams.length; i += batchSize){
|
|
122
|
+
batches.push(requestParams.slice(i, i + batchSize));
|
|
123
|
+
}
|
|
124
|
+
let processedCount = 0;
|
|
125
|
+
for (const batch of batches){
|
|
126
|
+
const batchPromises = batch.map(async (params, batchIndex)=>{
|
|
127
|
+
try {
|
|
128
|
+
const messageResponse = await gmail.users.messages.get(params);
|
|
129
|
+
const globalIndex = processedCount + batchIndex;
|
|
130
|
+
results[globalIndex] = messageResponse.data;
|
|
131
|
+
return messageResponse.data;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
// Log individual message fetch failures but continue processing
|
|
134
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
135
|
+
if (logger) logger.info('Gmail pagination: individual message fetch failed, continuing', {
|
|
136
|
+
error: errorMessage,
|
|
137
|
+
messageId: params.id,
|
|
138
|
+
globalIndex: processedCount + batchIndex
|
|
139
|
+
});
|
|
140
|
+
return null; // Mark as failed but continue
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
await Promise.all(batchPromises);
|
|
144
|
+
processedCount += batch.length;
|
|
145
|
+
// Progress logging for large batches
|
|
146
|
+
if (items.length > 20) {
|
|
147
|
+
if (logger) logger.info(`Gmail pagination: processed ${processedCount}/${items.length} messages`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Filter out any null results from failed individual fetches
|
|
151
|
+
return results.filter((result)=>result !== null && result !== undefined);
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-gmail/src/email/querying/pagination.ts"],"sourcesContent":["/** Gmail pagination helpers for single-page operations. */\n\nimport type { gmail_v1 } from 'googleapis';\nimport type { Logger } from '../../types.js';\n\nexport interface SinglePageResult {\n readonly messages: gmail_v1.Schema$Message[];\n readonly nextPageToken: string | undefined;\n}\n\n/**\n * Fetch a single page of messages from Gmail\n */\nexport interface FetchMessagesPageParams {\n readonly gmailQ: string;\n readonly pageSize?: number;\n readonly pageToken: string | undefined;\n readonly body?: boolean;\n readonly logger: Logger;\n readonly metadataHeaders?: readonly string[];\n}\n\nexport async function fetchMessagesPage(gmail: gmail_v1.Gmail, params: FetchMessagesPageParams): Promise<SinglePageResult> {\n const { gmailQ, pageSize = 50, pageToken, body = false, logger, metadataHeaders } = params;\n\n // Secure resource bounds checking - prevent security bypasses\n const maxPageSize = 500; // Gmail API maximum - enforced for security\n const minPageSize = 1; // Minimum valid page size\n\n // Validate input is a positive number to prevent bypass attempts\n if (!Number.isInteger(pageSize) || pageSize < 0) {\n throw new Error(`Invalid pageSize: must be a positive integer, got ${pageSize}`);\n }\n\n const safePageSize = Math.min(Math.max(minPageSize, pageSize), maxPageSize);\n\n if (pageSize !== safePageSize && logger) {\n logger.info('Page size bounded for API safety', { requested: pageSize, applied: safePageSize });\n // No fallback to console - would corrupt MCP stdio communication\n }\n\n try {\n const listParams = {\n userId: 'me',\n q: gmailQ,\n maxResults: safePageSize,\n };\n const listResponse = pageToken && pageToken.trim().length > 0 ? await gmail.users.messages.list({ ...listParams, pageToken }) : await gmail.users.messages.list(listParams);\n const response = listResponse.data;\n const messages = response.messages || [];\n\n if (messages.length === 0) {\n if (logger) logger.info('No messages found on page');\n return { messages: [], nextPageToken: undefined };\n }\n\n const items = messages.map((m: gmail_v1.Schema$Message) => m.id).filter(Boolean) as string[];\n if (items.length === 0) {\n if (logger) logger.info('No valid message ids on page');\n return { messages: [], nextPageToken: response.nextPageToken && response.nextPageToken.trim().length > 0 ? response.nextPageToken : undefined };\n }\n\n const concurrentArgs: FetchMessagesConcurrentlyParams = {\n items,\n concurrency: 5,\n body,\n ...(logger && { logger }),\n ...(metadataHeaders && { metadataHeaders }),\n };\n const detailedMessages = await fetchMessagesConcurrently(gmail, concurrentArgs);\n\n if (logger) logger.info(`Fetched page with ${detailedMessages.length} messages`);\n return {\n messages: detailedMessages,\n nextPageToken: response.nextPageToken && response.nextPageToken.trim().length > 0 ? response.nextPageToken : undefined,\n };\n } catch (error) {\n // Standardized error handling for pagination pipeline\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (logger)\n logger.error('Gmail pagination: single page fetch failed', {\n error: errorMessage,\n query: gmailQ,\n pageSize: safePageSize,\n hasPageToken: !!pageToken,\n });\n\n // Preserve original error type for upstream handling\n if (error instanceof Error) {\n // Enhance error with pagination context\n error.message = `Gmail pagination fetch failed: ${error.message}`;\n throw error;\n }\n\n // Convert non-Error objects to proper Error instances\n throw new Error(`Gmail pagination fetch failed: ${errorMessage}`);\n }\n}\n\nexport interface FetchMessagesConcurrentlyParams {\n readonly items: readonly string[];\n readonly concurrency?: number;\n readonly body?: boolean;\n readonly logger: Logger;\n readonly metadataHeaders?: readonly string[];\n}\n\nexport async function fetchMessagesConcurrently(gmail: gmail_v1.Gmail, params: FetchMessagesConcurrentlyParams): Promise<gmail_v1.Schema$Message[]> {\n const { items, concurrency = 2, body = false, logger, metadataHeaders } = params;\n\n // Secure resource bounds checking for concurrent operations\n const maxConcurrency = 10; // Conservative limit to prevent rate limiting and resource exhaustion\n const minConcurrency = 1; // Minimum valid concurrency\n\n // Validate input is a positive number to prevent bypass attempts\n if (!Number.isInteger(concurrency) || concurrency < 0) {\n throw new Error(`Invalid concurrency: must be a positive integer, got ${concurrency}`);\n }\n\n const safeConcurrency = Math.min(Math.max(minConcurrency, concurrency), maxConcurrency);\n\n if (concurrency !== safeConcurrency && logger) {\n logger.info('Concurrency bounded for API safety', { requested: concurrency, applied: safeConcurrency });\n // No fallback to console - would corrupt MCP stdio communication\n }\n\n if (items.length === 0) return [];\n\n const results: (gmail_v1.Schema$Message | null)[] = new Array(items.length);\n const format = body ? 'full' : 'metadata';\n // Always pass metadataHeaders if provided - body doesn't replace headers, it's additional content\n const metadataHeadersForRequest = metadataHeaders;\n\n // Pre-build request parameters to avoid repeated object creation\n const requestParams = items.map((id) => {\n const baseParams = {\n userId: 'me' as const,\n id,\n format,\n };\n // Only include metadataHeaders if defined (exactOptionalPropertyTypes compliance)\n return metadataHeadersForRequest ? { ...baseParams, metadataHeaders: [...metadataHeadersForRequest] } : baseParams;\n });\n\n // Optimize concurrent processing using batching\n const batchSize = safeConcurrency;\n const batches: (typeof requestParams)[] = [];\n for (let i = 0; i < requestParams.length; i += batchSize) {\n batches.push(requestParams.slice(i, i + batchSize));\n }\n\n let processedCount = 0;\n for (const batch of batches) {\n const batchPromises = batch.map(async (params, batchIndex) => {\n try {\n const messageResponse = await gmail.users.messages.get(params);\n const globalIndex = processedCount + batchIndex;\n results[globalIndex] = messageResponse.data;\n return messageResponse.data;\n } catch (error) {\n // Log individual message fetch failures but continue processing\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (logger)\n logger.info('Gmail pagination: individual message fetch failed, continuing', {\n error: errorMessage,\n messageId: params.id,\n globalIndex: processedCount + batchIndex,\n });\n return null; // Mark as failed but continue\n }\n });\n\n await Promise.all(batchPromises);\n processedCount += batch.length;\n\n // Progress logging for large batches\n if (items.length > 20) {\n if (logger) logger.info(`Gmail pagination: processed ${processedCount}/${items.length} messages`);\n }\n }\n\n // Filter out any null results from failed individual fetches\n return results.filter((result) => result !== null && result !== undefined);\n}\n"],"names":["fetchMessagesPage","gmail","params","gmailQ","pageSize","pageToken","body","logger","metadataHeaders","maxPageSize","minPageSize","Number","isInteger","Error","safePageSize","Math","min","max","info","requested","applied","listParams","userId","q","maxResults","listResponse","trim","length","users","messages","list","response","data","nextPageToken","undefined","items","map","m","id","filter","Boolean","concurrentArgs","concurrency","detailedMessages","fetchMessagesConcurrently","error","errorMessage","message","String","query","hasPageToken","maxConcurrency","minConcurrency","safeConcurrency","results","Array","format","metadataHeadersForRequest","requestParams","baseParams","batchSize","batches","i","push","slice","processedCount","batch","batchPromises","batchIndex","messageResponse","get","globalIndex","messageId","Promise","all","result"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { GmailQuery as QueryNode } from '../../schemas/gmail-query-schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Field operator interface for query filters
|
|
4
|
+
*/
|
|
5
|
+
export interface FieldOperator {
|
|
6
|
+
$any?: string[];
|
|
7
|
+
$all?: string[];
|
|
8
|
+
$none?: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Field query interface with support for all email fields including categories and labels
|
|
12
|
+
*/
|
|
13
|
+
export interface FieldQuery {
|
|
14
|
+
from?: FieldOperator | string;
|
|
15
|
+
to?: FieldOperator | string;
|
|
16
|
+
cc?: FieldOperator | string;
|
|
17
|
+
bcc?: FieldOperator | string;
|
|
18
|
+
subject?: FieldOperator | string;
|
|
19
|
+
text?: FieldOperator | string;
|
|
20
|
+
body?: FieldOperator | string;
|
|
21
|
+
categories?: FieldOperator | string;
|
|
22
|
+
label?: FieldOperator | string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Filter extraction result with all collected values from a query
|
|
26
|
+
*/
|
|
27
|
+
export interface Filters {
|
|
28
|
+
subjectIncludes?: string[];
|
|
29
|
+
bodyIncludes?: string[];
|
|
30
|
+
textIncludes?: string[];
|
|
31
|
+
fromIncludes?: string[];
|
|
32
|
+
toIncludes?: string[];
|
|
33
|
+
ccIncludes?: string[];
|
|
34
|
+
bccIncludes?: string[];
|
|
35
|
+
categoriesIncludes?: string[];
|
|
36
|
+
labelIncludes?: string[];
|
|
37
|
+
hasAttachment?: boolean;
|
|
38
|
+
since?: string;
|
|
39
|
+
before?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function toGmailQuery(query: QueryNode, options?: {
|
|
42
|
+
dateSlash?: boolean;
|
|
43
|
+
}): {
|
|
44
|
+
q: string;
|
|
45
|
+
filters: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
export declare function extractFiltersFromParsed(parsed: QueryNode): Filters;
|