mcp-scraper 0.17.0 → 0.18.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/README.md +1 -1
- package/dist/bin/api-server.cjs +424 -40
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +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.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +25 -8
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-LENCALSN.js → chunk-FMEDPBIV.js} +26 -9
- package/dist/chunk-FMEDPBIV.js.map +1 -0
- package/dist/chunk-RLWCHLV3.js +7 -0
- package/dist/chunk-RLWCHLV3.js.map +1 -0
- package/dist/{server-5KTVLL3L.js → server-MQDCAR6I.js} +390 -31
- package/dist/server-MQDCAR6I.js.map +1 -0
- package/docs/mcp-tool-manifest.generated.json +149 -7
- package/package.json +12 -3
- package/dist/chunk-L3FT4JBT.js +0 -7
- package/dist/chunk-L3FT4JBT.js.map +0 -1
- package/dist/chunk-LENCALSN.js.map +0 -1
- package/dist/server-5KTVLL3L.js.map +0 -1
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
renewConnectedDataArtifactDownload,
|
|
38
38
|
sanitizeAttempts,
|
|
39
39
|
sanitizeHarvestResult
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-FMEDPBIV.js";
|
|
41
41
|
import {
|
|
42
42
|
auditImages,
|
|
43
43
|
buildLinkReport,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
RawMapsOverviewSchema,
|
|
74
74
|
RawMapsReviewStatsSchema
|
|
75
75
|
} from "./chunk-XGIPATLV.js";
|
|
76
|
-
import "./chunk-
|
|
76
|
+
import "./chunk-RLWCHLV3.js";
|
|
77
77
|
import {
|
|
78
78
|
completeExtractJob,
|
|
79
79
|
countSuccessfulPages,
|
|
@@ -3506,7 +3506,7 @@ async function generateOgImage(post) {
|
|
|
3506
3506
|
}
|
|
3507
3507
|
|
|
3508
3508
|
// src/api/server.ts
|
|
3509
|
-
import { Resend } from "resend";
|
|
3509
|
+
import { Resend as Resend2 } from "resend";
|
|
3510
3510
|
|
|
3511
3511
|
// src/api/url-utils.ts
|
|
3512
3512
|
import { isIP } from "net";
|
|
@@ -5321,7 +5321,7 @@ async function extractSite(opts) {
|
|
|
5321
5321
|
}
|
|
5322
5322
|
|
|
5323
5323
|
// src/api/server.ts
|
|
5324
|
-
import { Hono as
|
|
5324
|
+
import { Hono as Hono23 } from "hono";
|
|
5325
5325
|
import { serve as serveInngest } from "inngest/hono";
|
|
5326
5326
|
|
|
5327
5327
|
// src/inngest/client.ts
|
|
@@ -19976,6 +19976,238 @@ loadActions();
|
|
|
19976
19976
|
</html>`;
|
|
19977
19977
|
}
|
|
19978
19978
|
|
|
19979
|
+
// src/api/resend-inbound-routes.ts
|
|
19980
|
+
import { Hono as Hono22 } from "hono";
|
|
19981
|
+
import { Resend } from "resend";
|
|
19982
|
+
var SUPPORT_ADDRESS = "support@mcpscraper.dev";
|
|
19983
|
+
var DMARC_ADDRESS = "dmarc@mcpscraper.dev";
|
|
19984
|
+
var FORWARD_FROM = "MCP Scraper Support <support@updates.mcpscraper.dev>";
|
|
19985
|
+
function classifyInboundRecipients(recipients, ...receivingDomains) {
|
|
19986
|
+
const normalized = recipients.map((address) => address.trim().toLowerCase());
|
|
19987
|
+
const domains = receivingDomains.map((domain) => domain?.trim().toLowerCase()).filter((domain) => Boolean(domain));
|
|
19988
|
+
const supportAddresses = [SUPPORT_ADDRESS, ...domains.map((domain) => `support@${domain}`)];
|
|
19989
|
+
const dmarcAddresses = [DMARC_ADDRESS, ...domains.map((domain) => `dmarc@${domain}`)];
|
|
19990
|
+
if (supportAddresses.some((address) => normalized.includes(address))) return "support";
|
|
19991
|
+
if (dmarcAddresses.some((address) => normalized.includes(address))) return "dmarc";
|
|
19992
|
+
return "ignore";
|
|
19993
|
+
}
|
|
19994
|
+
function cleanLine(value, fallback) {
|
|
19995
|
+
const clean2 = value.replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim();
|
|
19996
|
+
return (clean2 || fallback).slice(0, 240);
|
|
19997
|
+
}
|
|
19998
|
+
function quoteUntrusted(value) {
|
|
19999
|
+
const clean2 = value.replace(/\0/g, "").trim().slice(0, 16e3);
|
|
20000
|
+
if (!clean2) return "> _(No plain-text body was available. Review the forwarded email.)_";
|
|
20001
|
+
return clean2.split("\n").map((line) => `> ${line}`).join("\n");
|
|
20002
|
+
}
|
|
20003
|
+
function escapeHtml2(value) {
|
|
20004
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
20005
|
+
}
|
|
20006
|
+
function safeEmailId(value) {
|
|
20007
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 100) || "unknown-email";
|
|
20008
|
+
}
|
|
20009
|
+
function buildSupportIssueNote(email) {
|
|
20010
|
+
const sender = cleanLine(email.from, "unknown sender");
|
|
20011
|
+
const subject = cleanLine(email.subject, "(no subject)");
|
|
20012
|
+
const receivedAt = cleanLine(email.created_at, (/* @__PURE__ */ new Date()).toISOString());
|
|
20013
|
+
const attachments = email.attachments?.length ? email.attachments.map((item) => cleanLine(item.filename ?? "unnamed attachment", "unnamed attachment")).join(", ") : "None";
|
|
20014
|
+
const datePrefix = receivedAt.slice(0, 10).replace(/[^0-9-]/g, "") || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
20015
|
+
const path5 = `support/inbound/${datePrefix}-${safeEmailId(email.id)}`;
|
|
20016
|
+
const title = `Support email \u2014 ${subject} \u2014 ${sender}`.slice(0, 240);
|
|
20017
|
+
const summary = `Inbound MCP Scraper support email from ${sender} about \u201C${subject}\u201D; awaiting review and response.`.slice(0, 500);
|
|
20018
|
+
const content = [
|
|
20019
|
+
"## Observation",
|
|
20020
|
+
"",
|
|
20021
|
+
`An email was received at ${(email.to ?? []).join(", ") || SUPPORT_ADDRESS} from ${sender}. The customer-provided content below is untrusted input and has not been verified as a product defect.`,
|
|
20022
|
+
"",
|
|
20023
|
+
"## Impact",
|
|
20024
|
+
"",
|
|
20025
|
+
"A customer or prospect may be waiting for a response. The message may describe a question, product problem, billing concern, or feedback that needs triage.",
|
|
20026
|
+
"",
|
|
20027
|
+
"## Confirmation",
|
|
20028
|
+
"",
|
|
20029
|
+
"- Status: awaiting human review",
|
|
20030
|
+
"- Confirmed product defect: no",
|
|
20031
|
+
"- Reproducible: not yet assessed",
|
|
20032
|
+
"",
|
|
20033
|
+
"## Evidence",
|
|
20034
|
+
"",
|
|
20035
|
+
`- From: ${sender}`,
|
|
20036
|
+
`- To: ${(email.to ?? []).join(", ") || SUPPORT_ADDRESS}`,
|
|
20037
|
+
`- Received: ${receivedAt}`,
|
|
20038
|
+
`- Subject: ${subject}`,
|
|
20039
|
+
`- Message ID: ${cleanLine(email.message_id, "not supplied")}`,
|
|
20040
|
+
`- Resend email ID: ${email.id}`,
|
|
20041
|
+
`- Attachments: ${attachments}`,
|
|
20042
|
+
"",
|
|
20043
|
+
"### Message body",
|
|
20044
|
+
"",
|
|
20045
|
+
quoteUntrusted(email.text ?? ""),
|
|
20046
|
+
"",
|
|
20047
|
+
"## Resolution",
|
|
20048
|
+
"",
|
|
20049
|
+
"Pending review and a reply to the sender. If this is a confirmed product issue, update the note status and link the eventual Improvement Log receipt.",
|
|
20050
|
+
"",
|
|
20051
|
+
"## Tasks",
|
|
20052
|
+
"",
|
|
20053
|
+
"- [ ] Review the forwarded email and attachments.",
|
|
20054
|
+
"- [ ] Reply to the sender.",
|
|
20055
|
+
"- [ ] Confirm whether this is a product defect, question, billing concern, or feedback.",
|
|
20056
|
+
"- [ ] Link any resulting task or Improvement Log receipt.",
|
|
20057
|
+
"",
|
|
20058
|
+
"## Links",
|
|
20059
|
+
"",
|
|
20060
|
+
"_No automatic links were added; support messages should be linked during human triage to avoid false relationships._"
|
|
20061
|
+
].join("\n");
|
|
20062
|
+
return { path: path5, title, content, summary };
|
|
20063
|
+
}
|
|
20064
|
+
async function captureSupportIssue(email, memoryKey) {
|
|
20065
|
+
const note = buildSupportIssueNote(email);
|
|
20066
|
+
const tagCandidates = [
|
|
20067
|
+
{ tag: "customer-support", central: true, reusable: true, description: "Inbound and in-product MCP Scraper customer support requests." },
|
|
20068
|
+
{ tag: "inbound-email", central: true, reusable: true, description: "Messages received through an inbound email integration." },
|
|
20069
|
+
{ tag: "product-feedback", central: true, reusable: true, description: "Customer feedback and reported product problems." }
|
|
20070
|
+
];
|
|
20071
|
+
const prepared = await memoryCall("prepareMemoryWriteTool", {
|
|
20072
|
+
title: note.title,
|
|
20073
|
+
content: note.content,
|
|
20074
|
+
source: `resend:email:${email.id}`,
|
|
20075
|
+
type: "user_friction",
|
|
20076
|
+
vault: "Issues",
|
|
20077
|
+
tagCandidates,
|
|
20078
|
+
maxLinks: 4
|
|
20079
|
+
}, memoryKey);
|
|
20080
|
+
if (!prepared.ok) throw new Error(prepared.error ?? "memory preparation failed");
|
|
20081
|
+
const resolvedTags = (prepared.tagResolutions ?? []).filter((item) => item.action !== "omit").map((item) => item.tag ?? item.candidate).filter((tag) => Boolean(tag));
|
|
20082
|
+
const capture = await memoryCall("memoryCaptureTool", {
|
|
20083
|
+
vault: "Issues",
|
|
20084
|
+
path: note.path,
|
|
20085
|
+
title: note.title,
|
|
20086
|
+
content: note.content,
|
|
20087
|
+
props: {
|
|
20088
|
+
status: "ai_observed",
|
|
20089
|
+
summary: note.summary,
|
|
20090
|
+
tags: resolvedTags,
|
|
20091
|
+
pinned: false,
|
|
20092
|
+
source_type: "channel",
|
|
20093
|
+
source_ref: `resend:email:${email.id}`,
|
|
20094
|
+
related: [],
|
|
20095
|
+
related_vault_notes: [],
|
|
20096
|
+
embed: true,
|
|
20097
|
+
embed_priority: "high",
|
|
20098
|
+
embedding_summary: note.summary,
|
|
20099
|
+
type: "user_friction",
|
|
20100
|
+
severity: "untriaged",
|
|
20101
|
+
system: "MCP Scraper customer support",
|
|
20102
|
+
observed_at: email.created_at,
|
|
20103
|
+
detected_by: "resend-email-webhook",
|
|
20104
|
+
reproducible: false
|
|
20105
|
+
},
|
|
20106
|
+
tagDecisions: tagCandidates
|
|
20107
|
+
}, memoryKey);
|
|
20108
|
+
if (capture.ok) return capture.note?.path ?? note.path;
|
|
20109
|
+
if (capture.conflict) {
|
|
20110
|
+
const existing = await memoryCall("getTool", { vault: "Issues", path: note.path }, memoryKey);
|
|
20111
|
+
if (existing.ok) return note.path;
|
|
20112
|
+
}
|
|
20113
|
+
throw new Error(capture.error ?? "memory capture failed");
|
|
20114
|
+
}
|
|
20115
|
+
async function forwardReceivedEmail(resend, email, destination, label) {
|
|
20116
|
+
const attachmentResult = await resend.emails.receiving.attachments.list({ emailId: email.id });
|
|
20117
|
+
if (attachmentResult.error) throw new Error(`attachment retrieval failed: ${attachmentResult.error.message}`);
|
|
20118
|
+
const attachments = (attachmentResult.data?.data ?? []).filter((item) => item.content_disposition !== "inline").map((item) => ({
|
|
20119
|
+
path: item.download_url,
|
|
20120
|
+
filename: item.filename ?? "attachment",
|
|
20121
|
+
contentId: item.content_id
|
|
20122
|
+
}));
|
|
20123
|
+
const sender = email.reply_to?.[0] || email.from;
|
|
20124
|
+
const subject = cleanLine(email.subject, "(no subject)");
|
|
20125
|
+
const headerText = [
|
|
20126
|
+
`${label} message received at ${(email.to ?? []).join(", ")}`,
|
|
20127
|
+
`From: ${email.from}`,
|
|
20128
|
+
`Reply to: ${sender}`,
|
|
20129
|
+
`Received: ${email.created_at}`,
|
|
20130
|
+
""
|
|
20131
|
+
].join("\n");
|
|
20132
|
+
const headerHtml = [
|
|
20133
|
+
'<div style="font-family:Arial,sans-serif;font-size:13px;line-height:1.5;color:#5f5a54;border-bottom:1px solid #e9e4db;padding-bottom:12px;margin-bottom:18px">',
|
|
20134
|
+
`<strong>${label} message received</strong><br>`,
|
|
20135
|
+
`From: ${escapeHtml2(email.from)}<br>`,
|
|
20136
|
+
`Reply to: ${escapeHtml2(sender)}<br>`,
|
|
20137
|
+
`Received: ${escapeHtml2(email.created_at)}`,
|
|
20138
|
+
"</div>"
|
|
20139
|
+
].join("");
|
|
20140
|
+
const sent = await resend.emails.send({
|
|
20141
|
+
from: FORWARD_FROM,
|
|
20142
|
+
to: destination,
|
|
20143
|
+
replyTo: sender,
|
|
20144
|
+
subject: `[${label}] ${subject}`,
|
|
20145
|
+
text: `${headerText}${email.text || "(HTML-only message; view the HTML version.)"}`,
|
|
20146
|
+
html: email.html ? `${headerHtml}${email.html}` : void 0,
|
|
20147
|
+
attachments: attachments.length ? attachments : void 0,
|
|
20148
|
+
tags: [
|
|
20149
|
+
{ name: "category", value: label === "Support" ? "support_forward" : "dmarc_report" },
|
|
20150
|
+
{ name: "inbound_id", value: safeEmailId(email.id) }
|
|
20151
|
+
]
|
|
20152
|
+
}, { idempotencyKey: `mcp-inbound-${label.toLowerCase()}-${safeEmailId(email.id)}` });
|
|
20153
|
+
if (sent.error) throw new Error(`forward failed: ${sent.error.message}`);
|
|
20154
|
+
return sent.data.id;
|
|
20155
|
+
}
|
|
20156
|
+
var resendInboundApp = new Hono22();
|
|
20157
|
+
resendInboundApp.post("/webhooks", async (c) => {
|
|
20158
|
+
const apiKey = process.env.RESEND_API_KEY?.trim();
|
|
20159
|
+
const webhookSecret = process.env.RESEND_WEBHOOK_SECRET?.trim();
|
|
20160
|
+
if (!apiKey || !webhookSecret) return c.json({ error: "inbound email is not configured" }, 503);
|
|
20161
|
+
const rawBody = await c.req.text();
|
|
20162
|
+
const resend = new Resend(apiKey);
|
|
20163
|
+
let event;
|
|
20164
|
+
try {
|
|
20165
|
+
event = resend.webhooks.verify({
|
|
20166
|
+
payload: rawBody,
|
|
20167
|
+
headers: {
|
|
20168
|
+
id: c.req.header("svix-id") ?? "",
|
|
20169
|
+
timestamp: c.req.header("svix-timestamp") ?? "",
|
|
20170
|
+
signature: c.req.header("svix-signature") ?? ""
|
|
20171
|
+
},
|
|
20172
|
+
webhookSecret
|
|
20173
|
+
});
|
|
20174
|
+
} catch {
|
|
20175
|
+
return c.json({ error: "invalid webhook signature" }, 400);
|
|
20176
|
+
}
|
|
20177
|
+
if (event.type !== "email.received") return c.json({ ok: true, ignored: true });
|
|
20178
|
+
const receivedEvent = event;
|
|
20179
|
+
const route = classifyInboundRecipients(
|
|
20180
|
+
receivedEvent.data.to ?? [],
|
|
20181
|
+
process.env.RESEND_RECEIVING_DOMAIN,
|
|
20182
|
+
process.env.RESEND_MANAGED_RECEIVING_DOMAIN
|
|
20183
|
+
);
|
|
20184
|
+
if (route === "ignore") return c.json({ ok: true, ignored: true });
|
|
20185
|
+
const received = await resend.emails.receiving.get(receivedEvent.data.email_id);
|
|
20186
|
+
if (received.error || !received.data) {
|
|
20187
|
+
console.error("[resend/inbound] could not retrieve received email", receivedEvent.data.email_id);
|
|
20188
|
+
return c.json({ error: "received email could not be retrieved" }, 502);
|
|
20189
|
+
}
|
|
20190
|
+
try {
|
|
20191
|
+
if (route === "support") {
|
|
20192
|
+
const destination2 = process.env.SUPPORT_FORWARD_TO?.trim();
|
|
20193
|
+
const memoryKey = process.env.SUPPORT_INBOX_MEMORY_KEY?.trim();
|
|
20194
|
+
if (!destination2 || !memoryKey) return c.json({ error: "support routing is not configured" }, 503);
|
|
20195
|
+
const [forwardedId2, memoryPath] = await Promise.all([
|
|
20196
|
+
forwardReceivedEmail(resend, received.data, destination2, "Support"),
|
|
20197
|
+
captureSupportIssue(received.data, memoryKey)
|
|
20198
|
+
]);
|
|
20199
|
+
return c.json({ ok: true, route, forwardedId: forwardedId2, memoryPath });
|
|
20200
|
+
}
|
|
20201
|
+
const destination = process.env.DMARC_FORWARD_TO?.trim() || process.env.SUPPORT_FORWARD_TO?.trim();
|
|
20202
|
+
if (!destination) return c.json({ error: "DMARC routing is not configured" }, 503);
|
|
20203
|
+
const forwardedId = await forwardReceivedEmail(resend, received.data, destination, "DMARC");
|
|
20204
|
+
return c.json({ ok: true, route, forwardedId });
|
|
20205
|
+
} catch (err) {
|
|
20206
|
+
console.error("[resend/inbound] processing failed", receivedEvent.data.email_id, err instanceof Error ? err.message : String(err));
|
|
20207
|
+
return c.json({ error: "inbound email processing failed" }, 502);
|
|
20208
|
+
}
|
|
20209
|
+
});
|
|
20210
|
+
|
|
19979
20211
|
// src/api/site-audit-worker.ts
|
|
19980
20212
|
var MAX_CONCURRENT_SITE_AUDIT = 1;
|
|
19981
20213
|
async function drainSiteAuditQueue(budget) {
|
|
@@ -20446,6 +20678,7 @@ var CONNECTED_DATA_DATASETS = [
|
|
|
20446
20678
|
"calendar_events",
|
|
20447
20679
|
"zoom_recordings",
|
|
20448
20680
|
"zoom_transcripts",
|
|
20681
|
+
"meta_ads_insights",
|
|
20449
20682
|
"resend_data",
|
|
20450
20683
|
"resend_emails",
|
|
20451
20684
|
"resend_received_emails",
|
|
@@ -20918,6 +21151,24 @@ var CONNECTION_SYNC_REQUIRED_TOOLS = {
|
|
|
20918
21151
|
"get-broadcast",
|
|
20919
21152
|
"list-templates",
|
|
20920
21153
|
"get-template"
|
|
21154
|
+
],
|
|
21155
|
+
"meta-marketing-api": [
|
|
21156
|
+
"list-ad-accounts",
|
|
21157
|
+
"list-campaigns",
|
|
21158
|
+
"list-ad-sets",
|
|
21159
|
+
"list-ads",
|
|
21160
|
+
"list-ad-creatives",
|
|
21161
|
+
"get-insights"
|
|
21162
|
+
]
|
|
21163
|
+
};
|
|
21164
|
+
var CONNECTION_SYNC_OPTIONAL_TOOLS = {
|
|
21165
|
+
"meta-marketing-api": [
|
|
21166
|
+
"list-catalogs",
|
|
21167
|
+
"list-datasets",
|
|
21168
|
+
"list-custom-audiences",
|
|
21169
|
+
"list-ad-images",
|
|
21170
|
+
"list-ad-videos",
|
|
21171
|
+
"list-ad-rules"
|
|
20921
21172
|
]
|
|
20922
21173
|
};
|
|
20923
21174
|
function connectionSyncPolicyIssues(selections) {
|
|
@@ -20933,8 +21184,11 @@ function connectionSyncPolicyIssues(selections) {
|
|
|
20933
21184
|
if (missingTools.length > 0) {
|
|
20934
21185
|
issues.push({ providerConfigKey: selection.providerConfigKey, code: "missing_required_tools", missingTools });
|
|
20935
21186
|
}
|
|
20936
|
-
const
|
|
20937
|
-
|
|
21187
|
+
const permittedSet = /* @__PURE__ */ new Set([
|
|
21188
|
+
...required,
|
|
21189
|
+
...CONNECTION_SYNC_OPTIONAL_TOOLS[selection.providerConfigKey] ?? []
|
|
21190
|
+
]);
|
|
21191
|
+
const unexpectedTools = [...allowed].filter((tool) => !permittedSet.has(tool));
|
|
20938
21192
|
if (unexpectedTools.length > 0) {
|
|
20939
21193
|
issues.push({ providerConfigKey: selection.providerConfigKey, code: "unexpected_tools", unexpectedTools });
|
|
20940
21194
|
}
|
|
@@ -21043,7 +21297,10 @@ var SAFE_CONTROL_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
21043
21297
|
"tool_discovery_failed",
|
|
21044
21298
|
"live_tool_missing",
|
|
21045
21299
|
"connection_transport_unavailable",
|
|
21046
|
-
"connection_control_failed"
|
|
21300
|
+
"connection_control_failed",
|
|
21301
|
+
"missing_provider_permission",
|
|
21302
|
+
"permission_verification_unavailable",
|
|
21303
|
+
"meta_app_feature_not_enabled"
|
|
21047
21304
|
]);
|
|
21048
21305
|
var CONTROL_ERROR_CODE_ALIASES = /* @__PURE__ */ new Map([
|
|
21049
21306
|
["connection_not_active", "connection_inactive"],
|
|
@@ -21159,6 +21416,27 @@ async function getNangoCatalog() {
|
|
|
21159
21416
|
const safeDefaultAllowedTools = cleanTools(
|
|
21160
21417
|
row.safeDefaultAllowedTools ?? row.safe_default_allowed_tools ?? row.defaultAllowedTools ?? row.default_allowed_tools ?? row.allowedTools ?? row.allowed_tools
|
|
21161
21418
|
).filter((tool) => !disabledTools?.has(tool));
|
|
21419
|
+
const actionTools = cleanTools(
|
|
21420
|
+
row.actionTools ?? row.action_tools ?? row.writeTools ?? row.write_tools
|
|
21421
|
+
).filter((tool) => !disabledTools?.has(tool));
|
|
21422
|
+
const requiredPermissionsByTool = {};
|
|
21423
|
+
const rawRequiredPermissions = row.requiredPermissionsByTool ?? row.required_permissions_by_tool;
|
|
21424
|
+
if (isRecord2(rawRequiredPermissions)) {
|
|
21425
|
+
for (const [tool, permissions] of Object.entries(rawRequiredPermissions).slice(0, 500)) {
|
|
21426
|
+
const cleanTool = cleanString(tool, 200);
|
|
21427
|
+
if (!cleanTool || !safeDefaultAllowedTools.includes(cleanTool) && !actionTools.includes(cleanTool)) continue;
|
|
21428
|
+
requiredPermissionsByTool[cleanTool] = cleanStringArray(permissions, 32, 200);
|
|
21429
|
+
}
|
|
21430
|
+
}
|
|
21431
|
+
const requiredFeaturesByTool = {};
|
|
21432
|
+
const rawRequiredFeatures = row.requiredFeaturesByTool ?? row.required_features_by_tool;
|
|
21433
|
+
if (isRecord2(rawRequiredFeatures)) {
|
|
21434
|
+
for (const [tool, features] of Object.entries(rawRequiredFeatures).slice(0, 500)) {
|
|
21435
|
+
const cleanTool = cleanString(tool, 200);
|
|
21436
|
+
if (!cleanTool) continue;
|
|
21437
|
+
requiredFeaturesByTool[cleanTool] = cleanStringArray(features, 32, 200);
|
|
21438
|
+
}
|
|
21439
|
+
}
|
|
21162
21440
|
const platformSetupStatus = firstString(row, [
|
|
21163
21441
|
"platformSetupStatus",
|
|
21164
21442
|
"platform_setup_status",
|
|
@@ -21168,6 +21446,7 @@ async function getNangoCatalog() {
|
|
|
21168
21446
|
const appReviewStatus = row.appReviewLimited === true || row.app_review_limited === true ? "limited" : firstString(row, ["appReviewStatus", "app_review_status", "reviewStatus", "review_status"], 100);
|
|
21169
21447
|
const appReviewNote = firstString(row, ["appReviewNote", "app_review_note", "reviewNote", "review_note"], 500);
|
|
21170
21448
|
const connectionSyncRequiredTools = [...CONNECTION_SYNC_REQUIRED_TOOLS[providerConfigKey] ?? []];
|
|
21449
|
+
const connectionSyncOptionalTools = [...CONNECTION_SYNC_OPTIONAL_TOOLS[providerConfigKey] ?? []];
|
|
21171
21450
|
result.push({
|
|
21172
21451
|
providerConfigKey,
|
|
21173
21452
|
provider,
|
|
@@ -21178,8 +21457,13 @@ async function getNangoCatalog() {
|
|
|
21178
21457
|
authMode,
|
|
21179
21458
|
categories,
|
|
21180
21459
|
safeDefaultAllowedTools,
|
|
21460
|
+
actionTools,
|
|
21461
|
+
requiredPermissionsByTool,
|
|
21462
|
+
requiredFeaturesByTool,
|
|
21463
|
+
enabledFeatures: cleanStringArray(row.enabledFeatures ?? row.enabled_features, 32, 200),
|
|
21181
21464
|
connectionSyncSupported: connectionSyncRequiredTools.length > 0,
|
|
21182
21465
|
connectionSyncRequiredTools,
|
|
21466
|
+
connectionSyncOptionalTools,
|
|
21183
21467
|
platformSetupStatus,
|
|
21184
21468
|
appReviewStatus,
|
|
21185
21469
|
appReviewNote
|
|
@@ -21201,6 +21485,30 @@ async function getNangoConnections(identity) {
|
|
|
21201
21485
|
const label = firstString(row, ["label", "accountLabel", "account_label", "displayName", "display_name", "endUserEmail", "end_user_email"]) || providerConfigKey;
|
|
21202
21486
|
const rawStatus = firstString(row, ["status"], 64) || "connected";
|
|
21203
21487
|
const reconnectRequired = row.reconnectRequired === true || row.reconnect_required === true || rawStatus === "needs_reauth" || rawStatus === "reauth_required" || rawStatus === "invalid" || rawStatus === "error" || rawStatus === "revoked" || rawStatus === "disabled";
|
|
21488
|
+
const toolCapabilities = [];
|
|
21489
|
+
const rawToolCapabilities = row.toolCapabilities ?? row.tool_capabilities;
|
|
21490
|
+
if (Array.isArray(rawToolCapabilities)) {
|
|
21491
|
+
for (const value of rawToolCapabilities.slice(0, 500)) {
|
|
21492
|
+
if (!isRecord2(value)) continue;
|
|
21493
|
+
const name = cleanString(value.name, 200);
|
|
21494
|
+
const classification = value.classification;
|
|
21495
|
+
const blockedValue = Object.prototype.hasOwnProperty.call(value, "blockedReason") ? value.blockedReason : value.blocked_reason;
|
|
21496
|
+
const blockedReason = blockedValue === null ? null : blockedValue === "missing_permission" || blockedValue === "permission_policy_missing" || blockedValue === "permission_verification_unavailable" || blockedValue === "missing_app_feature" ? blockedValue : void 0;
|
|
21497
|
+
if (!name || classification !== "read" && classification !== "action" || typeof value.available !== "boolean" || blockedReason === void 0) continue;
|
|
21498
|
+
toolCapabilities.push({
|
|
21499
|
+
name,
|
|
21500
|
+
classification,
|
|
21501
|
+
requiredPermissions: cleanStringArray(value.requiredPermissions ?? value.required_permissions, 32, 200),
|
|
21502
|
+
requiredFeatures: cleanStringArray(value.requiredFeatures ?? value.required_features, 32, 200),
|
|
21503
|
+
available: value.available,
|
|
21504
|
+
blockedReason,
|
|
21505
|
+
missingPermissions: cleanStringArray(value.missingPermissions ?? value.missing_permissions, 32, 200),
|
|
21506
|
+
missingFeatures: cleanStringArray(value.missingFeatures ?? value.missing_features, 32, 200)
|
|
21507
|
+
});
|
|
21508
|
+
}
|
|
21509
|
+
}
|
|
21510
|
+
const permissionVerificationValue = row.permissionVerification ?? row.permission_verification;
|
|
21511
|
+
const permissionVerification = permissionVerificationValue === "verified" || permissionVerificationValue === "unavailable" ? permissionVerificationValue : null;
|
|
21204
21512
|
result.push({
|
|
21205
21513
|
connectionId,
|
|
21206
21514
|
providerConfigKey,
|
|
@@ -21211,6 +21519,10 @@ async function getNangoConnections(identity) {
|
|
|
21211
21519
|
actionsEnabled: row.actionsEnabled === true || row.actions_enabled === true,
|
|
21212
21520
|
readTools: cleanTools(row.readTools ?? row.read_tools),
|
|
21213
21521
|
actionTools: cleanTools(row.actionTools ?? row.action_tools ?? row.writeTools ?? row.write_tools),
|
|
21522
|
+
toolCapabilities,
|
|
21523
|
+
grantedPermissions: cleanStringArray(row.grantedPermissions ?? row.granted_permissions, 64, 200),
|
|
21524
|
+
enabledFeatures: cleanStringArray(row.enabledFeatures ?? row.enabled_features, 32, 200),
|
|
21525
|
+
permissionVerification,
|
|
21214
21526
|
mcpEndpoint: null,
|
|
21215
21527
|
schemaDiscovery: "compatibility_describe",
|
|
21216
21528
|
toolRevision: firstString(row, ["toolRevision", "tool_revision"], 200),
|
|
@@ -21438,7 +21750,7 @@ async function describeNangoTool(identity, connectionId, tool, fresh) {
|
|
|
21438
21750
|
const outputSchemaValue = rawTool.outputSchema ?? rawTool.output_schema;
|
|
21439
21751
|
const outputSchema = outputSchemaValue === void 0 ? void 0 : sanitizeToolSchema(outputSchemaValue);
|
|
21440
21752
|
const blockedReasonValue = rawTool.blockedReason ?? rawTool.blocked_reason;
|
|
21441
|
-
const blockedReason = blockedReasonValue === null || blockedReasonValue === void 0 ? null : blockedReasonValue === "actions_disabled" || blockedReasonValue === "inactive_connection" ? blockedReasonValue : void 0;
|
|
21753
|
+
const blockedReason = blockedReasonValue === null || blockedReasonValue === void 0 ? null : blockedReasonValue === "actions_disabled" || blockedReasonValue === "inactive_connection" || blockedReasonValue === "missing_permission" || blockedReasonValue === "missing_app_feature" || blockedReasonValue === "permission_policy_missing" || blockedReasonValue === "permission_verification_unavailable" ? blockedReasonValue : void 0;
|
|
21442
21754
|
if (serializedBytes > 256 * 1024 || !name || name !== tool || classification !== "read" && classification !== "action" || typeof rawTool.callable !== "boolean" || blockedReason === void 0 || transport !== "nango" && transport !== "remote_mcp" || !providerConfigKey || schemaSource !== "live_tools_list" || !upstreamSchemaHash || !/^[a-f0-9]{64}$/i.test(upstreamSchemaHash) || !fetchedAt || Number.isNaN(Date.parse(fetchedAt)) || !inputSchema || outputSchemaValue !== void 0 && !outputSchema) {
|
|
21443
21755
|
throw new NangoControlError(
|
|
21444
21756
|
"The connection service returned an invalid live tool description.",
|
|
@@ -21455,6 +21767,10 @@ async function describeNangoTool(identity, connectionId, tool, fresh) {
|
|
|
21455
21767
|
const annotations = sanitizeToolAnnotations(rawTool.annotations);
|
|
21456
21768
|
const icons = sanitizeToolIcons(rawTool.icons);
|
|
21457
21769
|
const execution = taskSupport ? { taskSupport } : void 0;
|
|
21770
|
+
const requiredPermissions = cleanStringArray(rawTool.requiredPermissions ?? rawTool.required_permissions, 32, 200);
|
|
21771
|
+
const missingPermissions = cleanStringArray(rawTool.missingPermissions ?? rawTool.missing_permissions, 32, 200);
|
|
21772
|
+
const requiredFeatures = cleanStringArray(rawTool.requiredFeatures ?? rawTool.required_features, 32, 200);
|
|
21773
|
+
const missingFeatures = cleanStringArray(rawTool.missingFeatures ?? rawTool.missing_features, 32, 200);
|
|
21458
21774
|
const schemaHash = projectedToolSchemaHash({
|
|
21459
21775
|
name,
|
|
21460
21776
|
inputSchema,
|
|
@@ -21472,6 +21788,10 @@ async function describeNangoTool(identity, connectionId, tool, fresh) {
|
|
|
21472
21788
|
classification,
|
|
21473
21789
|
callable: rawTool.callable,
|
|
21474
21790
|
blockedReason,
|
|
21791
|
+
requiredPermissions,
|
|
21792
|
+
missingPermissions,
|
|
21793
|
+
requiredFeatures,
|
|
21794
|
+
missingFeatures,
|
|
21475
21795
|
transport,
|
|
21476
21796
|
providerConfigKey,
|
|
21477
21797
|
protocolVersion,
|
|
@@ -21912,7 +22232,18 @@ var sessionAuth = createMiddleware3(async (c, next) => {
|
|
|
21912
22232
|
c.set("sessionUser", { ...refreshed, balance_mc: balanceMc });
|
|
21913
22233
|
return next();
|
|
21914
22234
|
});
|
|
21915
|
-
var
|
|
22235
|
+
var requireIntegrationsTier = createMiddleware3(async (c, next) => {
|
|
22236
|
+
const user = c.get("user");
|
|
22237
|
+
if (!user.subscription_tier) {
|
|
22238
|
+
return c.json({
|
|
22239
|
+
ok: false,
|
|
22240
|
+
error: "Integrations require an active Starter plan or higher.",
|
|
22241
|
+
code: "subscription_required"
|
|
22242
|
+
}, 403);
|
|
22243
|
+
}
|
|
22244
|
+
return next();
|
|
22245
|
+
});
|
|
22246
|
+
var app = new Hono23();
|
|
21916
22247
|
var STRIPE_API_VERSION = "2026-02-25.clover";
|
|
21917
22248
|
function requireStripeSecret() {
|
|
21918
22249
|
const secret2 = process.env.STRIPE_SECRET_KEY?.trim();
|
|
@@ -22080,7 +22411,7 @@ app.post("/auth/forgot-password", requireAllowedOrigin, async (c) => {
|
|
|
22080
22411
|
const resetUrl = `${appUrl}/reset-password?token=${token}`;
|
|
22081
22412
|
if (process.env.RESEND_API_KEY) {
|
|
22082
22413
|
try {
|
|
22083
|
-
const resend = new
|
|
22414
|
+
const resend = new Resend2(process.env.RESEND_API_KEY);
|
|
22084
22415
|
const sent = await resend.emails.send({
|
|
22085
22416
|
from: "MCP Scraper <noreply@updates.mcpscraper.dev>",
|
|
22086
22417
|
to: normalizedEmail,
|
|
@@ -22136,9 +22467,11 @@ app.get("/me", async (c) => {
|
|
|
22136
22467
|
return c.json({ authenticated: false });
|
|
22137
22468
|
}
|
|
22138
22469
|
const refreshed = await applyMonthlyFreeRefresh(foundUser);
|
|
22139
|
-
const balanceMc = await
|
|
22470
|
+
const [balanceMc, stats] = await Promise.all([
|
|
22471
|
+
reconcileBalanceMc(refreshed.id),
|
|
22472
|
+
getUserStats(refreshed.id)
|
|
22473
|
+
]);
|
|
22140
22474
|
const user = { ...refreshed, balance_mc: balanceMc };
|
|
22141
|
-
const stats = await getUserStats(user.id);
|
|
22142
22475
|
return c.json({
|
|
22143
22476
|
authenticated: true,
|
|
22144
22477
|
id: user.id,
|
|
@@ -22508,7 +22841,34 @@ async function combinedConnections(identity) {
|
|
|
22508
22841
|
if (nango.status === "rejected" && resend.status === "rejected") throw nango.reason;
|
|
22509
22842
|
return [
|
|
22510
22843
|
...nango.status === "fulfilled" ? nango.value.map((connection) => ({ ...connection, transport: "nango", adminBlockedTools: [] })) : [],
|
|
22511
|
-
...resend.status === "fulfilled" ? resend.value
|
|
22844
|
+
...resend.status === "fulfilled" ? resend.value.map((connection) => ({
|
|
22845
|
+
...connection,
|
|
22846
|
+
toolCapabilities: [
|
|
22847
|
+
...connection.readTools.map((name) => ({
|
|
22848
|
+
name,
|
|
22849
|
+
classification: "read",
|
|
22850
|
+
requiredPermissions: [],
|
|
22851
|
+
requiredFeatures: [],
|
|
22852
|
+
available: true,
|
|
22853
|
+
blockedReason: null,
|
|
22854
|
+
missingPermissions: [],
|
|
22855
|
+
missingFeatures: []
|
|
22856
|
+
})),
|
|
22857
|
+
...connection.actionTools.map((name) => ({
|
|
22858
|
+
name,
|
|
22859
|
+
classification: "action",
|
|
22860
|
+
requiredPermissions: [],
|
|
22861
|
+
requiredFeatures: [],
|
|
22862
|
+
available: true,
|
|
22863
|
+
blockedReason: null,
|
|
22864
|
+
missingPermissions: [],
|
|
22865
|
+
missingFeatures: []
|
|
22866
|
+
}))
|
|
22867
|
+
],
|
|
22868
|
+
grantedPermissions: [],
|
|
22869
|
+
enabledFeatures: [],
|
|
22870
|
+
permissionVerification: null
|
|
22871
|
+
})) : []
|
|
22512
22872
|
];
|
|
22513
22873
|
}
|
|
22514
22874
|
async function isResendConnection(identity, connectionId, providerHint) {
|
|
@@ -22554,7 +22914,7 @@ app.get("/schedule-connections", auth2, async (c) => {
|
|
|
22554
22914
|
return scheduleConnectionError(c, err, "Unable to load service connections.");
|
|
22555
22915
|
}
|
|
22556
22916
|
});
|
|
22557
|
-
app.post("/schedule-connections/session", auth2, async (c) => {
|
|
22917
|
+
app.post("/schedule-connections/session", auth2, requireIntegrationsTier, async (c) => {
|
|
22558
22918
|
const user = c.get("user");
|
|
22559
22919
|
const body = await c.req.json().catch(() => ({}));
|
|
22560
22920
|
const providerConfigKey = providerConfigKeyFrom(body.providerConfigKey);
|
|
@@ -22566,7 +22926,7 @@ app.post("/schedule-connections/session", auth2, async (c) => {
|
|
|
22566
22926
|
return scheduleConnectionError(c, err, "Unable to start the service connection flow.");
|
|
22567
22927
|
}
|
|
22568
22928
|
});
|
|
22569
|
-
app.post("/schedule-connections/:id/reconnect-session", auth2, async (c) => {
|
|
22929
|
+
app.post("/schedule-connections/:id/reconnect-session", auth2, requireIntegrationsTier, async (c) => {
|
|
22570
22930
|
const user = c.get("user");
|
|
22571
22931
|
const body = await c.req.json().catch(() => ({}));
|
|
22572
22932
|
const providerConfigKey = providerConfigKeyFrom(body.providerConfigKey);
|
|
@@ -22591,7 +22951,7 @@ app.delete("/schedule-connections/:id", auth2, async (c) => {
|
|
|
22591
22951
|
return scheduleConnectionError(c, err, "Unable to disconnect this service connection.");
|
|
22592
22952
|
}
|
|
22593
22953
|
});
|
|
22594
|
-
app.post("/schedule-connections/:id/enable-actions", auth2, async (c) => {
|
|
22954
|
+
app.post("/schedule-connections/:id/enable-actions", auth2, requireIntegrationsTier, async (c) => {
|
|
22595
22955
|
const user = c.get("user");
|
|
22596
22956
|
const body = await c.req.json().catch(() => ({}));
|
|
22597
22957
|
if (typeof body.enabled !== "boolean") return c.json({ ok: false, error: "enabled must be a boolean." }, 400);
|
|
@@ -22627,7 +22987,7 @@ app.get("/oauth/resend/callback", async (c) => {
|
|
|
22627
22987
|
return c.html(renderResendOAuthResult(false), 502);
|
|
22628
22988
|
}
|
|
22629
22989
|
});
|
|
22630
|
-
app.post("/schedule-connections/actions/slack/send-message", auth2, async (c) => {
|
|
22990
|
+
app.post("/schedule-connections/actions/slack/send-message", auth2, requireIntegrationsTier, async (c) => {
|
|
22631
22991
|
const user = c.get("user");
|
|
22632
22992
|
const body = await c.req.json().catch(() => ({}));
|
|
22633
22993
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22641,7 +23001,7 @@ app.post("/schedule-connections/actions/slack/send-message", auth2, async (c) =>
|
|
|
22641
23001
|
return scheduleConnectionError(c, err, "Unable to send the Slack message.");
|
|
22642
23002
|
}
|
|
22643
23003
|
});
|
|
22644
|
-
app.post("/schedule-connections/actions/gmail/send-message", auth2, async (c) => {
|
|
23004
|
+
app.post("/schedule-connections/actions/gmail/send-message", auth2, requireIntegrationsTier, async (c) => {
|
|
22645
23005
|
const user = c.get("user");
|
|
22646
23006
|
const body = await c.req.json().catch(() => ({}));
|
|
22647
23007
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22655,7 +23015,7 @@ app.post("/schedule-connections/actions/gmail/send-message", auth2, async (c) =>
|
|
|
22655
23015
|
return scheduleConnectionError(c, err, "Unable to send the email.");
|
|
22656
23016
|
}
|
|
22657
23017
|
});
|
|
22658
|
-
app.post("/schedule-connections/actions/google-calendar/create-event", auth2, async (c) => {
|
|
23018
|
+
app.post("/schedule-connections/actions/google-calendar/create-event", auth2, requireIntegrationsTier, async (c) => {
|
|
22659
23019
|
const user = c.get("user");
|
|
22660
23020
|
const body = await c.req.json().catch(() => ({}));
|
|
22661
23021
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22677,7 +23037,7 @@ app.post("/schedule-connections/actions/google-calendar/create-event", auth2, as
|
|
|
22677
23037
|
return scheduleConnectionError(c, err, "Unable to create the calendar event.");
|
|
22678
23038
|
}
|
|
22679
23039
|
});
|
|
22680
|
-
app.post("/schedule-connections/actions/zoom/create-meeting", auth2, async (c) => {
|
|
23040
|
+
app.post("/schedule-connections/actions/zoom/create-meeting", auth2, requireIntegrationsTier, async (c) => {
|
|
22681
23041
|
const user = c.get("user");
|
|
22682
23042
|
const body = await c.req.json().catch(() => ({}));
|
|
22683
23043
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22697,7 +23057,7 @@ app.post("/schedule-connections/actions/zoom/create-meeting", auth2, async (c) =
|
|
|
22697
23057
|
return scheduleConnectionError(c, err, "Unable to create the Zoom meeting.");
|
|
22698
23058
|
}
|
|
22699
23059
|
});
|
|
22700
|
-
app.post("/schedule-connections/actions/read", auth2, async (c) => {
|
|
23060
|
+
app.post("/schedule-connections/actions/read", auth2, requireIntegrationsTier, async (c) => {
|
|
22701
23061
|
const user = c.get("user");
|
|
22702
23062
|
const body = await c.req.json().catch(() => ({}));
|
|
22703
23063
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22714,7 +23074,7 @@ app.post("/schedule-connections/actions/read", auth2, async (c) => {
|
|
|
22714
23074
|
return scheduleConnectionError(c, err, "Unable to read from this connection.");
|
|
22715
23075
|
}
|
|
22716
23076
|
});
|
|
22717
|
-
app.post("/schedule-connections/actions/import-memory", auth2, async (c) => {
|
|
23077
|
+
app.post("/schedule-connections/actions/import-memory", auth2, requireIntegrationsTier, async (c) => {
|
|
22718
23078
|
const user = c.get("user");
|
|
22719
23079
|
const body = await c.req.json().catch(() => ({}));
|
|
22720
23080
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22771,7 +23131,7 @@ app.post("/schedule-connections/actions/import-memory", auth2, async (c) => {
|
|
|
22771
23131
|
return scheduleConnectionError(c, err, "Unable to import this connected-service snapshot into Memory.");
|
|
22772
23132
|
}
|
|
22773
23133
|
});
|
|
22774
|
-
app.post("/schedule-connections/actions/describe", auth2, async (c) => {
|
|
23134
|
+
app.post("/schedule-connections/actions/describe", auth2, requireIntegrationsTier, async (c) => {
|
|
22775
23135
|
const user = c.get("user");
|
|
22776
23136
|
const body = await c.req.json().catch(() => ({}));
|
|
22777
23137
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22788,7 +23148,7 @@ app.post("/schedule-connections/actions/describe", auth2, async (c) => {
|
|
|
22788
23148
|
return scheduleConnectionError(c, err, "Unable to describe this connection tool.");
|
|
22789
23149
|
}
|
|
22790
23150
|
});
|
|
22791
|
-
app.post("/schedule-connections/actions/export", auth2, async (c) => {
|
|
23151
|
+
app.post("/schedule-connections/actions/export", auth2, requireIntegrationsTier, async (c) => {
|
|
22792
23152
|
const user = c.get("user");
|
|
22793
23153
|
const body = await c.req.json().catch(() => ({}));
|
|
22794
23154
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22848,7 +23208,7 @@ app.post("/schedule-connections/actions/export", auth2, async (c) => {
|
|
|
22848
23208
|
return scheduleConnectionError(c, err, "Unable to export this connected service.");
|
|
22849
23209
|
}
|
|
22850
23210
|
});
|
|
22851
|
-
app.post("/schedule-connections/actions/export-download", auth2, async (c) => {
|
|
23211
|
+
app.post("/schedule-connections/actions/export-download", auth2, requireIntegrationsTier, async (c) => {
|
|
22852
23212
|
const user = c.get("user");
|
|
22853
23213
|
const body = await c.req.json().catch(() => ({}));
|
|
22854
23214
|
const artifactId = typeof body.artifactId === "string" ? body.artifactId.trim() : "";
|
|
@@ -22865,7 +23225,7 @@ app.post("/schedule-connections/actions/export-download", auth2, async (c) => {
|
|
|
22865
23225
|
return c.json({ ok: false, error: "Unable to renew this artifact download." }, 502);
|
|
22866
23226
|
}
|
|
22867
23227
|
});
|
|
22868
|
-
app.post("/schedule-connections/actions/call", auth2, async (c) => {
|
|
23228
|
+
app.post("/schedule-connections/actions/call", auth2, requireIntegrationsTier, async (c) => {
|
|
22869
23229
|
const user = c.get("user");
|
|
22870
23230
|
const body = await c.req.json().catch(() => ({}));
|
|
22871
23231
|
const connectionId = providerConfigKeyFrom(body.connectionId);
|
|
@@ -22985,7 +23345,7 @@ app.get("/schedule-actions/:id/connections", auth2, async (c) => {
|
|
|
22985
23345
|
return scheduleConnectionError(c, err, "Unable to load scheduled action service connections.");
|
|
22986
23346
|
}
|
|
22987
23347
|
});
|
|
22988
|
-
app.put("/schedule-actions/:id/connections", auth2, async (c) => {
|
|
23348
|
+
app.put("/schedule-actions/:id/connections", auth2, requireIntegrationsTier, async (c) => {
|
|
22989
23349
|
const user = c.get("user");
|
|
22990
23350
|
const body = await c.req.json().catch(() => ({}));
|
|
22991
23351
|
let connections;
|
|
@@ -23270,8 +23630,7 @@ app.get("/history", auth2, async (c) => {
|
|
|
23270
23630
|
location: job.options?.location ?? "",
|
|
23271
23631
|
source: LedgerOperation.SERP,
|
|
23272
23632
|
status: job.status,
|
|
23273
|
-
result_count: job.result ? (job.result.flat?.length ?? 0) + (job.result.organicResults?.length ?? 0) : 0
|
|
23274
|
-
result: job.result ?? null
|
|
23633
|
+
result_count: job.result ? (job.result.flat?.length ?? 0) + (job.result.organicResults?.length ?? 0) : 0
|
|
23275
23634
|
}));
|
|
23276
23635
|
const eventRows = events.map((event) => ({
|
|
23277
23636
|
id: event.id,
|
|
@@ -23281,7 +23640,6 @@ app.get("/history", auth2, async (c) => {
|
|
|
23281
23640
|
source: event.source,
|
|
23282
23641
|
status: event.status,
|
|
23283
23642
|
result_count: event.result_count ?? 0,
|
|
23284
|
-
result: event.result ?? null,
|
|
23285
23643
|
error: event.error ?? null
|
|
23286
23644
|
}));
|
|
23287
23645
|
const rows = [...jobRows, ...eventRows].sort((a, b) => String(b.ts).localeCompare(String(a.ts)));
|
|
@@ -23973,6 +24331,7 @@ app.route("/mcp", mcpApp);
|
|
|
23973
24331
|
app.route("/agent", buildBrowserAgentRoutes());
|
|
23974
24332
|
app.route("/chat", chatApp);
|
|
23975
24333
|
app.route("/schedule", scheduleApp);
|
|
24334
|
+
app.route("/resend", resendInboundApp);
|
|
23976
24335
|
app.get("/console", (c) => c.html(renderConsoleHtml()));
|
|
23977
24336
|
app.get("/console/auth/:id", async (c) => {
|
|
23978
24337
|
const id = c.req.param("id");
|
|
@@ -24102,4 +24461,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
24102
24461
|
export {
|
|
24103
24462
|
app
|
|
24104
24463
|
};
|
|
24105
|
-
//# sourceMappingURL=server-
|
|
24464
|
+
//# sourceMappingURL=server-MQDCAR6I.js.map
|