UNPKG

@automattic/mcp-wpcom-remote

Version:

MCP WordPress.com remote proxy server

1,458 lines (1,457 loc) 2.03 MB
#!/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