@automattic/mcp-wpcom-remote
Version:
MCP WordPress.com remote proxy server
1,458 lines (1,457 loc) • 2.03 MB
JavaScript
#!/usr/bin/env node
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
// node_modules/@automattic/mcp-wordpress-remote/dist/proxy.js
var proxy_exports = {};
import { createRequire as createRequire2 } from "module";
import { statSync, createReadStream, promises as fs3 } from "fs";
import { basename } from "path";
import Stream, { PassThrough } from "stream";
import { types, deprecate, promisify } from "util";
import { Buffer as Buffer2 } from "buffer";
import { types as types2 } from "util";
import http from "http";
import { isIP } from "net";
import { format as formatUrl } from "url";
import { deprecate as deprecate2 } from "util";
import http2 from "http";
import https from "https";
import zlib from "zlib";
import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "stream";
import { Buffer as Buffer3 } from "buffer";
import process2 from "process";
import * as fs2 from "fs";
import * as path3 from "path";
import * as os2 from "os";
import * as path22 from "path";
import net from "net";
import crypto3 from "crypto";
import path4 from "path";
import fs4 from "fs/promises";
import fsSync from "fs";
import crypto2 from "crypto";
import { EventEmitter as EventEmitter3 } from "events";
import process7 from "process";
import { Buffer as Buffer4 } from "buffer";
import path42 from "path";
import { fileURLToPath } from "url";
import childProcess from "child_process";
import fs7, { constants as fsConstants } from "fs/promises";
import process3 from "process";
import os22 from "os";
import fs6 from "fs";
import fs5 from "fs";
import fs42 from "fs";
import { promisify as promisify5 } from "util";
import process6 from "process";
import { execFile as execFile4 } from "child_process";
import { promisify as promisify2 } from "util";
import process4 from "process";
import { execFile } from "child_process";
import process5 from "process";
import { promisify as promisify3 } from "util";
import { execFile as execFile2, execFileSync } from "child_process";
import { promisify as promisify4 } from "util";
import { execFile as execFile3 } from "child_process";
import { EventEmitter } from "events";
import crypto4 from "crypto";
import * as fs8 from "fs";
import * as path5 from "path";
import * as os3 from "os";
import { EventEmitter as EventEmitter2 } from "events";
function dataUriToBuffer(uri) {
if (!/^data:/i.test(uri)) {
throw new TypeError('`uri` does not appear to be a Data URI (must begin with "data:")');
}
uri = uri.replace(/\r?\n/g, "");
const firstComma = uri.indexOf(",");
if (firstComma === -1 || firstComma <= 4) {
throw new TypeError("malformed data: URI");
}
const meta = uri.substring(5, firstComma).split(";");
let charset = "";
let base64 = false;
const type = meta[0] || "text/plain";
let typeFull = type;
for (let i2 = 1; i2 < meta.length; i2++) {
if (meta[i2] === "base64") {
base64 = true;
} else if (meta[i2]) {
typeFull += `;${meta[i2]}`;
if (meta[i2].indexOf("charset=") === 0) {
charset = meta[i2].substring(8);
}
}
}
if (!meta[0] && !charset.length) {
typeFull += ";charset=US-ASCII";
charset = "US-ASCII";
}
const encoding = base64 ? "base64" : "ascii";
const data = unescape(uri.substring(firstComma + 1));
const buffer = Buffer.from(data, encoding);
buffer.type = type;
buffer.typeFull = typeFull;
buffer.charset = charset;
return buffer;
}
async function* toIterator(parts, clone2 = true) {
for (const part of parts) {
if ("stream" in part) {
yield* (
/** @type {AsyncIterableIterator<Uint8Array>} */
part.stream()
);
} else if (ArrayBuffer.isView(part)) {
if (clone2) {
let position = part.byteOffset;
const end = part.byteOffset + part.byteLength;
while (position !== end) {
const size = Math.min(end - position, POOL_SIZE);
const chunk = part.buffer.slice(position, position + size);
position += chunk.byteLength;
yield new Uint8Array(chunk);
}
} else {
yield part;
}
} else {
let position = 0, b = (
/** @type {Blob} */
part
);
while (position !== b.size) {
const chunk = b.slice(position, Math.min(b.size, position + POOL_SIZE));
const buffer = await chunk.arrayBuffer();
position += buffer.byteLength;
yield new Uint8Array(buffer);
}
}
}
}
function formDataToBlob(F2, B = fetch_blob_default) {
var b = `${r()}${r()}`.replace(/\./g, "").slice(-28).padStart(32, "-"), c = [], p = `--${b}\r
Content-Disposition: form-data; name="`;
F2.forEach((v, n) => typeof v == "string" ? c.push(p + e(n) + `"\r
\r
${v.replace(/\r(?!\n)|(?<!\r)\n/g, "\r\n")}\r
`) : c.push(p + e(n) + `"; filename="${e(v.name, 1)}"\r
Content-Type: ${v.type || "application/octet-stream"}\r
\r
`, v, "\r\n"));
c.push(`--${b}--`);
return new B(c, { type: "multipart/form-data; boundary=" + b });
}
function _fileName(headerValue) {
const m2 = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
if (!m2) {
return;
}
const match = m2[2] || m2[3] || "";
let filename = match.slice(match.lastIndexOf("\\") + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#(\d{4});/g, (m3, code) => {
return String.fromCharCode(code);
});
return filename;
}
async function toFormData(Body2, ct) {
if (!/multipart/i.test(ct)) {
throw new TypeError("Failed to fetch");
}
const m2 = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
if (!m2) {
throw new TypeError("no or bad content-type header, no multipart boundary");
}
const parser = new MultipartParser(m2[1] || m2[2]);
let headerField;
let headerValue;
let entryValue;
let entryName;
let contentType;
let filename;
const entryChunks = [];
const formData = new FormData();
const onPartData = (ui8a) => {
entryValue += decoder.decode(ui8a, { stream: true });
};
const appendToFile = (ui8a) => {
entryChunks.push(ui8a);
};
const appendFileToFormData = () => {
const file = new file_default(entryChunks, filename, { type: contentType });
formData.append(entryName, file);
};
const appendEntryToFormData = () => {
formData.append(entryName, entryValue);
};
const decoder = new TextDecoder("utf-8");
decoder.decode();
parser.onPartBegin = function() {
parser.onPartData = onPartData;
parser.onPartEnd = appendEntryToFormData;
headerField = "";
headerValue = "";
entryValue = "";
entryName = "";
contentType = "";
filename = null;
entryChunks.length = 0;
};
parser.onHeaderField = function(ui8a) {
headerField += decoder.decode(ui8a, { stream: true });
};
parser.onHeaderValue = function(ui8a) {
headerValue += decoder.decode(ui8a, { stream: true });
};
parser.onHeaderEnd = function() {
headerValue += decoder.decode();
headerField = headerField.toLowerCase();
if (headerField === "content-disposition") {
const m3 = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
if (m3) {
entryName = m3[2] || m3[3] || "";
}
filename = _fileName(headerValue);
if (filename) {
parser.onPartData = appendToFile;
parser.onPartEnd = appendFileToFormData;
}
} else if (headerField === "content-type") {
contentType = headerValue;
}
headerValue = "";
headerField = "";
};
for await (const chunk of Body2) {
parser.write(chunk);
}
parser.end();
return formData;
}
async function consumeBody(data) {
if (data[INTERNALS].disturbed) {
throw new TypeError(`body used already for: ${data.url}`);
}
data[INTERNALS].disturbed = true;
if (data[INTERNALS].error) {
throw data[INTERNALS].error;
}
const { body } = data;
if (body === null) {
return Buffer2.alloc(0);
}
if (!(body instanceof Stream)) {
return Buffer2.alloc(0);
}
const accum = [];
let accumBytes = 0;
try {
for await (const chunk of body) {
if (data.size > 0 && accumBytes + chunk.length > data.size) {
const error = new FetchError(`content size at ${data.url} over limit: ${data.size}`, "max-size");
body.destroy(error);
throw error;
}
accumBytes += chunk.length;
accum.push(chunk);
}
} catch (error) {
const error_ = error instanceof FetchBaseError ? error : new FetchError(`Invalid response body while trying to fetch ${data.url}: ${error.message}`, "system", error);
throw error_;
}
if (body.readableEnded === true || body._readableState.ended === true) {
try {
if (accum.every((c) => typeof c === "string")) {
return Buffer2.from(accum.join(""));
}
return Buffer2.concat(accum, accumBytes);
} catch (error) {
throw new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, "system", error);
}
} else {
throw new FetchError(`Premature close of server response while trying to fetch ${data.url}`);
}
}
function fromRawHeaders(headers = []) {
return new Headers2(
headers.reduce((result, value, index, array) => {
if (index % 2 === 0) {
result.push(array.slice(index, index + 2));
}
return result;
}, []).filter(([name, value]) => {
try {
validateHeaderName(name);
validateHeaderValue(name, String(value));
return true;
} catch {
return false;
}
})
);
}
function stripURLForUseAsAReferrer(url, originOnly = false) {
if (url == null) {
return "no-referrer";
}
url = new URL(url);
if (/^(about|blob|data):$/.test(url.protocol)) {
return "no-referrer";
}
url.username = "";
url.password = "";
url.hash = "";
if (originOnly) {
url.pathname = "";
url.search = "";
}
return url;
}
function validateReferrerPolicy(referrerPolicy) {
if (!ReferrerPolicy.has(referrerPolicy)) {
throw new TypeError(`Invalid referrerPolicy: ${referrerPolicy}`);
}
return referrerPolicy;
}
function isOriginPotentiallyTrustworthy(url) {
if (/^(http|ws)s:$/.test(url.protocol)) {
return true;
}
const hostIp = url.host.replace(/(^\[)|(]$)/g, "");
const hostIPVersion = isIP(hostIp);
if (hostIPVersion === 4 && /^127\./.test(hostIp)) {
return true;
}
if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) {
return true;
}
if (url.host === "localhost" || url.host.endsWith(".localhost")) {
return false;
}
if (url.protocol === "file:") {
return true;
}
return false;
}
function isUrlPotentiallyTrustworthy(url) {
if (/^about:(blank|srcdoc)$/.test(url)) {
return true;
}
if (url.protocol === "data:") {
return true;
}
if (/^(blob|filesystem):$/.test(url.protocol)) {
return true;
}
return isOriginPotentiallyTrustworthy(url);
}
function determineRequestsReferrer(request, { referrerURLCallback, referrerOriginCallback } = {}) {
if (request.referrer === "no-referrer" || request.referrerPolicy === "") {
return null;
}
const policy = request.referrerPolicy;
if (request.referrer === "about:client") {
return "no-referrer";
}
const referrerSource = request.referrer;
let referrerURL = stripURLForUseAsAReferrer(referrerSource);
let referrerOrigin = stripURLForUseAsAReferrer(referrerSource, true);
if (referrerURL.toString().length > 4096) {
referrerURL = referrerOrigin;
}
if (referrerURLCallback) {
referrerURL = referrerURLCallback(referrerURL);
}
if (referrerOriginCallback) {
referrerOrigin = referrerOriginCallback(referrerOrigin);
}
const currentURL = new URL(request.url);
switch (policy) {
case "no-referrer":
return "no-referrer";
case "origin":
return referrerOrigin;
case "unsafe-url":
return referrerURL;
case "strict-origin":
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
return "no-referrer";
}
return referrerOrigin.toString();
case "strict-origin-when-cross-origin":
if (referrerURL.origin === currentURL.origin) {
return referrerURL;
}
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
return "no-referrer";
}
return referrerOrigin;
case "same-origin":
if (referrerURL.origin === currentURL.origin) {
return referrerURL;
}
return "no-referrer";
case "origin-when-cross-origin":
if (referrerURL.origin === currentURL.origin) {
return referrerURL;
}
return referrerOrigin;
case "no-referrer-when-downgrade":
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
return "no-referrer";
}
return referrerURL;
default:
throw new TypeError(`Invalid referrerPolicy: ${policy}`);
}
}
function parseReferrerPolicyFromHeader(headers) {
const policyTokens = (headers.get("referrer-policy") || "").split(/[,\s]+/);
let policy = "";
for (const token of policyTokens) {
if (token && ReferrerPolicy.has(token)) {
policy = token;
}
}
return policy;
}
async function fetch2(url, options_) {
return new Promise((resolve, reject) => {
const request = new Request(url, options_);
const { parsedURL, options } = getNodeRequestOptions(request);
if (!supportedSchemas.has(parsedURL.protocol)) {
throw new TypeError(`node-fetch cannot load ${url}. URL scheme "${parsedURL.protocol.replace(/:$/, "")}" is not supported.`);
}
if (parsedURL.protocol === "data:") {
const data = dist_default(request.url);
const response2 = new Response(data, { headers: { "Content-Type": data.typeFull } });
resolve(response2);
return;
}
const send = (parsedURL.protocol === "https:" ? https : http2).request;
const { signal } = request;
let response = null;
const abort = () => {
const error = new AbortError("The operation was aborted.");
reject(error);
if (request.body && request.body instanceof Stream2.Readable) {
request.body.destroy(error);
}
if (!response || !response.body) {
return;
}
response.body.emit("error", error);
};
if (signal && signal.aborted) {
abort();
return;
}
const abortAndFinalize = () => {
abort();
finalize();
};
const request_ = send(parsedURL.toString(), options);
if (signal) {
signal.addEventListener("abort", abortAndFinalize);
}
const finalize = () => {
request_.abort();
if (signal) {
signal.removeEventListener("abort", abortAndFinalize);
}
};
request_.on("error", (error) => {
reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, "system", error));
finalize();
});
fixResponseChunkedTransferBadEnding(request_, (error) => {
if (response && response.body) {
response.body.destroy(error);
}
});
if (process.version < "v14") {
request_.on("socket", (s2) => {
let endedWithEventsCount;
s2.prependListener("end", () => {
endedWithEventsCount = s2._eventsCount;
});
s2.prependListener("close", (hadError) => {
if (response && endedWithEventsCount < s2._eventsCount && !hadError) {
const error = new Error("Premature close");
error.code = "ERR_STREAM_PREMATURE_CLOSE";
response.body.emit("error", error);
}
});
});
}
request_.on("response", (response_) => {
request_.setTimeout(0);
const headers = fromRawHeaders(response_.rawHeaders);
if (isRedirect(response_.statusCode)) {
const location = headers.get("Location");
let locationURL = null;
try {
locationURL = location === null ? null : new URL(location, request.url);
} catch {
if (request.redirect !== "manual") {
reject(new FetchError(`uri requested responds with an invalid redirect URL: ${location}`, "invalid-redirect"));
finalize();
return;
}
}
switch (request.redirect) {
case "error":
reject(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${request.url}`, "no-redirect"));
finalize();
return;
case "manual":
break;
case "follow": {
if (locationURL === null) {
break;
}
if (request.counter >= request.follow) {
reject(new FetchError(`maximum redirect reached at: ${request.url}`, "max-redirect"));
finalize();
return;
}
const requestOptions = {
headers: new Headers2(request.headers),
follow: request.follow,
counter: request.counter + 1,
agent: request.agent,
compress: request.compress,
method: request.method,
body: clone(request),
signal: request.signal,
size: request.size,
referrer: request.referrer,
referrerPolicy: request.referrerPolicy
};
if (!isDomainOrSubdomain(request.url, locationURL) || !isSameProtocol(request.url, locationURL)) {
for (const name of ["authorization", "www-authenticate", "cookie", "cookie2"]) {
requestOptions.headers.delete(name);
}
}
if (response_.statusCode !== 303 && request.body && options_.body instanceof Stream2.Readable) {
reject(new FetchError("Cannot follow redirect with body being a readable stream", "unsupported-redirect"));
finalize();
return;
}
if (response_.statusCode === 303 || (response_.statusCode === 301 || response_.statusCode === 302) && request.method === "POST") {
requestOptions.method = "GET";
requestOptions.body = void 0;
requestOptions.headers.delete("content-length");
}
const responseReferrerPolicy = parseReferrerPolicyFromHeader(headers);
if (responseReferrerPolicy) {
requestOptions.referrerPolicy = responseReferrerPolicy;
}
resolve(fetch2(new Request(locationURL, requestOptions)));
finalize();
return;
}
default:
return reject(new TypeError(`Redirect option '${request.redirect}' is not a valid value of RequestRedirect`));
}
}
if (signal) {
response_.once("end", () => {
signal.removeEventListener("abort", abortAndFinalize);
});
}
let body = pump(response_, new PassThrough2(), (error) => {
if (error) {
reject(error);
}
});
if (process.version < "v12.10") {
response_.on("aborted", abortAndFinalize);
}
const responseOptions = {
url: request.url,
status: response_.statusCode,
statusText: response_.statusMessage,
headers,
size: request.size,
counter: request.counter,
highWaterMark: request.highWaterMark
};
const codings = headers.get("Content-Encoding");
if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
response = new Response(body, responseOptions);
resolve(response);
return;
}
const zlibOptions = {
flush: zlib.Z_SYNC_FLUSH,
finishFlush: zlib.Z_SYNC_FLUSH
};
if (codings === "gzip" || codings === "x-gzip") {
body = pump(body, zlib.createGunzip(zlibOptions), (error) => {
if (error) {
reject(error);
}
});
response = new Response(body, responseOptions);
resolve(response);
return;
}
if (codings === "deflate" || codings === "x-deflate") {
const raw = pump(response_, new PassThrough2(), (error) => {
if (error) {
reject(error);
}
});
raw.once("data", (chunk) => {
if ((chunk[0] & 15) === 8) {
body = pump(body, zlib.createInflate(), (error) => {
if (error) {
reject(error);
}
});
} else {
body = pump(body, zlib.createInflateRaw(), (error) => {
if (error) {
reject(error);
}
});
}
response = new Response(body, responseOptions);
resolve(response);
});
raw.once("end", () => {
if (!response) {
response = new Response(body, responseOptions);
resolve(response);
}
});
return;
}
if (codings === "br") {
body = pump(body, zlib.createBrotliDecompress(), (error) => {
if (error) {
reject(error);
}
});
response = new Response(body, responseOptions);
resolve(response);
return;
}
response = new Response(body, responseOptions);
resolve(response);
});
writeToStream(request_, request).catch(reject);
});
}
function fixResponseChunkedTransferBadEnding(request, errorCallback) {
const LAST_CHUNK = Buffer3.from("0\r\n\r\n");
let isChunkedTransfer = false;
let properLastChunkReceived = false;
let previousChunk;
request.on("response", (response) => {
const { headers } = response;
isChunkedTransfer = headers["transfer-encoding"] === "chunked" && !headers["content-length"];
});
request.on("socket", (socket) => {
const onSocketClose = () => {
if (isChunkedTransfer && !properLastChunkReceived) {
const error = new Error("Premature close");
error.code = "ERR_STREAM_PREMATURE_CLOSE";
errorCallback(error);
}
};
const onData = (buf) => {
properLastChunkReceived = Buffer3.compare(buf.slice(-5), LAST_CHUNK) === 0;
if (!properLastChunkReceived && previousChunk) {
properLastChunkReceived = Buffer3.compare(previousChunk.slice(-3), LAST_CHUNK.slice(0, 3)) === 0 && Buffer3.compare(buf.slice(-2), LAST_CHUNK.slice(3)) === 0;
}
previousChunk = buf;
};
socket.prependListener("close", onSocketClose);
socket.on("data", onData);
request.on("close", () => {
socket.removeListener("close", onSocketClose);
socket.removeListener("data", onData);
});
});
}
function setErrorMap2(map) {
overrideErrorMap2 = map;
}
function getErrorMap2() {
return overrideErrorMap2;
}
function addIssueToContext2(ctx, issueData) {
const overrideMap = getErrorMap2();
const issue = makeIssue2({
issueData,
data: ctx.data,
path: ctx.path,
errorMaps: [
ctx.common.contextualErrorMap,
// contextual error map is first priority
ctx.schemaErrorMap,
// then schema-bound map if available
overrideMap,
// then global override map
overrideMap === errorMap2 ? void 0 : errorMap2
// then global default map
].filter((x2) => !!x2)
});
ctx.common.issues.push(issue);
}
function __classPrivateFieldGet2(receiver, state, kind, f3) {
if (kind === "a" && !f3) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f3 : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f3 : kind === "a" ? f3.call(receiver) : f3 ? f3.value : state.get(receiver);
}
function __classPrivateFieldSet2(receiver, state, value, kind, f3) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f3) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f3 : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return kind === "a" ? f3.call(receiver, value) : f3 ? f3.value = value : state.set(receiver, value), value;
}
function processCreateParams2(params) {
if (!params)
return {};
const { errorMap: errorMap22, invalid_type_error, required_error, description } = params;
if (errorMap22 && (invalid_type_error || required_error)) {
throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);
}
if (errorMap22)
return { errorMap: errorMap22, description };
const customMap = (iss, ctx) => {
var _a, _b;
const { message } = params;
if (iss.code === "invalid_enum_value") {
return { message: message !== null && message !== void 0 ? message : ctx.defaultError };
}
if (typeof ctx.data === "undefined") {
return { message: (_a = message !== null && message !== void 0 ? message : required_error) !== null && _a !== void 0 ? _a : ctx.defaultError };
}
if (iss.code !== "invalid_type")
return { message: ctx.defaultError };
return { message: (_b = message !== null && message !== void 0 ? message : invalid_type_error) !== null && _b !== void 0 ? _b : ctx.defaultError };
};
return { errorMap: customMap, description };
}
function timeRegexSource2(args) {
let regex = `([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d`;
if (args.precision) {
regex = `${regex}\\.\\d{${args.precision}}`;
} else if (args.precision == null) {
regex = `${regex}(\\.\\d+)?`;
}
return regex;
}
function timeRegex2(args) {
return new RegExp(`^${timeRegexSource2(args)}$`);
}
function datetimeRegex2(args) {
let regex = `${dateRegexSource2}T${timeRegexSource2(args)}`;
const opts = [];
opts.push(args.local ? `Z?` : `Z`);
if (args.offset)
opts.push(`([+-]\\d{2}:?\\d{2})`);
regex = `${regex}(${opts.join("|")})`;
return new RegExp(`^${regex}$`);
}
function isValidIP2(ip, version) {
if ((version === "v4" || !version) && ipv4Regex2.test(ip)) {
return true;
}
if ((version === "v6" || !version) && ipv6Regex2.test(ip)) {
return true;
}
return false;
}
function isValidJWT2(jwt, alg) {
if (!jwtRegex2.test(jwt))
return false;
try {
const [header] = jwt.split(".");
const base64 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
const decoded = JSON.parse(atob(base64));
if (typeof decoded !== "object" || decoded === null)
return false;
if (!decoded.typ || !decoded.alg)
return false;
if (alg && decoded.alg !== alg)
return false;
return true;
} catch (_a) {
return false;
}
}
function isValidCidr2(ip, version) {
if ((version === "v4" || !version) && ipv4CidrRegex2.test(ip)) {
return true;
}
if ((version === "v6" || !version) && ipv6CidrRegex2.test(ip)) {
return true;
}
return false;
}
function floatSafeRemainder2(val, step) {
const valDecCount = (val.toString().split(".")[1] || "").length;
const stepDecCount = (step.toString().split(".")[1] || "").length;
const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount;
const valInt = parseInt(val.toFixed(decCount).replace(".", ""));
const stepInt = parseInt(step.toFixed(decCount).replace(".", ""));
return valInt % stepInt / Math.pow(10, decCount);
}
function deepPartialify2(schema) {
if (schema instanceof ZodObject2) {
const newShape = {};
for (const key in schema.shape) {
const fieldSchema = schema.shape[key];
newShape[key] = ZodOptional2.create(deepPartialify2(fieldSchema));
}
return new ZodObject2({
...schema._def,
shape: () => newShape
});
} else if (schema instanceof ZodArray2) {
return new ZodArray2({
...schema._def,
type: deepPartialify2(schema.element)
});
} else if (schema instanceof ZodOptional2) {
return ZodOptional2.create(deepPartialify2(schema.unwrap()));
} else if (schema instanceof ZodNullable2) {
return ZodNullable2.create(deepPartialify2(schema.unwrap()));
} else if (schema instanceof ZodTuple2) {
return ZodTuple2.create(schema.items.map((item) => deepPartialify2(item)));
} else {
return schema;
}
}
function mergeValues2(a, b) {
const aType = getParsedType2(a);
const bType = getParsedType2(b);
if (a === b) {
return { valid: true, data: a };
} else if (aType === ZodParsedType2.object && bType === ZodParsedType2.object) {
const bKeys = util2.objectKeys(b);
const sharedKeys = util2.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1);
const newObj = { ...a, ...b };
for (const key of sharedKeys) {
const sharedValue = mergeValues2(a[key], b[key]);
if (!sharedValue.valid) {
return { valid: false };
}
newObj[key] = sharedValue.data;
}
return { valid: true, data: newObj };
} else if (aType === ZodParsedType2.array && bType === ZodParsedType2.array) {
if (a.length !== b.length) {
return { valid: false };
}
const newArray = [];
for (let index = 0; index < a.length; index++) {
const itemA = a[index];
const itemB = b[index];
const sharedValue = mergeValues2(itemA, itemB);
if (!sharedValue.valid) {
return { valid: false };
}
newArray.push(sharedValue.data);
}
return { valid: true, data: newArray };
} else if (aType === ZodParsedType2.date && bType === ZodParsedType2.date && +a === +b) {
return { valid: true, data: a };
} else {
return { valid: false };
}
}
function createZodEnum2(values, params) {
return new ZodEnum2({
values,
typeName: ZodFirstPartyTypeKind2.ZodEnum,
...processCreateParams2(params)
});
}
function cleanParams2(params, data) {
const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params;
const p2 = typeof p === "string" ? { message: p } : p;
return p2;
}
function custom2(check, _params = {}, fatal) {
if (check)
return ZodAny2.create().superRefine((data, ctx) => {
var _a, _b;
const r2 = check(data);
if (r2 instanceof Promise) {
return r2.then((r3) => {
var _a2, _b2;
if (!r3) {
const params = cleanParams2(_params, data);
const _fatal = (_b2 = (_a2 = params.fatal) !== null && _a2 !== void 0 ? _a2 : fatal) !== null && _b2 !== void 0 ? _b2 : true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
});
}
if (!r2) {
const params = cleanParams2(_params, data);
const _fatal = (_b = (_a = params.fatal) !== null && _a !== void 0 ? _a : fatal) !== null && _b !== void 0 ? _b : true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
return;
});
return ZodAny2.create();
}
function mergeCapabilities(base, additional) {
return Object.entries(additional).reduce((acc, [key, value]) => {
if (value && typeof value === "object") {
acc[key] = acc[key] ? { ...acc[key], ...value } : value;
} else {
acc[key] = value;
}
return acc;
}, { ...base });
}
function deserializeMessage(line) {
return JSONRPCMessageSchema2.parse(JSON.parse(line));
}
function serializeMessage(message) {
return JSON.stringify(message) + "\n";
}
function getConfigDir() {
const baseConfigDir = CONFIG2.WP_MCP_CONFIG_DIR;
return path4.join(baseConfigDir, `wordpress-remote-${VERSION}`);
}
async function ensureConfigDir() {
try {
const configDir = getConfigDir();
await fs4.mkdir(configDir, { recursive: true });
await fs4.chmod(configDir, 448);
} catch (error) {
logger2.error("Error creating config directory", "AUTH", error);
throw error;
}
}
function getConfigFilePath(serverUrlHash, filename) {
const configDir = getConfigDir();
return path4.join(configDir, `${serverUrlHash}_${filename}`);
}
async function deleteConfigFile(serverUrlHash, filename) {
try {
const filePath = getConfigFilePath(serverUrlHash, filename);
await fs4.unlink(filePath);
} catch (error) {
if (error.code !== "ENOENT") {
logger2.error(`Error deleting ${filename}`, "AUTH", error);
}
}
}
async function readJsonFile(serverUrlHash, filename) {
try {
await ensureConfigDir();
const filePath = getConfigFilePath(serverUrlHash, filename);
const content = await fs4.readFile(filePath, "utf-8");
return JSON.parse(content);
} catch (error) {
if (error.code === "ENOENT") {
return void 0;
}
logger2.error(`Error reading ${filename}`, "AUTH", error);
return void 0;
}
}
async function writeJsonFile(serverUrlHash, filename, data) {
try {
await ensureConfigDir();
const filePath = getConfigFilePath(serverUrlHash, filename);
await fs4.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
await fs4.chmod(filePath, 384);
} catch (error) {
logger2.error(`Error writing ${filename}`, "AUTH", error);
throw error;
}
}
async function readTextFile(serverUrlHash, filename, errorMessage) {
try {
await ensureConfigDir();
const filePath = getConfigFilePath(serverUrlHash, filename);
return await fs4.readFile(filePath, "utf-8");
} catch (error) {
throw new Error(errorMessage || `Error reading ${filename}`);
}
}
async function writeTextFile(serverUrlHash, filename, text) {
try {
await ensureConfigDir();
const filePath = getConfigFilePath(serverUrlHash, filename);
await fs4.writeFile(filePath, text, "utf-8");
await fs4.chmod(filePath, 384);
} catch (error) {
logger2.error(`Error writing ${filename}`, "AUTH", error);
throw error;
}
}
function generateServerUrlHash(serverUrl) {
return crypto2.createHash("md5").update(serverUrl).digest("hex");
}
async function readTokens(serverUrlHash) {
try {
const tokens = await readJsonFile(serverUrlHash, "tokens.json");
if (tokens) {
logger2.debug(`Loaded tokens for server hash: ${serverUrlHash}`, "AUTH");
return tokens;
}
return null;
} catch (error) {
logger2.error(`Error reading tokens for ${serverUrlHash}`, "AUTH", error);
return null;
}
}
async function writeTokens(serverUrlHash, tokens) {
try {
const tokensWithTimestamp = {
...tokens,
obtained_at: Date.now()
};
await writeJsonFile(serverUrlHash, "tokens.json", tokensWithTimestamp);
logger2.info(`Stored tokens for server hash: ${serverUrlHash}`, "AUTH");
} catch (error) {
logger2.error(`Error writing tokens for ${serverUrlHash}`, "AUTH", error);
throw error;
}
}
async function deleteTokens(serverUrlHash) {
try {
await deleteConfigFile(serverUrlHash, "tokens.json");
logger2.info(`Deleted tokens for server hash: ${serverUrlHash}`, "AUTH");
} catch (error) {
logger2.error(`Error deleting tokens for ${serverUrlHash}`, "AUTH", error);
}
}
async function readClientInfo(serverUrlHash) {
try {
const clientInfo = await readJsonFile(serverUrlHash, "client_info.json");
if (clientInfo) {
logger2.debug(`Loaded client info for server hash: ${serverUrlHash}`, "AUTH");
return clientInfo;
}
return null;
} catch (error) {
logger2.error(`Error reading client info for ${serverUrlHash}`, "AUTH", error);
return null;
}
}
async function writeClientInfo(serverUrlHash, clientInfo) {
try {
await writeJsonFile(serverUrlHash, "client_info.json", clientInfo);
logger2.info(`Stored client info for server hash: ${serverUrlHash}`, "AUTH");
} catch (error) {
logger2.error(`Error writing client info for ${serverUrlHash}`, "AUTH", error);
throw error;
}
}
function isTokenValid(tokens) {
if (!tokens?.access_token) {
return { isValid: false, error: "No access token" };
}
if (!tokens.expires_in || !tokens.obtained_at) {
return { isValid: true };
}
const now = Date.now();
const expiryTime = tokens.obtained_at + tokens.expires_in * 1e3;
const isExpiringSoon = now >= expiryTime - 6e4;
if (isExpiringSoon) {
const expiresIn2 = Math.max(0, Math.floor((expiryTime - now) / 1e3));
return {
isValid: false,
expiresIn: expiresIn2,
error: "Token expired"
};
}
const expiresIn = Math.floor((expiryTime - now) / 1e3);
return {
isValid: true,
expiresIn: Math.max(0, expiresIn)
};
}
async function getValidTokens(serverUrlHash) {
const tokens = await readTokens(serverUrlHash);
if (!tokens) {
return null;
}
const validation = isTokenValid(tokens);
if (!validation.isValid) {
logger2.warn(`Tokens for ${serverUrlHash} are invalid: ${validation.error}`, "AUTH");
return null;
}
return tokens;
}
async function cleanupExpiredTokens() {
try {
const configDir = getConfigDir();
if (!fsSync.existsSync(configDir)) {
return;
}
const files = await fs4.readdir(configDir);
const tokenFiles = files.filter((file) => file.endsWith("_tokens.json"));
let cleaned = 0;
for (const file of tokenFiles) {
const serverHash = file.replace("_tokens.json", "");
const tokens = await readTokens(serverHash);
if (tokens && !isTokenValid(tokens).isValid) {
await deleteTokens(serverHash);
cleaned++;
}
}
if (cleaned > 0) {
logger2.info(`Cleaned up ${cleaned} expired token files`, "AUTH");
}
} catch (error) {
logger2.error("Error during token cleanup", "AUTH", error);
}
}
async function findAvailablePort(preferredPort) {
return new Promise((resolve, reject) => {
const server = net.createServer();
server.on("error", (err) => {
if (err.code === "EADDRINUSE") {
server.listen(0);
} else {
reject(err);
}
});
server.on("listening", () => {
const { port } = server.address();
server.close(() => {
resolve(port);
});
});
server.listen(preferredPort || 0);
});
}
function calculateDefaultPort(serverUrlHash) {
const offset = parseInt(serverUrlHash.substring(0, 4), 16);
return 3335 + offset % 45816;
}
async function findExistingClientPort(serverUrlHash) {
const clientInfo = await readJsonFile(serverUrlHash, "client_info.json");
if (!clientInfo) {
return void 0;
}
const localhostRedirectUri = clientInfo.redirect_uris.map((uri) => {
try {
return new URL(uri);
} catch {
return null;
}
}).filter((url) => url !== null).find(({ hostname: hostname2 }) => hostname2 === "localhost" || hostname2 === "127.0.0.1");
if (!localhostRedirectUri) {
return void 0;
}
const port = parseInt(localhostRedirectUri.port);
return isNaN(port) ? void 0 : port;
}
function getServerUrlHash(serverUrl) {
return crypto3.createHash("md5").update(serverUrl).digest("hex");
}
async function selectCallbackPort(serverUrl, specifiedPort, _unused) {
const serverUrlHash = getServerUrlHash(serverUrl);
if (specifiedPort) {
return specifiedPort;
}
const defaultPort = calculateDefaultPort(serverUrlHash);
const [existingClientPort, availablePort] = await Promise.all([
findExistingClientPort(serverUrlHash),
findAvailablePort(defaultPort)
]);
if (existingClientPort) {
return existingClientPort;
}
return availablePort;
}
function parseOAuthScopes(envScopes, defaultScopes) {
if (!envScopes || envScopes.trim() === "") {
return defaultScopes;
}
return envScopes.split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
}
function getDefaultOAuthScopes() {
const defaultScopes = ["read", "write"];
return parseOAuthScopes(CONFIG2.OAUTH_SCOPES, defaultScopes);
}
function validateConfig() {
const errors = [];
const hasJWT = !!CONFIG2.JWT_TOKEN;
const hasBasicAuth = !!(CONFIG2.WP_API_USERNAME && CONFIG2.WP_API_PASSWORD);
const hasOAuth = CONFIG2.OAUTH_ENABLED;
if (!hasJWT && !hasBasicAuth && !hasOAuth) {
errors.push(
"No authentication method configured. Please set one of: JWT_TOKEN, WP_API_USERNAME+WP_API_PASSWORD, or enable OAuth"
);
}
if (!CONFIG2.WP_API_URL || CONFIG2.WP_API_URL === "https://example.com") {
errors.push("WP_API_URL must be set to your WordPress site URL");
}
if (CONFIG2.OAUTH_ENABLED) {
if (CONFIG2.OAUTH_CALLBACK_PORT !== void 0 && (isNaN(CONFIG2.OAUTH_CALLBACK_PORT) || CONFIG2.OAUTH_CALLBACK_PORT < 1 || CONFIG2.OAUTH_CALLBACK_PORT > 65535)) {
errors.push("OAUTH_CALLBACK_PORT must be a valid port number (1-65535) if specified");
}
if (CONFIG2.OAUTH_FLOW_TYPE === "authorization_code" && !CONFIG2.OAUTH_USE_PKCE) {
errors.push(
"PKCE is required for OAuth 2.1 authorization_code flow (MCP Authorization specification 2025-06-18)"
);
}
}
return {
isValid: errors.length === 0,
errors: errors.map(formatConfigError)
};
}
async function getOAuthCallbackPort() {
return selectCallbackPort(
CONFIG2.WP_API_URL,
CONFIG2.OAUTH_CALLBACK_PORT,
false
// Always treat as self-hosted for port selection
);
}
function formatConfigError(error) {
if (error.includes("WP_API_URL must be set")) {
return `${error}. Example: WP_API_URL=https://yoursite.com`;
}
if (error.includes("No authentication method configured")) {
return `${error}. Configure one of these options:
\u2022 JWT_TOKEN=your_jwt_token (preferred for APIs)
\u2022 WP_API_USERNAME=username and WP_API_PASSWORD=app_password (for application passwords)
\u2022 Set OAUTH_ENABLED=true and WP_OAUTH_CLIENT_ID=your_client_id (for OAuth 2.1)`;
}
if (error.includes("OAUTH_CALLBACK_PORT")) {
return `${error}. The port must be available for the OAuth callback server. Try a different port like 7777, 7890, or other ports in the safe 7000-7999 range.`;
}
if (error.includes("PKCE is required")) {
return `${error}. Set OAUTH_USE_PKCE=true (this is required for secure OAuth 2.1 authentication).`;
}
if (error.includes("WP_OAUTH_CLIENT_ID")) {
return `${error}. You need to register your application with WordPress first. Check if the WordPress MCP plugin is installed and activated.`;
}
return error;
}
function log2(message, level = 2, category = "GENERAL", ...args) {
if (level > CURRENT_LOG_LEVEL2) {
return;
}
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
const levelName = LogLevel2[level];
const formattedArgs = args.length > 0 ? args.map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : arg).join(" ") : "";
const logMessage = `${timestamp} [${levelName}] [${category}] ${message}${formattedArgs ? "\n" + formattedArgs : ""}
`;
process.stderr.write(logMessage);
if (process.env.LOG_FILE) {
fs2.appendFileSync(process.env.LOG_FILE, logMessage);
}
}
function validateNodeVersion(requiredVersion = 18) {
const currentNodeVersion = parseInt(process.version.slice(1).split(".")[0]);
if (currentNodeVersion < requiredVersion) {
logger2.error(
`This application requires Node.js version ${requiredVersion} or higher.`,
"SYSTEM"
);
logger2.error(`Current version: ${process.version}`, "SYSTEM");
process.exit(1);
}
}
async function setupFetchPolyfill() {
if (typeof globalThis.fetch !== "function") {
logger2.info("Native fetch not available, loading node-fetch polyfill...", "SYSTEM");
try {
const { default: nodeFetch } = await Promise.resolve().then(() => (init_src(), src_exports));
globalThis.fetch = nodeFetch;
logger2.info("Successfully loaded node-fetch polyfill", "SYSTEM");
} catch (error) {
logger2.error(
"Failed to load node-fetch polyfill. Please install node-fetch: npm install node-fetch",
"SYSTEM"
);
logger2.error(`Error: ${error instanceof Error ? error.message : String(error)}`, "SYSTEM");
process.exit(1);
}
} else {
logger2.info("Using native fetch API", "SYSTEM");
}
}
function isAPIError(error) {
return error instanceof APIError;
}
function hasDockerEnv() {
try {
fs42.statSync("/.dockerenv");
return true;
} catch {
return false;
}
}
function hasDockerCGroup() {
try {
return fs42.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
} catch {
return false;
}
}
function isDocker() {
if (isDockerCached === void 0) {
isDockerCached = hasDockerEnv() || hasDockerCGroup();
}
return isDockerCached;
}
function isInsideContainer() {
if (cachedResult === void 0) {
cachedResult = hasContainerEnv() || isDocker();
}
return cachedResult;
}
function defineLazyProperty(object, propertyName, valueGetter) {
const define2 = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
Object.defineProperty(object, propertyName, {
configurable: true,
enumerable: true,
get() {
const result = valueGetter();
define2(result);
return result;
},
set(value) {
define2(value);
}
});
return object;
}
async function defaultBrowserId() {
if (process4.platform !== "darwin") {
throw new Error("macOS only");
}
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
return match?.groups.id ?? "com.apple.Safari";
}
async function runAppleScript(script, { humanReadableOutput = true } = {}) {
if (process5.platform !== "darwin") {
throw new Error("macOS only");
}
const outputArguments = humanReadableOutput ? [] : ["-ss"];
const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments]);
return stdout.trim();
}
async function bundleName(bundleId) {
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
}
async function defaultBrowser(_execFileAsync = execFileAsync3) {
const { stdout } = await _execFileAsync("reg", [
"QUERY",
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
"/v",
"ProgId"
]);
const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
if (!match) {
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
}
const { id } = match.groups;
const browser = windowsBrowserProgIds[id];
if (!browser) {
throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
}
return browser;
}
async function defaultBrowser2() {
if (process6.platform === "darwin") {
const id = await defaultBrowserId();
const name = await bundleName(id);
return { name, id };
}
if (process6.platform === "linux") {
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
const id = stdout.trim();
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
return { name, id };
}
if (process6.platform === "win32") {
return defaultBrowser();
}
throw new Error("Only macOS, Linux, and Windows are supported");
}
function detectArchBinary(binary) {
if (typeof binary === "string" || Array.isArray(binary)) {
return binary;
}
const { [arch]: archBinary } = binary;
if (!archBinary) {
throw new Error(`${arch} is not supported`);
}
return archBinary;
}
function detectPlatformBinary({ [platform]: platformBinary }, { wsl }) {
if (wsl && is_wsl_default) {
return detectArchBinary(wsl);
}
if (!platformBinary) {
throw new Error(`${platform} is not supported`);
}
return detectArchBinary(platformBinary);
}
function generatePKCE() {
const codeVerifier = crypto4.randomBytes(64).toString("base64url").substring(0, 128);
const codeChallenge = crypto4.createHash("sha256").update(codeVerifier).digest("base64url");
return {
codeVerifier,
codeChallenge,
codeChallengeMethod: "S256"
};
}
function generateCanonicalResourceURI(serverUrl) {
try {
const url = new URL(serverUrl);
url.protocol = url.protocol.toLowerCase();
url.hostname = url.hostname.toLowerCase();
url.hash = "";
if (url.pathname.endsWith("/") && url.pathname !== "/") {
url.pathname = url.pathname.slice(0, -1);
}
return url.toString();
} catch (error) {
throw new OAuthError(
`Invalid server URL for resource indicator: ${serverUrl}`,
"INVALID_RESOURCE_URI"
);
}
}
async function discoverAuthorizationServerMetadata(authorizationServerUrl) {
try {
const metadataUrl = new URL("/.well-known/oauth-authorization-server", authorizationServerUrl);
logger2.oauth(`Discovering authorization server metadata: ${metadataUrl}`);
const response = await fetch(metadataUrl.toString());
if (!response.ok) {
throw new OAuthError(
`Failed to fetch authorization server metadata: ${response.status}`,
"METADATA_DISCOVERY_FAILED"
);
}
const metadata = await response.json();
if (!metadata.authorization_endpoint || !metadata.token_endpoint) {
throw new OAuthError(
"Authorization server metadata missing required endpoints",
"INVALID_METADATA"
);
}
logger2.oauth("Authorization server metadata discovered successfully");
return metadata;
} catch (error) {
if (error instanceof OAuthError) {
throw error;
}
throw new OAuthError(
`Error discovering authorization server metadata: ${error instanceof Error ? error.message : String(error)}`,
"METADATA_DISCOVE