mcp-scraper 0.72.3 → 0.72.5
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/CHANGELOG.md +15 -1
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +77 -9
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-QRXSCUU2.js → chunk-3SECYTNB.js} +1 -1
- package/dist/{chunk-MB72PA6S.js → chunk-K2SXQGKM.js} +49 -0
- package/dist/{chunk-V2YM7V4E.js → chunk-WHXNA6GK.js} +1 -1
- package/dist/{gmail-service-E276SBJU.js → gmail-service-QXDGNWUJ.js} +1 -1
- package/dist/{server-MCB6LV5G.js → server-IABKDP7V.js} +30 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to MCP Scraper are documented here. The format is based on [
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.72.5] - 2026-08-27
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Gmail Memory imports now provide deterministic descriptions for newly encountered import tags, allowing complete messages, manifests, and attachments to enter the selected vault instead of stopping at the first note write.
|
|
12
|
+
|
|
13
|
+
## [0.72.4] - 2026-08-27
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `gmail_send_message` now uses the same owner-checked, action-gated Gmail REST transport as complete reads and bulk actions, with a durable idempotency receipt, instead of depending on the unavailable generic provider MCP send transport.
|
|
18
|
+
|
|
7
19
|
## [0.72.3] - 2026-08-27
|
|
8
20
|
|
|
9
21
|
### Fixed
|
|
@@ -1260,7 +1272,9 @@ All notable changes to MCP Scraper are documented here. The format is based on [
|
|
|
1260
1272
|
- Write actions remain unavailable until the account owner explicitly enables them.
|
|
1261
1273
|
- Provider-specific connection data is normalized into one agent-facing contract.
|
|
1262
1274
|
|
|
1263
|
-
[Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.
|
|
1275
|
+
[Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.5...HEAD
|
|
1276
|
+
[0.72.5]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.4...v0.72.5
|
|
1277
|
+
[0.72.4]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.3...v0.72.4
|
|
1264
1278
|
[0.72.3]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.2...v0.72.3
|
|
1265
1279
|
[0.72.2]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.1...v0.72.2
|
|
1266
1280
|
[0.72.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.72.0...v0.72.1
|
package/README.md
CHANGED
|
@@ -159,7 +159,7 @@ Build the branded one-click bundle:
|
|
|
159
159
|
npm run build:mcpb
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.72.
|
|
162
|
+
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.72.5`, SHA-256 `fa1470cbf16f4586a6009e32f0278078e7a99065676bf8ad1975db70736ad5fb`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
|
|
163
163
|
|
|
164
164
|
The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
|
|
165
165
|
|
package/dist/bin/api-server.cjs
CHANGED
|
@@ -44074,6 +44074,7 @@ var init_main_nango_transport = __esm({
|
|
|
44074
44074
|
{ method: "GET", pattern: /^\/gmail\/v1\/users\/me\/labels$/ },
|
|
44075
44075
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/batchModify$/ },
|
|
44076
44076
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/batchDelete$/ },
|
|
44077
|
+
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/send$/ },
|
|
44077
44078
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/[A-Za-z0-9_-]+\/(?:trash|untrash)$/ }
|
|
44078
44079
|
];
|
|
44079
44080
|
GMAIL_QUERY_KEYS = /* @__PURE__ */ new Set(["q", "maxResults", "pageToken", "format", "metadataHeaders", "fields"]);
|
|
@@ -44379,6 +44380,21 @@ function base64urlDecode(value) {
|
|
|
44379
44380
|
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
44380
44381
|
return Buffer.from(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="), "base64");
|
|
44381
44382
|
}
|
|
44383
|
+
function encodeHeaderValue(value) {
|
|
44384
|
+
return /^[\x20-\x7e]*$/.test(value) ? value : `=?UTF-8?B?${Buffer.from(value, "utf8").toString("base64")}?=`;
|
|
44385
|
+
}
|
|
44386
|
+
function buildRawTextMessage(to, subject, body) {
|
|
44387
|
+
const encodedBody = Buffer.from(body, "utf8").toString("base64").match(/.{1,76}/g)?.join("\r\n") ?? "";
|
|
44388
|
+
return [
|
|
44389
|
+
`To: ${to}`,
|
|
44390
|
+
`Subject: ${encodeHeaderValue(subject)}`,
|
|
44391
|
+
"MIME-Version: 1.0",
|
|
44392
|
+
"Content-Type: text/plain; charset=UTF-8",
|
|
44393
|
+
"Content-Transfer-Encoding: base64",
|
|
44394
|
+
"",
|
|
44395
|
+
encodedBody
|
|
44396
|
+
].join("\r\n");
|
|
44397
|
+
}
|
|
44382
44398
|
function decodeQuotedPrintable(buffer) {
|
|
44383
44399
|
const source = buffer.toString("latin1").replace(/=\r?\n/g, "");
|
|
44384
44400
|
const bytes = [];
|
|
@@ -44637,6 +44653,39 @@ var init_gmail_service = __esm({
|
|
|
44637
44653
|
this.createArtifact = dependencies.createArtifact ?? createConnectedDataBinaryArtifact;
|
|
44638
44654
|
this.createJsonlArtifact = dependencies.createJsonlArtifact ?? createConnectedDataArtifact;
|
|
44639
44655
|
}
|
|
44656
|
+
async sendMessage(args) {
|
|
44657
|
+
const to = args.to.trim().toLowerCase();
|
|
44658
|
+
const subject = args.subject.trim();
|
|
44659
|
+
if (!/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(to) || /[\r\n]/.test(args.to)) throw new GmailServiceError("invalid_request", "A valid recipient email address is required.");
|
|
44660
|
+
if (!subject || subject.length > 500 || /[\r\n]/.test(subject)) throw new GmailServiceError("invalid_request", "A subject of at most 500 characters without line breaks is required.");
|
|
44661
|
+
if (!args.body || args.body.length > 5e4) throw new GmailServiceError("invalid_request", "A plain-text body of at most 50,000 characters is required.");
|
|
44662
|
+
if (args.idempotencyKey.length < 8 || args.idempotencyKey.length > 200) throw new GmailServiceError("idempotency_key_invalid", "Idempotency key must contain 8-200 characters.");
|
|
44663
|
+
const fingerprint3 = gmailFingerprint({ connectionId: args.connectionId, to, subject, bodySha256: (0, import_node_crypto25.createHash)("sha256").update(args.body).digest("hex") });
|
|
44664
|
+
const begun = await beginGmailAction({ ownerId: args.ownerId, idempotencyKey: args.idempotencyKey, fingerprint: fingerprint3 });
|
|
44665
|
+
if (begun.replay && begun.execution.result) return { ...begun.execution.result, replay: true };
|
|
44666
|
+
if (begun.replay) return { actionId: begun.execution.actionId, status: "outcome_unknown", replay: true, retryable: false };
|
|
44667
|
+
const claim = await claimGmailActionChunk(begun.execution.actionId, "send:0");
|
|
44668
|
+
if (!claim.claimed) return { ...claim.receipt.result ?? {}, actionId: begun.execution.actionId, status: claim.receipt.status, replay: true };
|
|
44669
|
+
try {
|
|
44670
|
+
const payload = record(await this.providerCall({
|
|
44671
|
+
identity: args.providerIdentity ?? args.ownerId,
|
|
44672
|
+
connectionId: args.connectionId,
|
|
44673
|
+
method: "POST",
|
|
44674
|
+
path: "/gmail/v1/users/me/messages/send",
|
|
44675
|
+
body: { raw: Buffer.from(buildRawTextMessage(to, subject, args.body), "utf8").toString("base64url") },
|
|
44676
|
+
requestId: args.idempotencyKey
|
|
44677
|
+
}));
|
|
44678
|
+
const result2 = { actionId: begun.execution.actionId, status: "complete", messageId: stringValue(payload?.id), threadId: stringValue(payload?.threadId), replay: false };
|
|
44679
|
+
await finishGmailActionChunk(begun.execution.actionId, "send:0", "complete", result2);
|
|
44680
|
+
await finishGmailAction(begun.execution.actionId, "complete", result2);
|
|
44681
|
+
return result2;
|
|
44682
|
+
} catch (error) {
|
|
44683
|
+
const result2 = { actionId: begun.execution.actionId, status: "outcome_unknown", code: serviceErrorCode(error), retryable: false };
|
|
44684
|
+
await finishGmailActionChunk(begun.execution.actionId, "send:0", "failed", result2);
|
|
44685
|
+
await finishGmailAction(begun.execution.actionId, "partial", result2);
|
|
44686
|
+
throw error;
|
|
44687
|
+
}
|
|
44688
|
+
}
|
|
44640
44689
|
async searchMessages(args) {
|
|
44641
44690
|
const query = args.query.trim();
|
|
44642
44691
|
if (!query || query.length > 2e3) throw new GmailServiceError("invalid_request", "A Gmail query of at most 2,000 characters is required.");
|
|
@@ -45475,6 +45524,21 @@ function gmailFileAssetSaveArguments(args) {
|
|
|
45475
45524
|
idempotencyKey: args.idempotencyKey
|
|
45476
45525
|
};
|
|
45477
45526
|
}
|
|
45527
|
+
function gmailMemoryNoteArguments(args) {
|
|
45528
|
+
const descriptions = {
|
|
45529
|
+
gmail: "Content preserved from an owner-authorized Gmail connection.",
|
|
45530
|
+
"email-import": "A complete email source captured through the Gmail import workflow.",
|
|
45531
|
+
"import-manifest": "A durable manifest recording a completed or partial source import."
|
|
45532
|
+
};
|
|
45533
|
+
return {
|
|
45534
|
+
vault: args.vault,
|
|
45535
|
+
path: args.path,
|
|
45536
|
+
title: args.title,
|
|
45537
|
+
content: args.content,
|
|
45538
|
+
props: { sourceKey: args.sourceKey, capturedAt: args.capturedAt, tags: args.tags, references: args.references ?? [] },
|
|
45539
|
+
tagDescriptions: Object.fromEntries(args.tags.map((tag) => [tag, descriptions[tag] ?? `Gmail import tag: ${tag}.`]))
|
|
45540
|
+
};
|
|
45541
|
+
}
|
|
45478
45542
|
function gmailMemoryAssetToolsForMime(mimeType) {
|
|
45479
45543
|
return mimeType.startsWith("image/") ? { saveTool: "image_asset_save", getTool: "image_asset_get" } : { saveTool: "file_asset_save", getTool: "file_asset_get" };
|
|
45480
45544
|
}
|
|
@@ -45513,7 +45577,7 @@ async function memoryPort(c) {
|
|
|
45513
45577
|
},
|
|
45514
45578
|
async saveNote(args) {
|
|
45515
45579
|
const path6 = `gmail/${(0, import_node_crypto29.createHash)("sha256").update(args.sourceKey).digest("hex")}.md`;
|
|
45516
|
-
const result2 = await memoryCall("putTool", {
|
|
45580
|
+
const result2 = await memoryCall("putTool", gmailMemoryNoteArguments({ ...args, path: path6 }), key2);
|
|
45517
45581
|
if (!result2.ok) throw new GmailMemoryIngestError("memory_note_failed", String(result2.error ?? "Memory note write failed."), 503, true);
|
|
45518
45582
|
return { ...result2, path: path6 };
|
|
45519
45583
|
},
|
|
@@ -54132,7 +54196,7 @@ var PACKAGE_VERSION;
|
|
|
54132
54196
|
var init_version = __esm({
|
|
54133
54197
|
"src/version.ts"() {
|
|
54134
54198
|
"use strict";
|
|
54135
|
-
PACKAGE_VERSION = "0.72.
|
|
54199
|
+
PACKAGE_VERSION = "0.72.5";
|
|
54136
54200
|
}
|
|
54137
54201
|
});
|
|
54138
54202
|
|
|
@@ -105068,7 +105132,7 @@ function settleWithinTickBudget(label, unfinished, work, onDeadlineOrError) {
|
|
|
105068
105132
|
);
|
|
105069
105133
|
});
|
|
105070
105134
|
}
|
|
105071
|
-
var import_resend3, import_node_crypto98, import_hono39, import_hono40, import_factory8, import_cookie2, import_stripe2, secureCookies2, isProduction2, sessionCookieOptions2, requireAllowedOrigin, auth5, sessionAuth, requireIntegrationsTier, requirePaidSchedulingTier, app, deploymentProfile, STRIPE_API_VERSION, SYNC_HARVEST_TIMEOUT_OVERRIDE_MS, CRON_TICK_BUDGET_MS, CRON_TICK_DRAIN_BUDGET_MS;
|
|
105135
|
+
var import_resend3, import_node_crypto98, import_hono39, import_hono40, import_factory8, import_cookie2, import_stripe2, secureCookies2, isProduction2, sessionCookieOptions2, requireAllowedOrigin, auth5, sessionAuth, requireIntegrationsTier, requirePaidSchedulingTier, app, deploymentProfile, STRIPE_API_VERSION, directGmailService, SYNC_HARVEST_TIMEOUT_OVERRIDE_MS, CRON_TICK_BUDGET_MS, CRON_TICK_DRAIN_BUDGET_MS;
|
|
105072
105136
|
var init_server = __esm({
|
|
105073
105137
|
"src/api/server.ts"() {
|
|
105074
105138
|
"use strict";
|
|
@@ -105113,6 +105177,7 @@ var init_server = __esm({
|
|
|
105113
105177
|
init_instagram_routes();
|
|
105114
105178
|
init_reddit_routes();
|
|
105115
105179
|
init_gmail_routes();
|
|
105180
|
+
init_gmail_service();
|
|
105116
105181
|
init_video_routes();
|
|
105117
105182
|
init_maps_routes();
|
|
105118
105183
|
init_trustpilot_routes();
|
|
@@ -105990,6 +106055,7 @@ var init_server = __esm({
|
|
|
105990
106055
|
return scheduleConnectionError(c, err, "Unable to send the Slack message.");
|
|
105991
106056
|
}
|
|
105992
106057
|
});
|
|
106058
|
+
directGmailService = new GmailService();
|
|
105993
106059
|
app.post("/schedule-connections/actions/gmail/send-message", auth5, requireIntegrationsTier, async (c) => {
|
|
105994
106060
|
const user = c.get("user");
|
|
105995
106061
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -105998,13 +106064,15 @@ var init_server = __esm({
|
|
|
105998
106064
|
return c.json({ ok: false, error: "connectionId, to, subject, and body are required." }, 400);
|
|
105999
106065
|
}
|
|
106000
106066
|
try {
|
|
106001
|
-
const result2 = await
|
|
106002
|
-
user.
|
|
106067
|
+
const result2 = await directGmailService.sendMessage({
|
|
106068
|
+
ownerId: (0, import_node_crypto98.createHash)("sha256").update(user.api_key).digest("hex").slice(0, 24),
|
|
106069
|
+
providerIdentity: user.email,
|
|
106003
106070
|
connectionId,
|
|
106004
|
-
|
|
106005
|
-
|
|
106006
|
-
|
|
106007
|
-
|
|
106071
|
+
to: body.to,
|
|
106072
|
+
subject: body.subject,
|
|
106073
|
+
body: body.body,
|
|
106074
|
+
idempotencyKey: connectedActionIdempotencyKey(c)
|
|
106075
|
+
});
|
|
106008
106076
|
return c.json({ ok: true, result: result2 });
|
|
106009
106077
|
} catch (err) {
|
|
106010
106078
|
return scheduleConnectionError(c, err, "Unable to send the email.");
|
package/dist/bin/api-server.js
CHANGED
|
@@ -17,7 +17,7 @@ loadDotEnv();
|
|
|
17
17
|
async function main() {
|
|
18
18
|
const [{ serve }, { app }, { startWorker }, { migrate }] = await Promise.all([
|
|
19
19
|
import("@hono/node-server"),
|
|
20
|
-
import("../server-
|
|
20
|
+
import("../server-IABKDP7V.js"),
|
|
21
21
|
import("../worker-JQORPCFQ.js"),
|
|
22
22
|
import("../db-566MOHHD.js")
|
|
23
23
|
]);
|
|
@@ -112,7 +112,7 @@ function renderInstallTerminal(options) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
// src/version.ts
|
|
115
|
-
var PACKAGE_VERSION = "0.72.
|
|
115
|
+
var PACKAGE_VERSION = "0.72.5";
|
|
116
116
|
|
|
117
117
|
// bin/mcp-scraper-install.ts
|
|
118
118
|
var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "../chunk-RAFQEPJ4.js";
|
|
5
5
|
import {
|
|
6
6
|
PACKAGE_VERSION
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-WHXNA6GK.js";
|
|
8
8
|
|
|
9
9
|
// bin/mcp-scraper-install.ts
|
|
10
10
|
var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
registerScheduledResultsMcpTools,
|
|
14
14
|
registerSerpIntelligenceCaptureTools,
|
|
15
15
|
resolveDeploymentProfile
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-3SECYTNB.js";
|
|
17
17
|
import "../chunk-PGJQDMC2.js";
|
|
18
18
|
import "../chunk-T3MZISOF.js";
|
|
19
19
|
import "../chunk-7RQULQF3.js";
|
|
@@ -26,7 +26,7 @@ import "../chunk-VXLU74YZ.js";
|
|
|
26
26
|
import "../chunk-GGZEC22A.js";
|
|
27
27
|
import {
|
|
28
28
|
PACKAGE_VERSION
|
|
29
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-WHXNA6GK.js";
|
|
30
30
|
import "../chunk-DNM65UCK.js";
|
|
31
31
|
import "../chunk-FVL4GUTP.js";
|
|
32
32
|
import "../chunk-WEFPBAAG.js";
|
|
@@ -755,6 +755,7 @@ var GMAIL_PROXY_PATHS = [
|
|
|
755
755
|
{ method: "GET", pattern: /^\/gmail\/v1\/users\/me\/labels$/ },
|
|
756
756
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/batchModify$/ },
|
|
757
757
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/batchDelete$/ },
|
|
758
|
+
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/send$/ },
|
|
758
759
|
{ method: "POST", pattern: /^\/gmail\/v1\/users\/me\/messages\/[A-Za-z0-9_-]+\/(?:trash|untrash)$/ }
|
|
759
760
|
];
|
|
760
761
|
var GMAIL_QUERY_KEYS = /* @__PURE__ */ new Set(["q", "maxResults", "pageToken", "format", "metadataHeaders", "fields"]);
|
|
@@ -1496,6 +1497,21 @@ function base64urlDecode(value) {
|
|
|
1496
1497
|
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1497
1498
|
return Buffer.from(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="), "base64");
|
|
1498
1499
|
}
|
|
1500
|
+
function encodeHeaderValue(value) {
|
|
1501
|
+
return /^[\x20-\x7e]*$/.test(value) ? value : `=?UTF-8?B?${Buffer.from(value, "utf8").toString("base64")}?=`;
|
|
1502
|
+
}
|
|
1503
|
+
function buildRawTextMessage(to, subject, body) {
|
|
1504
|
+
const encodedBody = Buffer.from(body, "utf8").toString("base64").match(/.{1,76}/g)?.join("\r\n") ?? "";
|
|
1505
|
+
return [
|
|
1506
|
+
`To: ${to}`,
|
|
1507
|
+
`Subject: ${encodeHeaderValue(subject)}`,
|
|
1508
|
+
"MIME-Version: 1.0",
|
|
1509
|
+
"Content-Type: text/plain; charset=UTF-8",
|
|
1510
|
+
"Content-Transfer-Encoding: base64",
|
|
1511
|
+
"",
|
|
1512
|
+
encodedBody
|
|
1513
|
+
].join("\r\n");
|
|
1514
|
+
}
|
|
1499
1515
|
function decodeQuotedPrintable(buffer) {
|
|
1500
1516
|
const source = buffer.toString("latin1").replace(/=\r?\n/g, "");
|
|
1501
1517
|
const bytes = [];
|
|
@@ -1666,6 +1682,39 @@ var GmailService = class {
|
|
|
1666
1682
|
this.createArtifact = dependencies.createArtifact ?? createConnectedDataBinaryArtifact;
|
|
1667
1683
|
this.createJsonlArtifact = dependencies.createJsonlArtifact ?? createConnectedDataArtifact;
|
|
1668
1684
|
}
|
|
1685
|
+
async sendMessage(args) {
|
|
1686
|
+
const to = args.to.trim().toLowerCase();
|
|
1687
|
+
const subject = args.subject.trim();
|
|
1688
|
+
if (!/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(to) || /[\r\n]/.test(args.to)) throw new GmailServiceError("invalid_request", "A valid recipient email address is required.");
|
|
1689
|
+
if (!subject || subject.length > 500 || /[\r\n]/.test(subject)) throw new GmailServiceError("invalid_request", "A subject of at most 500 characters without line breaks is required.");
|
|
1690
|
+
if (!args.body || args.body.length > 5e4) throw new GmailServiceError("invalid_request", "A plain-text body of at most 50,000 characters is required.");
|
|
1691
|
+
if (args.idempotencyKey.length < 8 || args.idempotencyKey.length > 200) throw new GmailServiceError("idempotency_key_invalid", "Idempotency key must contain 8-200 characters.");
|
|
1692
|
+
const fingerprint = gmailFingerprint({ connectionId: args.connectionId, to, subject, bodySha256: createHash4("sha256").update(args.body).digest("hex") });
|
|
1693
|
+
const begun = await beginGmailAction({ ownerId: args.ownerId, idempotencyKey: args.idempotencyKey, fingerprint });
|
|
1694
|
+
if (begun.replay && begun.execution.result) return { ...begun.execution.result, replay: true };
|
|
1695
|
+
if (begun.replay) return { actionId: begun.execution.actionId, status: "outcome_unknown", replay: true, retryable: false };
|
|
1696
|
+
const claim = await claimGmailActionChunk(begun.execution.actionId, "send:0");
|
|
1697
|
+
if (!claim.claimed) return { ...claim.receipt.result ?? {}, actionId: begun.execution.actionId, status: claim.receipt.status, replay: true };
|
|
1698
|
+
try {
|
|
1699
|
+
const payload = record(await this.providerCall({
|
|
1700
|
+
identity: args.providerIdentity ?? args.ownerId,
|
|
1701
|
+
connectionId: args.connectionId,
|
|
1702
|
+
method: "POST",
|
|
1703
|
+
path: "/gmail/v1/users/me/messages/send",
|
|
1704
|
+
body: { raw: Buffer.from(buildRawTextMessage(to, subject, args.body), "utf8").toString("base64url") },
|
|
1705
|
+
requestId: args.idempotencyKey
|
|
1706
|
+
}));
|
|
1707
|
+
const result = { actionId: begun.execution.actionId, status: "complete", messageId: stringValue(payload?.id), threadId: stringValue(payload?.threadId), replay: false };
|
|
1708
|
+
await finishGmailActionChunk(begun.execution.actionId, "send:0", "complete", result);
|
|
1709
|
+
await finishGmailAction(begun.execution.actionId, "complete", result);
|
|
1710
|
+
return result;
|
|
1711
|
+
} catch (error) {
|
|
1712
|
+
const result = { actionId: begun.execution.actionId, status: "outcome_unknown", code: serviceErrorCode(error), retryable: false };
|
|
1713
|
+
await finishGmailActionChunk(begun.execution.actionId, "send:0", "failed", result);
|
|
1714
|
+
await finishGmailAction(begun.execution.actionId, "partial", result);
|
|
1715
|
+
throw error;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1669
1718
|
async searchMessages(args) {
|
|
1670
1719
|
const query = args.query.trim();
|
|
1671
1720
|
if (!query || query.length > 2e3) throw new GmailServiceError("invalid_request", "A Gmail query of at most 2,000 characters is required.");
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
probeNangoConnectionDirect,
|
|
71
71
|
recordNangoConnectionCost,
|
|
72
72
|
settleConnectedUsage
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-K2SXQGKM.js";
|
|
74
74
|
import {
|
|
75
75
|
ANALYTICS_CONTENT_SORTS,
|
|
76
76
|
AnalyticsProviderRegistryError,
|
|
@@ -271,7 +271,7 @@ import {
|
|
|
271
271
|
resolveDeploymentProfile,
|
|
272
272
|
resolveLocalSourcebookSchemaType,
|
|
273
273
|
transcribeMediaUrl
|
|
274
|
-
} from "./chunk-
|
|
274
|
+
} from "./chunk-3SECYTNB.js";
|
|
275
275
|
import {
|
|
276
276
|
auditImageUrls,
|
|
277
277
|
auditImages,
|
|
@@ -336,7 +336,7 @@ import {
|
|
|
336
336
|
} from "./chunk-GGZEC22A.js";
|
|
337
337
|
import {
|
|
338
338
|
PACKAGE_VERSION
|
|
339
|
-
} from "./chunk-
|
|
339
|
+
} from "./chunk-WHXNA6GK.js";
|
|
340
340
|
import {
|
|
341
341
|
SITE_EXTRACT_ARTIFACT_PREFIX,
|
|
342
342
|
abandonExtractSettlement,
|
|
@@ -3845,7 +3845,7 @@ async function generateOgImage(post) {
|
|
|
3845
3845
|
|
|
3846
3846
|
// src/api/server.ts
|
|
3847
3847
|
import { Resend as Resend3 } from "resend";
|
|
3848
|
-
import { randomUUID as randomUUID39 } from "crypto";
|
|
3848
|
+
import { createHash as createHash48, randomUUID as randomUUID39 } from "crypto";
|
|
3849
3849
|
|
|
3850
3850
|
// src/api/kpo-extractor.ts
|
|
3851
3851
|
import TurndownService from "turndown";
|
|
@@ -21938,6 +21938,21 @@ function gmailFileAssetSaveArguments(args) {
|
|
|
21938
21938
|
idempotencyKey: args.idempotencyKey
|
|
21939
21939
|
};
|
|
21940
21940
|
}
|
|
21941
|
+
function gmailMemoryNoteArguments(args) {
|
|
21942
|
+
const descriptions = {
|
|
21943
|
+
gmail: "Content preserved from an owner-authorized Gmail connection.",
|
|
21944
|
+
"email-import": "A complete email source captured through the Gmail import workflow.",
|
|
21945
|
+
"import-manifest": "A durable manifest recording a completed or partial source import."
|
|
21946
|
+
};
|
|
21947
|
+
return {
|
|
21948
|
+
vault: args.vault,
|
|
21949
|
+
path: args.path,
|
|
21950
|
+
title: args.title,
|
|
21951
|
+
content: args.content,
|
|
21952
|
+
props: { sourceKey: args.sourceKey, capturedAt: args.capturedAt, tags: args.tags, references: args.references ?? [] },
|
|
21953
|
+
tagDescriptions: Object.fromEntries(args.tags.map((tag) => [tag, descriptions[tag] ?? `Gmail import tag: ${tag}.`]))
|
|
21954
|
+
};
|
|
21955
|
+
}
|
|
21941
21956
|
function gmailMemoryAssetToolsForMime(mimeType) {
|
|
21942
21957
|
return mimeType.startsWith("image/") ? { saveTool: "image_asset_save", getTool: "image_asset_get" } : { saveTool: "file_asset_save", getTool: "file_asset_get" };
|
|
21943
21958
|
}
|
|
@@ -21976,7 +21991,7 @@ async function memoryPort(c) {
|
|
|
21976
21991
|
},
|
|
21977
21992
|
async saveNote(args) {
|
|
21978
21993
|
const path5 = `gmail/${createHash6("sha256").update(args.sourceKey).digest("hex")}.md`;
|
|
21979
|
-
const result2 = await memoryCall("putTool", {
|
|
21994
|
+
const result2 = await memoryCall("putTool", gmailMemoryNoteArguments({ ...args, path: path5 }), key2);
|
|
21980
21995
|
if (!result2.ok) throw new GmailMemoryIngestError("memory_note_failed", String(result2.error ?? "Memory note write failed."), 503, true);
|
|
21981
21996
|
return { ...result2, path: path5 };
|
|
21982
21997
|
},
|
|
@@ -45764,7 +45779,7 @@ async function callMainOwnedExportPage(identity, input) {
|
|
|
45764
45779
|
});
|
|
45765
45780
|
}
|
|
45766
45781
|
if (connection.providerConfigKey === "google-mail" && input.dataset === "emails") {
|
|
45767
|
-
const { GmailService: GmailService2 } = await import("./gmail-service-
|
|
45782
|
+
const { GmailService: GmailService2 } = await import("./gmail-service-QXDGNWUJ.js");
|
|
45768
45783
|
const service = new GmailService2();
|
|
45769
45784
|
const ownerId3 = createHash27("sha256").update(identity.toLowerCase()).digest("hex").slice(0, 24);
|
|
45770
45785
|
const after = Math.floor(Date.parse(input.from) / 1e3);
|
|
@@ -56776,6 +56791,7 @@ app.post("/schedule-connections/actions/slack/send-message", auth5, requireInteg
|
|
|
56776
56791
|
return scheduleConnectionError(c, err, "Unable to send the Slack message.");
|
|
56777
56792
|
}
|
|
56778
56793
|
});
|
|
56794
|
+
var directGmailService = new GmailService();
|
|
56779
56795
|
app.post("/schedule-connections/actions/gmail/send-message", auth5, requireIntegrationsTier, async (c) => {
|
|
56780
56796
|
const user = c.get("user");
|
|
56781
56797
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -56784,13 +56800,15 @@ app.post("/schedule-connections/actions/gmail/send-message", auth5, requireInteg
|
|
|
56784
56800
|
return c.json({ ok: false, error: "connectionId, to, subject, and body are required." }, 400);
|
|
56785
56801
|
}
|
|
56786
56802
|
try {
|
|
56787
|
-
const result2 = await
|
|
56788
|
-
user.
|
|
56803
|
+
const result2 = await directGmailService.sendMessage({
|
|
56804
|
+
ownerId: createHash48("sha256").update(user.api_key).digest("hex").slice(0, 24),
|
|
56805
|
+
providerIdentity: user.email,
|
|
56789
56806
|
connectionId,
|
|
56790
|
-
|
|
56791
|
-
|
|
56792
|
-
|
|
56793
|
-
|
|
56807
|
+
to: body.to,
|
|
56808
|
+
subject: body.subject,
|
|
56809
|
+
body: body.body,
|
|
56810
|
+
idempotencyKey: connectedActionIdempotencyKey(c)
|
|
56811
|
+
});
|
|
56794
56812
|
return c.json({ ok: true, result: result2 });
|
|
56795
56813
|
} catch (err) {
|
|
56796
56814
|
return scheduleConnectionError(c, err, "Unable to send the email.");
|