Sign In

@zeroheight/mcp-server

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@zeroheight/mcp-server - npm Package Compare versions

Comparing version
2.7.0
to
2.8.0
+46
dist/common/logger.js
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9a180770-fe2e-5d4e-8fa6-708e85b0d7c0")}catch(e){}}();
import { getRequestContext } from "./requestContext.js";
function prefix() {
const ctx = getRequestContext();
if (!ctx)
return {};
const meta = { path: ctx.path, ip: ctx.ip };
if (ctx.userId !== undefined)
meta.userId = ctx.userId;
if (ctx.teamId !== undefined)
meta.teamId = ctx.teamId;
if (ctx.viewerId !== undefined)
meta.viewerId = ctx.viewerId;
return meta;
}
let stderrOnly = false;
export function useStderrOnly() {
stderrOnly = true;
}
function emit(level, args) {
const meta = prefix();
const target = stderrOnly
? console.error
: level === "error"
? console.error
: level === "warn"
? console.warn
: level === "debug"
? console.debug
: console.log;
if (Object.keys(meta).length === 0) {
target(...args);
}
else {
target(meta, ...args);
}
}
export const log = {
debug: (...args) => emit("debug", args),
info: (...args) => emit("info", args),
warn: (...args) => emit("warn", args),
error: (...args) => emit("error", args),
};
//# sourceMappingURL=logger.js.map
//# debugId=9a180770-fe2e-5d4e-8fa6-708e85b0d7c0
{"version":3,"file":"logger.js","sources":["common/logger.ts"],"sourceRoot":"/","sourcesContent":["import { getRequestContext } from \"./requestContext.js\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nfunction prefix(): Record<string, unknown> {\n const ctx = getRequestContext();\n if (!ctx) return {};\n const meta: Record<string, unknown> = { path: ctx.path, ip: ctx.ip };\n if (ctx.userId !== undefined) meta.userId = ctx.userId;\n if (ctx.teamId !== undefined) meta.teamId = ctx.teamId;\n if (ctx.viewerId !== undefined) meta.viewerId = ctx.viewerId;\n return meta;\n}\n\nlet stderrOnly = false;\n\nexport function useStderrOnly(): void {\n stderrOnly = true;\n}\n\nfunction emit(level: LogLevel, args: unknown[]): void {\n const meta = prefix();\n const target = stderrOnly\n ? console.error\n : level === \"error\"\n ? console.error\n : level === \"warn\"\n ? console.warn\n : level === \"debug\"\n ? console.debug\n : console.log;\n\n if (Object.keys(meta).length === 0) {\n target(...args);\n } else {\n target(meta, ...args);\n }\n}\n\nexport const log = {\n debug: (...args: unknown[]) => emit(\"debug\", args),\n info: (...args: unknown[]) => emit(\"info\", args),\n warn: (...args: unknown[]) => emit(\"warn\", args),\n error: (...args: unknown[]) => emit(\"error\", args),\n};\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,SAAS,MAAM;IACb,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,IAAI,GAA4B,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACrE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACvD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACvD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC7D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB,MAAM,UAAU,aAAa;IAC3B,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAED,SAAS,IAAI,CAAC,KAAe,EAAE,IAAe;IAC5C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IACtB,MAAM,MAAM,GAAG,UAAU;QACvB,CAAC,CAAC,OAAO,CAAC,KAAK;QACf,CAAC,CAAC,KAAK,KAAK,OAAO;YACjB,CAAC,CAAC,OAAO,CAAC,KAAK;YACf,CAAC,CAAC,KAAK,KAAK,MAAM;gBAChB,CAAC,CAAC,OAAO,CAAC,IAAI;gBACd,CAAC,CAAC,KAAK,KAAK,OAAO;oBACjB,CAAC,CAAC,OAAO,CAAC,KAAK;oBACf,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAEtB,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;IAClD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;IAChD,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;CACnD,CAAC","debug_id":"9a180770-fe2e-5d4e-8fa6-708e85b0d7c0"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c5b92874-ab43-5ca2-87f5-50f3dd0b4bea")}catch(e){}}();
import { AsyncLocalStorage } from "node:async_hooks";
const storage = new AsyncLocalStorage();
export function runWithRequestContext(context, callback) {
return storage.run(context, callback);
}
export function getRequestContext() {
return storage.getStore();
}
export function setRequestUser(credentials) {
const store = storage.getStore();
if (!store)
return;
if (credentials.type === "client_token")
return;
if (credentials.userId !== undefined)
store.userId = credentials.userId;
if (credentials.viewerId !== undefined)
store.viewerId = credentials.viewerId;
if (credentials.teamId !== undefined)
store.teamId = credentials.teamId;
}
export function setActiveTool(name, args) {
const store = storage.getStore();
if (!store)
return;
store.activeToolName = name;
store.activeToolArgs = args;
store.activeToolStartedAt = Date.now();
}
//# sourceMappingURL=requestContext.js.map
//# debugId=c5b92874-ab43-5ca2-87f5-50f3dd0b4bea
{"version":3,"file":"requestContext.js","sources":["common/requestContext.ts"],"sourceRoot":"/","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { Credentials } from \"./credentials.js\";\n\nexport interface RequestContext {\n path: string;\n ip: string | undefined;\n userId?: number;\n teamId?: number;\n viewerId?: string;\n activeToolName?: string;\n activeToolArgs?: Record<string, unknown>;\n activeToolStartedAt?: number;\n}\n\nconst storage = new AsyncLocalStorage<RequestContext>();\n\nexport function runWithRequestContext<T>(\n context: RequestContext,\n callback: () => T,\n): T {\n return storage.run(context, callback);\n}\n\nexport function getRequestContext(): RequestContext | undefined {\n return storage.getStore();\n}\n\nexport function setRequestUser(credentials: Credentials): void {\n const store = storage.getStore();\n if (!store) return;\n if (credentials.type === \"client_token\") return;\n\n if (credentials.userId !== undefined) store.userId = credentials.userId;\n if (credentials.viewerId !== undefined) store.viewerId = credentials.viewerId;\n if (credentials.teamId !== undefined) store.teamId = credentials.teamId;\n}\n\nexport function setActiveTool(\n name: string,\n args: Record<string, unknown>,\n): void {\n const store = storage.getStore();\n if (!store) return;\n store.activeToolName = name;\n store.activeToolArgs = args;\n store.activeToolStartedAt = Date.now();\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAcrD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAExD,MAAM,UAAU,qBAAqB,CACnC,OAAuB,EACvB,QAAiB;IAEjB,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAAwB;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,IAAI,WAAW,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO;IAEhD,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IACxE,IAAI,WAAW,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC9E,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,IAA6B;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACzC,CAAC","debug_id":"c5b92874-ab43-5ca2-87f5-50f3dd0b4bea"}
/**
* Page Resources
*/
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9beddded-3d0d-51df-8da0-993c3d916a6b")}catch(e){}}();
import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
import { fetchBlobFromUrl } from "../common/formatters/page.js";
import { registerTrackedResource } from "../logging.js";
export function registerPageImageResource(server, context) {
if (!context.features["OAK-37_mcp_image_resources"]) {
return;
}
registerTrackedResource(server, "page-image", new ResourceTemplate("zeroheight://image/{+imageUrl}", { list: undefined }), {
title: "Styleguide page image",
description: "Fetch a single image from a styleguide page by its URL. Preferred over `get-page-images` when only specific images are needed. Image resource URIs are embedded in the content returned by `get-page`. Construct the resource URI by appending the image URL to `zeroheight://image/` (e.g. `zeroheight://image/https://example.com/image.png`).",
}, async (uri, variables) => {
const raw = variables.imageUrl;
if (typeof raw !== "string" || raw.length === 0) {
throw new McpError(ErrorCode.InvalidParams, "No image URL provided.");
}
let parsedUrl;
try {
parsedUrl = new URL(raw);
}
catch {
throw new McpError(ErrorCode.InvalidParams, "Invalid image URL.");
}
if (parsedUrl.protocol !== "https:") {
throw new McpError(ErrorCode.InvalidParams, "Only HTTPS image URLs are supported.");
}
const image = await fetchBlobFromUrl(raw);
if (!image) {
throw new McpError(ErrorCode.InternalError, `Could not fetch image: ${raw}`);
}
return {
contents: [
{
uri: uri.toString(),
blob: image.blob,
mimeType: image.mimeType,
},
],
};
});
}
//# sourceMappingURL=page.js.map
//# debugId=9beddded-3d0d-51df-8da0-993c3d916a6b
{"version":3,"file":"page.js","sources":["resources/page.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Page Resources\n */\n\nimport {\n McpServer,\n ResourceTemplate,\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { McpError, ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { fetchBlobFromUrl } from \"../common/formatters/page.js\";\nimport { registerTrackedResource } from \"../logging.js\";\nimport { ServerContext } from \"../types/server.js\";\n\nexport function registerPageImageResource(\n server: McpServer,\n context: ServerContext,\n) {\n if (!context.features[\"OAK-37_mcp_image_resources\"]) {\n return;\n }\n\n registerTrackedResource(\n server,\n \"page-image\",\n new ResourceTemplate(\"zeroheight://image/{+imageUrl}\", { list: undefined }),\n {\n title: \"Styleguide page image\",\n description:\n \"Fetch a single image from a styleguide page by its URL. Preferred over `get-page-images` when only specific images are needed. Image resource URIs are embedded in the content returned by `get-page`. Construct the resource URI by appending the image URL to `zeroheight://image/` (e.g. `zeroheight://image/https://example.com/image.png`).\",\n },\n async (uri, variables) => {\n const raw = variables.imageUrl;\n if (typeof raw !== \"string\" || raw.length === 0) {\n throw new McpError(ErrorCode.InvalidParams, \"No image URL provided.\");\n }\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(raw);\n } catch {\n throw new McpError(ErrorCode.InvalidParams, \"Invalid image URL.\");\n }\n if (parsedUrl.protocol !== \"https:\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Only HTTPS image URLs are supported.\",\n );\n }\n const image = await fetchBlobFromUrl(raw);\n if (!image) {\n throw new McpError(\n ErrorCode.InternalError,\n `Could not fetch image: ${raw}`,\n );\n }\n return {\n contents: [\n {\n uri: uri.toString(),\n blob: image.blob,\n mimeType: image.mimeType,\n },\n ],\n };\n },\n );\n}\n"],"names":[],"mappings":"AAAA;;GAEG;;;AAEH,OAAO,EAEL,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,MAAM,UAAU,yBAAyB,CACvC,MAAiB,EACjB,OAAsB;IAEtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,CAAC;QACpD,OAAO;IACT,CAAC;IAED,uBAAuB,CACrB,MAAM,EACN,YAAY,EACZ,IAAI,gBAAgB,CAAC,gCAAgC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAC3E;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,kVAAkV;KACrV,EACD,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;QAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,wBAAwB,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,SAAc,CAAC;QACnB,IAAI,CAAC;YACH,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,sCAAsC,CACvC,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,0BAA0B,GAAG,EAAE,CAChC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;iBACzB;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC","debug_id":"9beddded-3d0d-51df-8da0-993c3d916a6b"}
+4
-0
## Release notes
## [2.8.0](https://www.npmjs.com/package/@zeroheight/mcp-server/v/2.8.0) - 23rd April 2026
- `get-page-images` now also includes image-typed file attachments
## [2.7.0](https://www.npmjs.com/package/@zeroheight/mcp-server/v/2.7.0) - 1st April 2026

@@ -4,0 +8,0 @@

+19
-6
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5187beba-eaa2-55de-86e1-1867179935f5")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a817ecf8-fc58-5e47-ace2-d6ffb941bc80")}catch(e){}}();
import * as Sentry from "@sentry/node";
import { log } from "../common/logger.js";
import { IncorrectScopeError, MaxRetriesError, NotFoundError, UnauthorizedError, UnknownError, } from "./errors.js";
import packageJson from "../../package.json" with { type: "json" };
const API_PATH = "/open_api/v2";
const EXPERIMENTAL_API_PATH = "/open_api/experimental";
const USER_AGENT = `zeroheight-mcp-server/${packageJson.version}`;

@@ -11,2 +13,3 @@ export var ApiType;

ApiType["OpenApi"] = "open_api";
ApiType["OpenApiExperimental"] = "open_api_experimental";
ApiType["Internal"] = "internal";

@@ -38,5 +41,15 @@ })(ApiType || (ApiType = {}));

}
function pathPrefixFor(apiType) {
switch (apiType) {
case ApiType.OpenApi:
return API_PATH;
case ApiType.OpenApiExperimental:
return EXPERIMENTAL_API_PATH;
case ApiType.Internal:
return "/api";
}
}
export async function request(path, credentials, init, search, apiType = ApiType.OpenApi, metadata = {}) {
const url = getZeroheightURL();
url.pathname = (apiType === ApiType.OpenApi ? API_PATH : "/api") + path;
url.pathname = pathPrefixFor(apiType) + path;
if (search) {

@@ -81,3 +94,3 @@ url.search = "?" + search.toString();

if (response.status === 401) {
console.error("Unauthorized response from API", {
log.error("Unauthorized response from API", {
response: { status: response.status, body: await response.text() },

@@ -101,3 +114,3 @@ });

else if (response.status < 200 || response.status >= 300) {
console.error("API request failed", {
log.error("API request failed", {
response: { status: response.status, body: await response.text() },

@@ -138,3 +151,3 @@ });

if (response.status < 200 || response.status >= 300) {
console.error("Internal API request failed", {
log.error("Internal API request failed", {
response: { status: response.status, body: await response.text() },

@@ -157,2 +170,2 @@ });

//# sourceMappingURL=api.js.map
//# debugId=5187beba-eaa2-55de-86e1-1867179935f5
//# debugId=a817ecf8-fc58-5e47-ace2-d6ffb941bc80

@@ -1,1 +0,1 @@

{"version":3,"file":"api.js","sources":["api/api.ts"],"sourceRoot":"/","sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport {\n IncorrectScopeError,\n MaxRetriesError,\n NotFoundError,\n UnauthorizedError,\n UnknownError,\n} from \"./errors.js\";\n\nimport packageJson from \"../../package.json\" with { type: \"json\" };\n\nimport { Credentials } from \"../common/credentials.js\";\n\nconst API_PATH = \"/open_api/v2\";\nconst USER_AGENT = `zeroheight-mcp-server/${packageJson.version}`;\n\nexport enum ApiType {\n OpenApi = \"open_api\", // /open_api/v2\n Internal = \"internal\", // /api\n}\n\nexport enum ResponseStatus {\n Success = \"success\",\n Error = \"error\",\n Fail = \"fail\",\n}\n\n/**\n * Open API V2 Response format\n */\n\ninterface BaseResponse<T> {\n status: ResponseStatus;\n message: string;\n data: T;\n}\n\ninterface SuccessResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Success;\n}\n\ninterface FailResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Fail;\n}\n\ninterface ErrorResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Error;\n}\n\nexport type APIResponse<S = {}, F = {}, E = {}> =\n | SuccessResponse<S>\n | FailResponse<F>\n | ErrorResponse<E>;\n\n/**\n * Get the correct URL for production of development depending on the environment variable\n */\nexport function getZeroheightURL() {\n const zeroheightURL = process.env[\"ZEROHEIGHT_URL\"];\n if (zeroheightURL) {\n return new URL(zeroheightURL);\n }\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n return new URL(\"https://zeroheight.dev\");\n } else {\n return new URL(\"https://zeroheight.com\");\n }\n}\n\nasync function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function request<R>(\n path: string,\n credentials: Credentials,\n init: RequestInit,\n search?: URLSearchParams,\n apiType: ApiType = ApiType.OpenApi,\n metadata: { clientUserAgent?: string } = {},\n): Promise<R> {\n const url = getZeroheightURL();\n url.pathname = (apiType === ApiType.OpenApi ? API_PATH : \"/api\") + path;\n if (search) {\n url.search = \"?\" + search.toString();\n }\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n process.env[\"NODE_TLS_REJECT_UNAUTHORIZED\"] = \"0\";\n }\n\n const maxRetries = 3;\n let retries = 0;\n\n const headers: Record<string, string> = {\n \"X-API-CLIENT-NAME\": \"mcp-server\",\n \"X-API-CLIENT-VERSION\": packageJson.version,\n \"User-Agent\": USER_AGENT,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n\n if (metadata.clientUserAgent) {\n headers[\"X-MCP-Client-User-Agent\"] = metadata.clientUserAgent;\n }\n\n if (credentials.type === \"jwt\") {\n headers[\"Authorization\"] = `Bearer ${credentials.jwt}`;\n headers[\"X-API-CLIENT-NAME\"] = \"remote-mcp-server\";\n if (credentials.mcpAuthId) {\n headers[\"X-MCP-Auth-ID\"] = String(credentials.mcpAuthId);\n }\n } else if (credentials.type === \"oauth_jwt\") {\n headers[\"Authorization\"] = `Bearer ${credentials.jwt}`;\n headers[\"X-API-CLIENT-NAME\"] = `remote-mcp-server:${credentials.clientId}`;\n } else {\n headers[\"X-API-CLIENT\"] = credentials.client;\n headers[\"X-API-KEY\"] = credentials.token;\n }\n\n while (retries < maxRetries) {\n const response = await fetch(url, {\n ...init,\n headers,\n });\n\n if (response.status === 401) {\n console.error(\"Unauthorized response from API\", {\n response: { status: response.status, body: await response.text() },\n });\n throw new UnauthorizedError();\n } else if (response.status === 429) {\n retries++;\n let waitTime: number;\n if (apiType === ApiType.OpenApi) {\n const responseData = await response.json();\n waitTime = responseData.data.reset_time * 1000 - Date.now();\n } else {\n waitTime = 2 ** retries * 1000;\n }\n await sleep(waitTime);\n continue;\n } else if (response.status < 200 || response.status >= 300) {\n console.error(\"API request failed\", {\n response: { status: response.status, body: await response.text() },\n });\n\n if (response.status === 403) {\n throw new IncorrectScopeError();\n } else if (response.status === 404) {\n throw new NotFoundError();\n } else {\n Sentry.captureMessage(\n `Unknown error occurred making request to: ${url}`,\n );\n throw new UnknownError();\n }\n }\n\n const responseJson = await response.json();\n return responseJson;\n }\n\n throw new MaxRetriesError();\n}\n\nexport async function internalRequest<R>(\n path: string,\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n body: any,\n): Promise<R> {\n const url = getZeroheightURL();\n url.pathname = \"/api\" + path;\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n process.env[\"NODE_TLS_REJECT_UNAUTHORIZED\"] = \"0\";\n }\n\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": USER_AGENT,\n \"X-API-KEY\": process.env[\"INTERNAL_API_KEY\"] || \"\",\n },\n body: JSON.stringify(body),\n });\n\n if (response.status < 200 || response.status >= 300) {\n console.error(\"Internal API request failed\", {\n response: { status: response.status, body: await response.text() },\n });\n\n if (response.status === 401) {\n throw new UnauthorizedError();\n } else if (response.status === 404) {\n throw new NotFoundError();\n } else {\n Sentry.captureMessage(\n `Unknown error occurred making internal request to: ${url}`,\n );\n throw new UnknownError();\n }\n }\n\n const responseJson = await response.json();\n return responseJson;\n}\n"],"names":[],"mappings":"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","debug_id":"5187beba-eaa2-55de-86e1-1867179935f5"}
{"version":3,"file":"api.js","sources":["api/api.ts"],"sourceRoot":"/","sourcesContent":["import * as Sentry from \"@sentry/node\";\nimport { log } from \"../common/logger.js\";\nimport {\n IncorrectScopeError,\n MaxRetriesError,\n NotFoundError,\n UnauthorizedError,\n UnknownError,\n} from \"./errors.js\";\n\nimport packageJson from \"../../package.json\" with { type: \"json\" };\n\nimport { Credentials } from \"../common/credentials.js\";\n\nconst API_PATH = \"/open_api/v2\";\nconst EXPERIMENTAL_API_PATH = \"/open_api/experimental\";\nconst USER_AGENT = `zeroheight-mcp-server/${packageJson.version}`;\n\nexport enum ApiType {\n OpenApi = \"open_api\", // /open_api/v2\n OpenApiExperimental = \"open_api_experimental\", // /open_api/experimental\n Internal = \"internal\", // /api\n}\n\nexport enum ResponseStatus {\n Success = \"success\",\n Error = \"error\",\n Fail = \"fail\",\n}\n\n/**\n * Open API V2 Response format\n */\n\ninterface BaseResponse<T> {\n status: ResponseStatus;\n message: string;\n data: T;\n}\n\ninterface SuccessResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Success;\n}\n\ninterface FailResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Fail;\n}\n\ninterface ErrorResponse<T> extends BaseResponse<T> {\n status: ResponseStatus.Error;\n}\n\nexport type APIResponse<S = {}, F = {}, E = {}> =\n | SuccessResponse<S>\n | FailResponse<F>\n | ErrorResponse<E>;\n\n/**\n * Get the correct URL for production of development depending on the environment variable\n */\nexport function getZeroheightURL() {\n const zeroheightURL = process.env[\"ZEROHEIGHT_URL\"];\n if (zeroheightURL) {\n return new URL(zeroheightURL);\n }\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n return new URL(\"https://zeroheight.dev\");\n } else {\n return new URL(\"https://zeroheight.com\");\n }\n}\n\nasync function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction pathPrefixFor(apiType: ApiType): string {\n switch (apiType) {\n case ApiType.OpenApi:\n return API_PATH;\n case ApiType.OpenApiExperimental:\n return EXPERIMENTAL_API_PATH;\n case ApiType.Internal:\n return \"/api\";\n }\n}\n\nexport async function request<R>(\n path: string,\n credentials: Credentials,\n init: RequestInit,\n search?: URLSearchParams,\n apiType: ApiType = ApiType.OpenApi,\n metadata: { clientUserAgent?: string } = {},\n): Promise<R> {\n const url = getZeroheightURL();\n url.pathname = pathPrefixFor(apiType) + path;\n if (search) {\n url.search = \"?\" + search.toString();\n }\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n process.env[\"NODE_TLS_REJECT_UNAUTHORIZED\"] = \"0\";\n }\n\n const maxRetries = 3;\n let retries = 0;\n\n const headers: Record<string, string> = {\n \"X-API-CLIENT-NAME\": \"mcp-server\",\n \"X-API-CLIENT-VERSION\": packageJson.version,\n \"User-Agent\": USER_AGENT,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n\n if (metadata.clientUserAgent) {\n headers[\"X-MCP-Client-User-Agent\"] = metadata.clientUserAgent;\n }\n\n if (credentials.type === \"jwt\") {\n headers[\"Authorization\"] = `Bearer ${credentials.jwt}`;\n headers[\"X-API-CLIENT-NAME\"] = \"remote-mcp-server\";\n if (credentials.mcpAuthId) {\n headers[\"X-MCP-Auth-ID\"] = String(credentials.mcpAuthId);\n }\n } else if (credentials.type === \"oauth_jwt\") {\n headers[\"Authorization\"] = `Bearer ${credentials.jwt}`;\n headers[\"X-API-CLIENT-NAME\"] = `remote-mcp-server:${credentials.clientId}`;\n } else {\n headers[\"X-API-CLIENT\"] = credentials.client;\n headers[\"X-API-KEY\"] = credentials.token;\n }\n\n while (retries < maxRetries) {\n const response = await fetch(url, {\n ...init,\n headers,\n });\n\n if (response.status === 401) {\n log.error(\"Unauthorized response from API\", {\n response: { status: response.status, body: await response.text() },\n });\n throw new UnauthorizedError();\n } else if (response.status === 429) {\n retries++;\n let waitTime: number;\n if (apiType === ApiType.OpenApi) {\n const responseData = await response.json();\n waitTime = responseData.data.reset_time * 1000 - Date.now();\n } else {\n waitTime = 2 ** retries * 1000;\n }\n await sleep(waitTime);\n continue;\n } else if (response.status < 200 || response.status >= 300) {\n log.error(\"API request failed\", {\n response: { status: response.status, body: await response.text() },\n });\n\n if (response.status === 403) {\n throw new IncorrectScopeError();\n } else if (response.status === 404) {\n throw new NotFoundError();\n } else {\n Sentry.captureMessage(\n `Unknown error occurred making request to: ${url}`,\n );\n throw new UnknownError();\n }\n }\n\n const responseJson = await response.json();\n return responseJson;\n }\n\n throw new MaxRetriesError();\n}\n\nexport async function internalRequest<R>(\n path: string,\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n body: any,\n): Promise<R> {\n const url = getZeroheightURL();\n url.pathname = \"/api\" + path;\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n process.env[\"NODE_TLS_REJECT_UNAUTHORIZED\"] = \"0\";\n }\n\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"User-Agent\": USER_AGENT,\n \"X-API-KEY\": process.env[\"INTERNAL_API_KEY\"] || \"\",\n },\n body: JSON.stringify(body),\n });\n\n if (response.status < 200 || response.status >= 300) {\n log.error(\"Internal API request failed\", {\n response: { status: response.status, body: await response.text() },\n });\n\n if (response.status === 401) {\n throw new UnauthorizedError();\n } else if (response.status === 404) {\n throw new NotFoundError();\n } else {\n Sentry.captureMessage(\n `Unknown error occurred making internal request to: ${url}`,\n );\n throw new UnknownError();\n }\n }\n\n const responseJson = await response.json();\n return responseJson;\n}\n"],"names":[],"mappings":"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","debug_id":"a817ecf8-fc58-5e47-ace2-d6ffb941bc80"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="209959a5-32d5-556f-9bdd-8e06b0de90bb")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="90adacd6-9032-5c2c-816f-3d96b3af0b2b")}catch(e){}}();
export class ApiError extends Error {

@@ -39,3 +39,8 @@ constructor(message) {

}
export function isExpectedAuthError(error) {
return (error instanceof InvalidCredentialsError ||
error instanceof UnauthorizedError ||
error instanceof IncorrectScopeError);
}
//# sourceMappingURL=errors.js.map
//# debugId=209959a5-32d5-556f-9bdd-8e06b0de90bb
//# debugId=90adacd6-9032-5c2c-816f-3d96b3af0b2b

@@ -1,1 +0,1 @@

{"version":3,"file":"errors.js","sources":["api/errors.ts"],"sourceRoot":"/","sourcesContent":["export class ApiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport class UnauthorizedError extends ApiError {\n constructor() {\n super(\"Unauthorized. Please ensure you have added your credentials.\");\n }\n}\n\nexport class IncorrectScopeError extends ApiError {\n constructor() {\n super(\n \"The authentication token used does not have the correct scope. \\n\\nPlease create a new authentication token with the relevant scopes and then update your credentials.\",\n );\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor() {\n super(\n \"The requested resource was not found. It may have been deleted or you may not have access to it.\",\n );\n }\n}\n\nexport class InvalidCredentialsError extends ApiError {\n constructor() {\n super(\n \"Your credentials could not be verified. The token may be invalid or expired.\",\n );\n }\n}\n\nexport class UnknownError extends ApiError {\n constructor() {\n super(\"An unknown error occurred while calling the zeroheight API\");\n }\n}\n\nexport class MaxRetriesError extends ApiError {\n constructor() {\n super(\"Max retries exceeded while calling the zeroheight API\");\n }\n}\n"],"names":[],"mappings":";;AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,QAAQ;IAC7C;QACE,KAAK,CAAC,8DAA8D,CAAC,CAAC;IACxE,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,QAAQ;IAC/C;QACE,KAAK,CACH,wKAAwK,CACzK,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,QAAQ;IACzC;QACE,KAAK,CACH,kGAAkG,CACnG,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,QAAQ;IACnD;QACE,KAAK,CACH,8EAA8E,CAC/E,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,QAAQ;IACxC;QACE,KAAK,CAAC,4DAA4D,CAAC,CAAC;IACtE,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3C;QACE,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACjE,CAAC;CACF","debug_id":"209959a5-32d5-556f-9bdd-8e06b0de90bb"}
{"version":3,"file":"errors.js","sources":["api/errors.ts"],"sourceRoot":"/","sourcesContent":["export class ApiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport class UnauthorizedError extends ApiError {\n constructor() {\n super(\"Unauthorized. Please ensure you have added your credentials.\");\n }\n}\n\nexport class IncorrectScopeError extends ApiError {\n constructor() {\n super(\n \"The authentication token used does not have the correct scope. \\n\\nPlease create a new authentication token with the relevant scopes and then update your credentials.\",\n );\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor() {\n super(\n \"The requested resource was not found. It may have been deleted or you may not have access to it.\",\n );\n }\n}\n\nexport class InvalidCredentialsError extends ApiError {\n constructor() {\n super(\n \"Your credentials could not be verified. The token may be invalid or expired.\",\n );\n }\n}\n\nexport class UnknownError extends ApiError {\n constructor() {\n super(\"An unknown error occurred while calling the zeroheight API\");\n }\n}\n\nexport class MaxRetriesError extends ApiError {\n constructor() {\n super(\"Max retries exceeded while calling the zeroheight API\");\n }\n}\n\nexport function isExpectedAuthError(error: unknown): boolean {\n return (\n error instanceof InvalidCredentialsError ||\n error instanceof UnauthorizedError ||\n error instanceof IncorrectScopeError\n );\n}\n"],"names":[],"mappings":";;AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,QAAQ;IAC7C;QACE,KAAK,CAAC,8DAA8D,CAAC,CAAC;IACxE,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,QAAQ;IAC/C;QACE,KAAK,CACH,wKAAwK,CACzK,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,QAAQ;IACzC;QACE,KAAK,CACH,kGAAkG,CACnG,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,QAAQ;IACnD;QACE,KAAK,CACH,8EAA8E,CAC/E,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,QAAQ;IACxC;QACE,KAAK,CAAC,4DAA4D,CAAC,CAAC;IACtE,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3C;QACE,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACjE,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,OAAO,CACL,KAAK,YAAY,uBAAuB;QACxC,KAAK,YAAY,iBAAiB;QAClC,KAAK,YAAY,mBAAmB,CACrC,CAAC;AACJ,CAAC","debug_id":"90adacd6-9032-5c2c-816f-3d96b3af0b2b"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4cc32259-80f6-5153-bf7c-7e2ca8c7578d")}catch(e){}}();
import { request } from "./api.js";
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="829c864d-fd21-56b5-9323-ecdbe40a8e84")}catch(e){}}();
import { ApiType, request } from "./api.js";
import { UnknownError } from "./errors.js";

@@ -38,3 +38,3 @@ import { captureException } from "../common/errors.js";

method: "GET",
}, searchParams, undefined, { clientUserAgent });
}, searchParams, ApiType.OpenApiExperimental, { clientUserAgent });
if ("page" in response.data) {

@@ -77,2 +77,2 @@ return response.data.page;

//# sourceMappingURL=page.js.map
//# debugId=4cc32259-80f6-5153-bf7c-7e2ca8c7578d
//# debugId=829c864d-fd21-56b5-9323-ecdbe40a8e84

@@ -1,1 +0,1 @@

{"version":3,"file":"page.js","sources":["api/page.ts"],"sourceRoot":"/","sourcesContent":["import { Credentials } from \"../common/credentials.js\";\nimport { APIResponse, request } from \"./api.js\";\nimport { UnknownError } from \"./errors.js\";\nimport { Page, PageListItem, PageSearchResultItem } from \"./types/page.js\";\nimport { captureException } from \"../common/errors.js\";\n\ninterface PageListSuccessResponse {\n pages: PageListItem[];\n}\n\ninterface PageListOptionalParams {\n searchTerm: string;\n releaseId: number;\n}\n\nexport async function listPages(\n credentials: Credentials,\n styleguideId: number,\n optionalParams: Partial<PageListOptionalParams> = {},\n clientUserAgent?: string,\n) {\n try {\n const searchParams = new URLSearchParams({\n show_hidden: \"false\",\n });\n\n if (optionalParams.releaseId) {\n searchParams.set(\"release_id\", optionalParams.releaseId.toString());\n }\n\n if (optionalParams.searchTerm) {\n searchParams.set(\"search\", optionalParams.searchTerm);\n }\n\n const response = await request<\n APIResponse<PageListSuccessResponse, {}, {}>\n >(\n `/styleguides/${styleguideId}/pages`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"pages\" in response.data) {\n return response.data.pages;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n\ninterface PageSuccessResponse {\n page: Page;\n}\n\ninterface PageOptionalParams {\n releaseId: number;\n}\n\nexport async function getPage(\n credentials: Credentials,\n pageId: number | string,\n optionalParams: Partial<PageOptionalParams> = {},\n clientUserAgent?: string,\n) {\n try {\n const searchParams = new URLSearchParams();\n\n if (optionalParams.releaseId) {\n searchParams.set(\"release_id\", optionalParams.releaseId.toString());\n }\n\n const response = await request<APIResponse<PageSuccessResponse, {}, {}>>(\n `/pages/${pageId}`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"page\" in response.data) {\n return response.data.page;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return null;\n }\n}\n\ninterface SearchSuccessResponse {\n results: PageSearchResultItem[];\n}\n\nexport async function searchPages(\n credentials: Credentials,\n styleguideId: number,\n query: string,\n releaseId?: number,\n clientUserAgent?: string,\n) {\n try {\n const filters: Record<string, number | string> = {\n type: \"page\",\n styleguide_id: styleguideId,\n };\n\n if (typeof releaseId === \"number\") {\n filters[\"styleguide_version_id\"] = releaseId;\n }\n\n const response = await request<APIResponse<SearchSuccessResponse, {}, {}>>(\n `/search`,\n credentials,\n {\n method: \"POST\",\n body: JSON.stringify({\n query,\n filters,\n }),\n },\n undefined,\n undefined,\n { clientUserAgent },\n );\n\n if (\"results\" in response.data) {\n return response.data.results;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n"],"names":[],"mappings":"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","debug_id":"4cc32259-80f6-5153-bf7c-7e2ca8c7578d"}
{"version":3,"file":"page.js","sources":["api/page.ts"],"sourceRoot":"/","sourcesContent":["import { Credentials } from \"../common/credentials.js\";\nimport { APIResponse, ApiType, request } from \"./api.js\";\nimport { UnknownError } from \"./errors.js\";\nimport { Page, PageListItem, PageSearchResultItem } from \"./types/page.js\";\nimport { captureException } from \"../common/errors.js\";\n\ninterface PageListSuccessResponse {\n pages: PageListItem[];\n}\n\ninterface PageListOptionalParams {\n searchTerm: string;\n releaseId: number;\n}\n\nexport async function listPages(\n credentials: Credentials,\n styleguideId: number,\n optionalParams: Partial<PageListOptionalParams> = {},\n clientUserAgent?: string,\n) {\n try {\n const searchParams = new URLSearchParams({\n show_hidden: \"false\",\n });\n\n if (optionalParams.releaseId) {\n searchParams.set(\"release_id\", optionalParams.releaseId.toString());\n }\n\n if (optionalParams.searchTerm) {\n searchParams.set(\"search\", optionalParams.searchTerm);\n }\n\n const response = await request<\n APIResponse<PageListSuccessResponse, {}, {}>\n >(\n `/styleguides/${styleguideId}/pages`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"pages\" in response.data) {\n return response.data.pages;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n\ninterface PageSuccessResponse {\n page: Page;\n}\n\ninterface PageOptionalParams {\n releaseId: number;\n}\n\nexport async function getPage(\n credentials: Credentials,\n pageId: number | string,\n optionalParams: Partial<PageOptionalParams> = {},\n clientUserAgent?: string,\n) {\n try {\n const searchParams = new URLSearchParams();\n\n if (optionalParams.releaseId) {\n searchParams.set(\"release_id\", optionalParams.releaseId.toString());\n }\n\n const response = await request<APIResponse<PageSuccessResponse, {}, {}>>(\n `/pages/${pageId}`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n ApiType.OpenApiExperimental,\n { clientUserAgent },\n );\n\n if (\"page\" in response.data) {\n return response.data.page;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return null;\n }\n}\n\ninterface SearchSuccessResponse {\n results: PageSearchResultItem[];\n}\n\nexport async function searchPages(\n credentials: Credentials,\n styleguideId: number,\n query: string,\n releaseId?: number,\n clientUserAgent?: string,\n) {\n try {\n const filters: Record<string, number | string> = {\n type: \"page\",\n styleguide_id: styleguideId,\n };\n\n if (typeof releaseId === \"number\") {\n filters[\"styleguide_version_id\"] = releaseId;\n }\n\n const response = await request<APIResponse<SearchSuccessResponse, {}, {}>>(\n `/search`,\n credentials,\n {\n method: \"POST\",\n body: JSON.stringify({\n query,\n filters,\n }),\n },\n undefined,\n undefined,\n { clientUserAgent },\n );\n\n if (\"results\" in response.data) {\n return response.data.results;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAe,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAWvD,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,WAAwB,EACxB,YAAoB,EACpB,iBAAkD,EAAE,EACpD,eAAwB;IAExB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC;YACvC,WAAW,EAAE,OAAO;SACrB,CAAC,CAAC;QAEH,IAAI,cAAc,CAAC,SAAS,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,cAAc,CAAC,UAAU,EAAE,CAAC;YAC9B,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,gBAAgB,YAAY,QAAQ,EACpC,WAAW,EACX;YACE,MAAM,EAAE,KAAK;SACd,EACD,YAAY,EACZ,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAC7B,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAUD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,WAAwB,EACxB,MAAuB,EACvB,iBAA8C,EAAE,EAChD,eAAwB;IAExB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE,CAAC;QAE3C,IAAI,cAAc,CAAC,SAAS,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,UAAU,MAAM,EAAE,EAClB,WAAW,EACX;YACE,MAAM,EAAE,KAAK;SACd,EACD,YAAY,EACZ,OAAO,CAAC,mBAAmB,EAC3B,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAwB,EACxB,YAAoB,EACpB,KAAa,EACb,SAAkB,EAClB,eAAwB;IAExB,IAAI,CAAC;QACH,MAAM,OAAO,GAAoC;YAC/C,IAAI,EAAE,MAAM;YACZ,aAAa,EAAE,YAAY;SAC5B,CAAC;QAEF,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,CAAC;QAC/C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,SAAS,EACT,WAAW,EACX;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,OAAO;aACR,CAAC;SACH,EACD,SAAS,EACT,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;QAC/B,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC","debug_id":"829c864d-fd21-56b5-9323-ecdbe40a8e84"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9f2ff797-d5ab-50eb-a199-5a5ddc18f7d2")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fdecf984-8774-5ff8-aaaa-8bb35817515c")}catch(e){}}();
import { request } from "./api.js";

@@ -52,3 +52,2 @@ import { UnknownError } from "./errors.js";

}
console.error(response);
throw new UnknownError();

@@ -62,2 +61,2 @@ }

//# sourceMappingURL=styleguide.js.map
//# debugId=9f2ff797-d5ab-50eb-a199-5a5ddc18f7d2
//# debugId=fdecf984-8774-5ff8-aaaa-8bb35817515c

@@ -1,1 +0,1 @@

{"version":3,"file":"styleguide.js","sources":["api/styleguide.ts"],"sourceRoot":"/","sourcesContent":["import { APIResponse, request } from \"./api.js\";\nimport { UnknownError } from \"./errors.js\";\nimport { Credentials } from \"../common/credentials.js\";\nimport {\n CategoryNode,\n NavigationNode,\n PageNode,\n Styleguide,\n StyleguideVersion,\n} from \"./types/styleguide.js\";\nimport { captureException } from \"../common/errors.js\";\n\ninterface StyleguideListSuccessResponse {\n styleguides: Styleguide[];\n}\n\nexport async function listStyleguides(credentials: Credentials, clientUserAgent?: string) {\n try {\n const response = await request<\n APIResponse<StyleguideListSuccessResponse, {}, {}>\n >(\"/styleguides\", credentials, {\n method: \"GET\",\n }, undefined, undefined, { clientUserAgent });\n\n if (\"styleguides\" in response.data) {\n if (credentials.type === \"jwt\") {\n return response.data.styleguides.filter(\n (sg) => sg.id === credentials.styleguideId,\n );\n }\n\n return response.data.styleguides;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n\ninterface StyleguideVersionsSuccessResponse {\n versions: StyleguideVersion[];\n}\n\nexport async function listStyleguideVersions(credentials: Credentials, styleguideId: number, clientUserAgent?: string): Promise<StyleguideVersion[]> {\n const searchParams = new URLSearchParams({ show_hidden: \"false\" });\n\n try {\n const response = await request<\n APIResponse<StyleguideVersionsSuccessResponse, {}, {}>\n >(\n `/styleguides/${styleguideId}/versions`,\n credentials,\n { method: \"GET\" },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"versions\" in response.data) {\n return response.data.versions;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n throw e;\n }\n}\n\ninterface SyleguideTreeSuccessResponse {\n tree: (PageNode | CategoryNode | NavigationNode)[];\n}\n\nexport async function getStyleguideTree(credentials: Credentials, id: number, clientUserAgent?: string, releaseId?: number) {\n const searchParams = new URLSearchParams({\n show_hidden: \"false\",\n });\n if (releaseId) {\n searchParams.set(\"release_id\", String(releaseId));\n }\n\n try {\n const response = await request<\n APIResponse<SyleguideTreeSuccessResponse, {}, {}>\n >(\n `/styleguides/${id}/tree`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"tree\" in response.data) {\n return response.data.tree;\n }\n\n console.error(response);\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n throw e;\n }\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMvD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAAwB,EAAE,eAAwB;IACtF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAE5B,cAAc,EAAE,WAAW,EAAE;YAC7B,MAAM,EAAE,KAAK;SACd,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC;QAE9C,IAAI,aAAa,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,WAAW,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CACrC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,WAAW,CAAC,YAAY,CAC3C,CAAC;YACJ,CAAC;YAED,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;QACnC,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,WAAwB,EAAE,YAAoB,EAAE,eAAwB;IACnH,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,gBAAgB,YAAY,WAAW,EACvC,WAAW,EACX,EAAE,MAAM,EAAE,KAAK,EAAE,EACjB,YAAY,EACZ,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAChC,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;QAChC,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAwB,EAAE,EAAU,EAAE,eAAwB,EAAE,SAAkB;IACxH,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC;QACvC,WAAW,EAAE,OAAO;KACrB,CAAC,CAAC;IACH,IAAI,SAAS,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,gBAAgB,EAAE,OAAO,EACzB,WAAW,EACX;YACE,MAAM,EAAE,KAAK;SACd,EACD,YAAY,EACZ,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC","debug_id":"9f2ff797-d5ab-50eb-a199-5a5ddc18f7d2"}
{"version":3,"file":"styleguide.js","sources":["api/styleguide.ts"],"sourceRoot":"/","sourcesContent":["import { APIResponse, request } from \"./api.js\";\nimport { UnknownError } from \"./errors.js\";\nimport { Credentials } from \"../common/credentials.js\";\nimport {\n CategoryNode,\n NavigationNode,\n PageNode,\n Styleguide,\n StyleguideVersion,\n} from \"./types/styleguide.js\";\nimport { captureException } from \"../common/errors.js\";\n\ninterface StyleguideListSuccessResponse {\n styleguides: Styleguide[];\n}\n\nexport async function listStyleguides(\n credentials: Credentials,\n clientUserAgent?: string,\n) {\n try {\n const response = await request<\n APIResponse<StyleguideListSuccessResponse, {}, {}>\n >(\n \"/styleguides\",\n credentials,\n {\n method: \"GET\",\n },\n undefined,\n undefined,\n { clientUserAgent },\n );\n\n if (\"styleguides\" in response.data) {\n if (credentials.type === \"jwt\") {\n return response.data.styleguides.filter(\n (sg) => sg.id === credentials.styleguideId,\n );\n }\n\n return response.data.styleguides;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n return [];\n }\n}\n\ninterface StyleguideVersionsSuccessResponse {\n versions: StyleguideVersion[];\n}\n\nexport async function listStyleguideVersions(\n credentials: Credentials,\n styleguideId: number,\n clientUserAgent?: string,\n): Promise<StyleguideVersion[]> {\n const searchParams = new URLSearchParams({ show_hidden: \"false\" });\n\n try {\n const response = await request<\n APIResponse<StyleguideVersionsSuccessResponse, {}, {}>\n >(\n `/styleguides/${styleguideId}/versions`,\n credentials,\n { method: \"GET\" },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"versions\" in response.data) {\n return response.data.versions;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n throw e;\n }\n}\n\ninterface SyleguideTreeSuccessResponse {\n tree: (PageNode | CategoryNode | NavigationNode)[];\n}\n\nexport async function getStyleguideTree(\n credentials: Credentials,\n id: number,\n clientUserAgent?: string,\n releaseId?: number,\n) {\n const searchParams = new URLSearchParams({\n show_hidden: \"false\",\n });\n if (releaseId) {\n searchParams.set(\"release_id\", String(releaseId));\n }\n\n try {\n const response = await request<\n APIResponse<SyleguideTreeSuccessResponse, {}, {}>\n >(\n `/styleguides/${id}/tree`,\n credentials,\n {\n method: \"GET\",\n },\n searchParams,\n undefined,\n { clientUserAgent },\n );\n\n if (\"tree\" in response.data) {\n return response.data.tree;\n }\n\n throw new UnknownError();\n } catch (e) {\n captureException(e);\n throw e;\n }\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMvD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAwB,EACxB,eAAwB;IAExB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,cAAc,EACd,WAAW,EACX;YACE,MAAM,EAAE,KAAK;SACd,EACD,SAAS,EACT,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,aAAa,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,WAAW,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBAC/B,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CACrC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,WAAW,CAAC,YAAY,CAC3C,CAAC;YACJ,CAAC;YAED,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;QACnC,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,WAAwB,EACxB,YAAoB,EACpB,eAAwB;IAExB,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,gBAAgB,YAAY,WAAW,EACvC,WAAW,EACX,EAAE,MAAM,EAAE,KAAK,EAAE,EACjB,YAAY,EACZ,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAChC,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;QAChC,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAwB,EACxB,EAAU,EACV,eAAwB,EACxB,SAAkB;IAElB,MAAM,YAAY,GAAG,IAAI,eAAe,CAAC;QACvC,WAAW,EAAE,OAAO;KACrB,CAAC,CAAC;IACH,IAAI,SAAS,EAAE,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAG5B,gBAAgB,EAAE,OAAO,EACzB,WAAW,EACX;YACE,MAAM,EAAE,KAAK;SACd,EACD,YAAY,EACZ,SAAS,EACT,EAAE,eAAe,EAAE,CACpB,CAAC;QAEF,IAAI,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,MAAM,IAAI,YAAY,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC","debug_id":"fdecf984-8774-5ff8-aaaa-8bb35817515c"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bf5b0fee-6c8e-580b-8cc7-2bb23ef8efb0")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2c2b6c69-c5be-5ccf-8943-821ae688a601")}catch(e){}}();
export {};
//# sourceMappingURL=page.js.map
//# debugId=bf5b0fee-6c8e-580b-8cc7-2bb23ef8efb0
//# debugId=2c2b6c69-c5be-5ccf-8943-821ae688a601

@@ -1,1 +0,1 @@

{"version":3,"file":"page.js","sources":["api/types/page.ts"],"sourceRoot":"/","sourcesContent":["export interface PageListItem {\n id: number;\n name: string;\n hidden: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PageSearchResultItem {\n id: number;\n type: string;\n name: string;\n hidden: boolean;\n url: string;\n matching_chunk: string;\n score: number;\n}\n\nexport interface Tab {\n name: string;\n hidden: boolean;\n order: number;\n uid: string;\n url: string;\n content: string;\n}\n\nexport interface PageStatus {\n id: string;\n name: string;\n}\n\nexport interface Page {\n id: number;\n uid: string;\n slug: string;\n url: string;\n name: string;\n introduction: string;\n hidden: boolean;\n locked: boolean;\n created_at: string;\n updated_at: string;\n status: PageStatus | null;\n tabs?: Tab[];\n content?: string;\n}\n"],"names":[],"mappings":"","debug_id":"bf5b0fee-6c8e-580b-8cc7-2bb23ef8efb0"}
{"version":3,"file":"page.js","sources":["api/types/page.ts"],"sourceRoot":"/","sourcesContent":["export interface PageListItem {\n id: number;\n name: string;\n hidden: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport interface PageSearchResultItem {\n id: number;\n type: string;\n name: string;\n hidden: boolean;\n url: string;\n matching_chunk: string;\n score: number;\n}\n\nexport interface Tab {\n name: string;\n hidden: boolean;\n order: number;\n uid: string;\n url: string;\n content: string;\n}\n\nexport interface PageStatus {\n id: string;\n name: string;\n}\n\nexport interface CoverShortcutTile {\n title: string;\n description: string;\n url: string;\n page_id?: number;\n image_url?: string;\n}\n\nexport interface Page {\n id: number;\n uid: string;\n slug: string;\n url: string;\n name: string;\n introduction: string;\n hidden: boolean;\n locked: boolean;\n created_at: string;\n updated_at: string;\n status: PageStatus | null;\n tabs?: Tab[];\n content?: string;\n cover_shortcut_tiles?: CoverShortcutTile[];\n content_images_valid_until?: string;\n content_attachments_valid_until?: string;\n}\n"],"names":[],"mappings":"","debug_id":"2c2b6c69-c5be-5ccf-8943-821ae688a601"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="00a53473-e975-58f2-96d3-02166ee7d41a")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="470ceeab-f6c6-541a-bc8b-0e5744b204b6")}catch(e){}}();
import { InvalidTokenError, } from "@modelcontextprotocol/sdk/server/auth/errors.js";

@@ -17,3 +17,3 @@ import { internalRequest } from "../api/api.js";

}
export async function verifyAccessToken(token, _req) {
export async function verifyAccessToken(token) {
const exchange = await internalRequest("/mcp/exchange_oauth_token", "POST", {

@@ -28,2 +28,5 @@ access_token: token,

}
if (exchange.exp < Date.now() / 1000) {
throw new InvalidTokenError("Token has expired");
}
return {

@@ -38,2 +41,2 @@ token: exchange.extra.jwt,

//# sourceMappingURL=introspection.js.map
//# debugId=00a53473-e975-58f2-96d3-02166ee7d41a
//# debugId=470ceeab-f6c6-541a-bc8b-0e5744b204b6

@@ -1,1 +0,1 @@

{"version":3,"file":"introspection.js","sources":["auth/introspection.ts"],"sourceRoot":"/","sourcesContent":["import { Request } from \"express\";\nimport { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport {\n InvalidTokenError,\n ServerError,\n} from \"@modelcontextprotocol/sdk/server/auth/errors.js\";\nimport { internalRequest } from \"../api/api.js\";\n\ninterface ExchangeResponse {\n active: boolean;\n scope?: string | string[];\n client_id?: string;\n exp?: number;\n extra: {\n features: Record<string, unknown>;\n jwt: string;\n user_id: number;\n team_id: number;\n };\n}\n\nfunction parseScopes(scope?: string | string[]): string[] {\n if (!scope) {\n return [];\n }\n if (Array.isArray(scope)) {\n return scope.filter((item): item is string => typeof item === \"string\");\n }\n return scope\n .split(\" \")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nexport async function verifyAccessToken(\n token: string,\n _req: Request,\n): Promise<AuthInfo> {\n const exchange = await internalRequest<ExchangeResponse>(\n \"/mcp/exchange_oauth_token\",\n \"POST\",\n {\n access_token: token,\n },\n );\n\n if (!exchange.active) {\n throw new InvalidTokenError(\"Token is inactive\");\n }\n\n if (typeof exchange.exp !== \"number\") {\n throw new InvalidTokenError(\"Token has no expiration time\");\n }\n\n return {\n token: exchange.extra.jwt,\n clientId: exchange.client_id ?? \"unknown-client\",\n scopes: parseScopes(exchange.scope),\n expiresAt: exchange.exp,\n extra: exchange.extra,\n };\n}\n"],"names":[],"mappings":";;AAEA,OAAO,EACL,iBAAiB,GAElB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAehD,SAAS,WAAW,CAAC,KAAyB;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,IAAa;IAEb,MAAM,QAAQ,GAAG,MAAM,eAAe,CACpC,2BAA2B,EAC3B,MAAM,EACN;QACE,YAAY,EAAE,KAAK;KACpB,CACF,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,MAAM,IAAI,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,IAAI,iBAAiB,CAAC,8BAA8B,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG;QACzB,QAAQ,EAAE,QAAQ,CAAC,SAAS,IAAI,gBAAgB;QAChD,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnC,SAAS,EAAE,QAAQ,CAAC,GAAG;QACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;AACJ,CAAC","debug_id":"00a53473-e975-58f2-96d3-02166ee7d41a"}
{"version":3,"file":"introspection.js","sources":["auth/introspection.ts"],"sourceRoot":"/","sourcesContent":["import { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport {\n InvalidTokenError,\n ServerError,\n} from \"@modelcontextprotocol/sdk/server/auth/errors.js\";\nimport { internalRequest } from \"../api/api.js\";\n\ninterface ExchangeResponse {\n active: boolean;\n scope?: string | string[];\n client_id?: string;\n exp?: number;\n extra: {\n features: Record<string, unknown>;\n jwt: string;\n user_id: number;\n team_id: number;\n };\n}\n\nfunction parseScopes(scope?: string | string[]): string[] {\n if (!scope) {\n return [];\n }\n if (Array.isArray(scope)) {\n return scope.filter((item): item is string => typeof item === \"string\");\n }\n return scope\n .split(\" \")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nexport async function verifyAccessToken(token: string): Promise<AuthInfo> {\n const exchange = await internalRequest<ExchangeResponse>(\n \"/mcp/exchange_oauth_token\",\n \"POST\",\n {\n access_token: token,\n },\n );\n\n if (!exchange.active) {\n throw new InvalidTokenError(\"Token is inactive\");\n }\n\n if (typeof exchange.exp !== \"number\") {\n throw new InvalidTokenError(\"Token has no expiration time\");\n }\n\n if (exchange.exp < Date.now() / 1000) {\n throw new InvalidTokenError(\"Token has expired\");\n }\n\n return {\n token: exchange.extra.jwt,\n clientId: exchange.client_id ?? \"unknown-client\",\n scopes: parseScopes(exchange.scope),\n expiresAt: exchange.exp,\n extra: exchange.extra,\n };\n}\n"],"names":[],"mappings":";;AACA,OAAO,EACL,iBAAiB,GAElB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAehD,SAAS,WAAW,CAAC,KAAyB;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAa;IACnD,MAAM,QAAQ,GAAG,MAAM,eAAe,CACpC,2BAA2B,EAC3B,MAAM,EACN;QACE,YAAY,EAAE,KAAK;KACpB,CACF,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,MAAM,IAAI,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,IAAI,iBAAiB,CAAC,8BAA8B,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,IAAI,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG;QACzB,QAAQ,EAAE,QAAQ,CAAC,SAAS,IAAI,gBAAgB;QAChD,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnC,SAAS,EAAE,QAAQ,CAAC,GAAG;QACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;AACJ,CAAC","debug_id":"470ceeab-f6c6-541a-bc8b-0e5744b204b6"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a8b94cb7-b633-5e19-be85-722b7a610e41")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a2d33af4-58fa-5f6b-bea0-1c456ae17e4a")}catch(e){}}();
import { MissingCredentialsError } from "./errors.js";

@@ -58,5 +58,6 @@ import { internalRequest } from "../api/api.js";

clientId: authInfo.clientId,
viewerId: authInfo.extra.viewer_id,
};
}
//# sourceMappingURL=credentials.js.map
//# debugId=a8b94cb7-b633-5e19-be85-722b7a610e41
//# debugId=a2d33af4-58fa-5f6b-bea0-1c456ae17e4a

@@ -1,1 +0,1 @@

{"version":3,"file":"credentials.js","sources":["common/credentials.ts"],"sourceRoot":"/","sourcesContent":["import { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport { MissingCredentialsError } from \"./errors.js\";\nimport { internalRequest } from \"../api/api.js\";\nimport { InvalidCredentialsError, NotFoundError } from \"../api/errors.js\";\n\nexport type Credentials =\n | {\n type: \"client_token\";\n token: string;\n client: string;\n }\n | {\n type: \"jwt\";\n jwt: string;\n styleguideId: number;\n styleguideName?: string;\n features: Record<string, boolean>;\n viewerId?: string;\n userId?: number;\n teamId?: number;\n mcpAuthId?: number;\n tokenSets?: Array<{ id: number; name: string }>;\n }\n | {\n type: \"oauth_jwt\";\n jwt: string;\n clientId: string;\n features: Record<string, boolean>;\n userId: number;\n teamId: number;\n };\n\nexport function isLocalMCP(\n credentials: Credentials,\n): credentials is Extract<Credentials, { type: \"client_token\" }> {\n return credentials.type === \"client_token\";\n}\n\nexport function getCredentialsFromEnvironment(): Credentials {\n const token = process.env[\"ZEROHEIGHT_ACCESS_TOKEN\"];\n const client = process.env[\"ZEROHEIGHT_CLIENT_ID\"];\n if (!token || !client) {\n throw new MissingCredentialsError();\n }\n\n return {\n type: \"client_token\",\n token,\n client,\n };\n}\n\ninterface JwtResponse {\n jwt: string;\n styleguide_id: number;\n styleguide_name?: string;\n features: Record<string, boolean>;\n user_id?: number;\n viewer_id?: string;\n team_id?: number;\n mcp_auth_id?: number;\n token_sets?: Array<{ id: number; name: string }>;\n}\n\nexport async function getCredentials(\n authInfo?: AuthInfo,\n): Promise<Credentials> {\n if (!authInfo) {\n return getCredentialsFromEnvironment();\n }\n if (authInfo.clientId === \"http-client\") {\n let res: JwtResponse;\n try {\n res = await internalRequest<JwtResponse>(\n \"/mcp_url/exchange_token\",\n \"POST\",\n {\n token: authInfo.token,\n },\n );\n } catch (e) {\n if (e instanceof NotFoundError) {\n throw new InvalidCredentialsError();\n }\n throw e;\n }\n\n return {\n type: \"jwt\",\n jwt: res.jwt,\n styleguideId: res.styleguide_id,\n styleguideName: res.styleguide_name,\n features: res.features ?? {},\n userId: res.user_id,\n viewerId: res.viewer_id,\n teamId: res.team_id,\n mcpAuthId: res.mcp_auth_id,\n tokenSets: res.token_sets,\n };\n }\n return {\n type: \"oauth_jwt\",\n jwt: authInfo.token,\n features: authInfo.extra!.features as Record<string, boolean>,\n userId: authInfo.extra!.user_id as number,\n teamId: authInfo.extra!.team_id as number,\n clientId: authInfo.clientId,\n };\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA6B1E,MAAM,UAAU,UAAU,CACxB,WAAwB;IAExB,OAAO,WAAW,CAAC,IAAI,KAAK,cAAc,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,uBAAuB,EAAE,CAAC;IACtC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,KAAK;QACL,MAAM;KACP,CAAC;AACJ,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAmB;IAEnB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,6BAA6B,EAAE,CAAC;IACzC,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QACxC,IAAI,GAAgB,CAAC;QACrB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,eAAe,CACzB,yBAAyB,EACzB,MAAM,EACN;gBACE,KAAK,EAAE,QAAQ,CAAC,KAAK;aACtB,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,aAAa,EAAE,CAAC;gBAC/B,MAAM,IAAI,uBAAuB,EAAE,CAAC;YACtC,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;QAED,OAAO;YACL,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,YAAY,EAAE,GAAG,CAAC,aAAa;YAC/B,cAAc,EAAE,GAAG,CAAC,eAAe;YACnC,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,SAAS,EAAE,GAAG,CAAC,WAAW;YAC1B,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,QAAQ,CAAC,KAAK;QACnB,QAAQ,EAAE,QAAQ,CAAC,KAAM,CAAC,QAAmC;QAC7D,MAAM,EAAE,QAAQ,CAAC,KAAM,CAAC,OAAiB;QACzC,MAAM,EAAE,QAAQ,CAAC,KAAM,CAAC,OAAiB;QACzC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC;AACJ,CAAC","debug_id":"a8b94cb7-b633-5e19-be85-722b7a610e41"}
{"version":3,"file":"credentials.js","sources":["common/credentials.ts"],"sourceRoot":"/","sourcesContent":["import { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport { MissingCredentialsError } from \"./errors.js\";\nimport { internalRequest } from \"../api/api.js\";\nimport { InvalidCredentialsError, NotFoundError } from \"../api/errors.js\";\n\nexport type ClientTokenCredentials = {\n type: \"client_token\";\n token: string;\n client: string;\n};\n\nexport type JwtCredentials = {\n type: \"jwt\";\n jwt: string;\n styleguideId: number;\n styleguideName?: string;\n features: Record<string, boolean>;\n viewerId?: string;\n userId?: number;\n teamId?: number;\n mcpAuthId?: number;\n tokenSets?: Array<{ id: number; name: string }>;\n};\n\nexport type OauthJwtCredentials = {\n type: \"oauth_jwt\";\n jwt: string;\n clientId: string;\n features: Record<string, boolean>;\n userId?: number;\n teamId: number;\n viewerId?: string;\n};\n\nexport type Credentials =\n | ClientTokenCredentials\n | JwtCredentials\n | OauthJwtCredentials;\n\nexport function isLocalMCP(\n credentials: Credentials,\n): credentials is Extract<Credentials, { type: \"client_token\" }> {\n return credentials.type === \"client_token\";\n}\n\nexport function getCredentialsFromEnvironment(): Credentials {\n const token = process.env[\"ZEROHEIGHT_ACCESS_TOKEN\"];\n const client = process.env[\"ZEROHEIGHT_CLIENT_ID\"];\n if (!token || !client) {\n throw new MissingCredentialsError();\n }\n\n return {\n type: \"client_token\",\n token,\n client,\n };\n}\n\ninterface JwtResponse {\n jwt: string;\n styleguide_id: number;\n styleguide_name?: string;\n features: Record<string, boolean>;\n user_id?: number;\n viewer_id?: string;\n team_id?: number;\n mcp_auth_id?: number;\n token_sets?: Array<{ id: number; name: string }>;\n}\n\nexport async function getCredentials(\n authInfo?: AuthInfo,\n): Promise<Credentials> {\n if (!authInfo) {\n return getCredentialsFromEnvironment();\n }\n if (authInfo.clientId === \"http-client\") {\n let res: JwtResponse;\n try {\n res = await internalRequest<JwtResponse>(\n \"/mcp_url/exchange_token\",\n \"POST\",\n {\n token: authInfo.token,\n },\n );\n } catch (e) {\n if (e instanceof NotFoundError) {\n throw new InvalidCredentialsError();\n }\n throw e;\n }\n\n return {\n type: \"jwt\",\n jwt: res.jwt,\n styleguideId: res.styleguide_id,\n styleguideName: res.styleguide_name,\n features: res.features ?? {},\n userId: res.user_id,\n viewerId: res.viewer_id,\n teamId: res.team_id,\n mcpAuthId: res.mcp_auth_id,\n tokenSets: res.token_sets,\n };\n }\n return {\n type: \"oauth_jwt\",\n jwt: authInfo.token,\n features: authInfo.extra!.features as Record<string, boolean>,\n userId: authInfo.extra!.user_id as number,\n teamId: authInfo.extra!.team_id as number,\n clientId: authInfo.clientId,\n viewerId: authInfo.extra!.viewer_id as string | undefined,\n };\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAoC1E,MAAM,UAAU,UAAU,CACxB,WAAwB;IAExB,OAAO,WAAW,CAAC,IAAI,KAAK,cAAc,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,uBAAuB,EAAE,CAAC;IACtC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,KAAK;QACL,MAAM;KACP,CAAC;AACJ,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAmB;IAEnB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,6BAA6B,EAAE,CAAC;IACzC,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QACxC,IAAI,GAAgB,CAAC;QACrB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,eAAe,CACzB,yBAAyB,EACzB,MAAM,EACN;gBACE,KAAK,EAAE,QAAQ,CAAC,KAAK;aACtB,CACF,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,aAAa,EAAE,CAAC;gBAC/B,MAAM,IAAI,uBAAuB,EAAE,CAAC;YACtC,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;QAED,OAAO;YACL,IAAI,EAAE,KAAK;YACX,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,YAAY,EAAE,GAAG,CAAC,aAAa;YAC/B,cAAc,EAAE,GAAG,CAAC,eAAe;YACnC,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,MAAM,EAAE,GAAG,CAAC,OAAO;YACnB,SAAS,EAAE,GAAG,CAAC,WAAW;YAC1B,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,QAAQ,CAAC,KAAK;QACnB,QAAQ,EAAE,QAAQ,CAAC,KAAM,CAAC,QAAmC;QAC7D,MAAM,EAAE,QAAQ,CAAC,KAAM,CAAC,OAAiB;QACzC,MAAM,EAAE,QAAQ,CAAC,KAAM,CAAC,OAAiB;QACzC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,QAAQ,EAAE,QAAQ,CAAC,KAAM,CAAC,SAA+B;KAC1D,CAAC;AACJ,CAAC","debug_id":"a2d33af4-58fa-5f6b-bea0-1c456ae17e4a"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f8341007-f28e-5411-8517-88f7217b7fba")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="30cc22df-8518-53d2-bcda-9ada8557dad1")}catch(e){}}();
import * as Sentry from "@sentry/node";
import { log } from "./logger.js";
import { getRequestContext } from "./requestContext.js";
export class ServerError extends Error {

@@ -15,2 +17,23 @@ constructor(message) {

}
function withRequestContext(context) {
const request = getRequestContext();
if (!request)
return context;
const tags = {
request_path: request.path,
team_id: request.teamId,
};
const user = {
id: request.userId ?? request.viewerId,
ip_address: request.ip,
};
if (!context)
return { tags, user };
const scopeContext = context;
return {
...scopeContext,
tags: { ...tags, ...(scopeContext.tags ?? {}) },
user: { ...user, ...(scopeContext.user ?? {}) },
};
}
export function captureException(exception) {

@@ -20,6 +43,6 @@ const disableTelemetry = process.env["ZEROHEIGHT_MCP_DISABLE_TELEMETRY"];

if (disableTelemetry || !sentryDSN) {
console.error(exception);
log.error(exception);
return;
}
Sentry.captureException(exception);
Sentry.captureException(exception, withRequestContext());
}

@@ -30,8 +53,8 @@ export function captureMessage(message, context) {

if (disableTelemetry || !sentryDSN) {
console.error(`${message}: ${JSON.stringify(context)}`);
log.error(`${message}: ${JSON.stringify(context)}`);
return;
}
Sentry.captureMessage(message, context);
Sentry.captureMessage(message, withRequestContext(context));
}
//# sourceMappingURL=errors.js.map
//# debugId=f8341007-f28e-5411-8517-88f7217b7fba
//# debugId=30cc22df-8518-53d2-bcda-9ada8557dad1

@@ -1,1 +0,1 @@

{"version":3,"file":"errors.js","sources":["common/errors.ts"],"sourceRoot":"/","sourcesContent":["import { CaptureContext } from \"@sentry/core\";\nimport * as Sentry from \"@sentry/node\";\n\nexport class ServerError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ServerError\";\n }\n}\n\nexport class MissingCredentialsError extends ServerError {\n constructor() {\n super(\n \"Missing credentials. Please ensure ZEROHEIGHT_CLIENT_ID and ZEROHEIGHT_ACCESS_TOKEN are set in your environment\",\n );\n }\n}\n\nexport function captureException(exception: unknown) {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n const sentryDSN = process.env[\"SENTRY_DSN\"];\n if (disableTelemetry || !sentryDSN) {\n console.error(exception);\n return;\n }\n\n Sentry.captureException(exception);\n}\n\nexport function captureMessage(message: string, context?: CaptureContext) {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n const sentryDSN = process.env[\"SENTRY_DSN\"];\n if (disableTelemetry || !sentryDSN) {\n console.error(`${message}: ${JSON.stringify(context)}`);\n return;\n }\n\n Sentry.captureMessage(message, context);\n}\n"],"names":[],"mappings":";;AACA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,WAAW;IACtD;QACE,KAAK,CACH,iHAAiH,CAClH,CAAC;IACJ,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,gBAAgB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,OAAwB;IACtE,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,gBAAgB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC","debug_id":"f8341007-f28e-5411-8517-88f7217b7fba"}
{"version":3,"file":"errors.js","sources":["common/errors.ts"],"sourceRoot":"/","sourcesContent":["import { CaptureContext, ScopeContext, User } from \"@sentry/core\";\nimport * as Sentry from \"@sentry/node\";\nimport { log } from \"./logger.js\";\nimport { getRequestContext } from \"./requestContext.js\";\n\nexport class ServerError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ServerError\";\n }\n}\n\nexport class MissingCredentialsError extends ServerError {\n constructor() {\n super(\n \"Missing credentials. Please ensure ZEROHEIGHT_CLIENT_ID and ZEROHEIGHT_ACCESS_TOKEN are set in your environment\",\n );\n }\n}\n\nfunction withRequestContext(\n context?: CaptureContext,\n): CaptureContext | undefined {\n const request = getRequestContext();\n if (!request) return context;\n\n const tags = {\n request_path: request.path,\n team_id: request.teamId,\n };\n\n const user = {\n id: request.userId ?? request.viewerId,\n ip_address: request.ip,\n };\n\n if (!context) return { tags, user };\n\n const scopeContext = context as Partial<ScopeContext>;\n return {\n ...scopeContext,\n tags: { ...tags, ...(scopeContext.tags ?? {}) },\n user: { ...user, ...(scopeContext.user ?? {}) },\n };\n}\n\nexport function captureException(exception: unknown) {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n const sentryDSN = process.env[\"SENTRY_DSN\"];\n if (disableTelemetry || !sentryDSN) {\n log.error(exception);\n return;\n }\n\n Sentry.captureException(exception, withRequestContext());\n}\n\nexport function captureMessage(message: string, context?: CaptureContext) {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n const sentryDSN = process.env[\"SENTRY_DSN\"];\n if (disableTelemetry || !sentryDSN) {\n log.error(`${message}: ${JSON.stringify(context)}`);\n return;\n }\n\n Sentry.captureMessage(message, withRequestContext(context));\n}\n"],"names":[],"mappings":";;AACA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,WAAW;IACtD;QACE,KAAK,CACH,iHAAiH,CAClH,CAAC;IACJ,CAAC;CACF;AAED,SAAS,kBAAkB,CACzB,OAAwB;IAExB,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC;IAE7B,MAAM,IAAI,GAAG;QACX,YAAY,EAAE,OAAO,CAAC,IAAI;QAC1B,OAAO,EAAE,OAAO,CAAC,MAAM;KACxB,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ;QACtC,UAAU,EAAE,OAAO,CAAC,EAAE;KACvB,CAAC;IAEF,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAEpC,MAAM,YAAY,GAAG,OAAgC,CAAC;IACtD,OAAO;QACL,GAAG,YAAY;QACf,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;QAC/C,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;KAChD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,gBAAgB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,OAAwB;IACtE,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,IAAI,gBAAgB,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9D,CAAC","debug_id":"30cc22df-8518-53d2-bcda-9ada8557dad1"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3000168b-a645-5f50-addb-16c879ac1e7c")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dc74ce91-deab-514a-85e8-cc24b0850600")}catch(e){}}();
import { fileTypeFromBuffer } from "file-type";
const MARKDOWN_IMAGE_REGEX = /!\[[^\]]*\]\(([^)]+)\)/g;
const HTML_IMAGE_REGEX = /<img\b[^>]*\bsrc\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/gi;
const MARKDOWN_IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
const ANNOTATIONS_BLOCK_REGEX = /<annotations\b[^>]*>/i;
// Matches attachment lines emitted by the Rails prosemirror_to_markdown adapter:
// - [name](url) | size | mimeType | date
const MARKDOWN_ATTACHMENT_REGEX = /^- \[([^\]]+)\]\(([^)]+)\) \| ([^|]+) \| ([^|]+) \| ([^\n|]+)$/gm;
const MIME_TYPE_BY_EXTENSION = {

@@ -18,14 +21,30 @@ png: "image/png",

tiff: "image/tiff",
txt: "text/plain",
csv: "text/csv",
json: "application/json",
xml: "application/xml",
};
const GENERIC_CONTENT_TYPES = new Set([
"application/octet-stream",
"binary/octet-stream",
"application/x-octet-stream",
"*/*",
"",
]);
export function formatPageAsMarkdown(page) {
const content = page.content ||
page.tabs?.map((tab) => `# ${tab.name}\n${tab.content}\n---\n`).join("\n");
return [
const shortcutTiles = formatCoverShortcutTiles(page.cover_shortcut_tiles);
const frontmatter = [
`---`,
`title: ${page.name}`,
`url: ${page.url}`,
page.introduction ? `introduction: ${page.introduction}\n---` : `---`,
"",
content,
].join("\n");
page.introduction ? `introduction: ${page.introduction}` : undefined,
`---`,
]
.filter((part) => part != null)
.join("\n");
return shortcutTiles
? [frontmatter, "", shortcutTiles, "", content].join("\n")
: [frontmatter, "", content].join("\n");
}

@@ -37,2 +56,20 @@ export function formatPageListItemsAsMarkdown(pages) {

}
export async function fetchBlobFromUrl(resourceUrl) {
// Presigned S3 URLs embedded in page content may be double-encoded
// (e.g. %252F instead of %2F). Normalise one level of %25-encoding so the
// URL reaches S3 with the single-encoded query params it expects.
const fetchUrl = resourceUrl.replace(/%25([0-9A-Fa-f]{2})/gi, "%$1");
try {
const response = await fetch(fetchUrl);
if (!response.ok) {
return null;
}
const buffer = Buffer.from(await response.arrayBuffer());
const mimeType = await getMimeType(fetchUrl, response.headers.get("content-type"), buffer);
return { blob: buffer.toString("base64"), mimeType };
}
catch {
return null;
}
}
export async function extractImageUrlsFromPage(content) {

@@ -44,34 +81,77 @@ const imageUrls = extractImageUrls(content);

}
try {
const response = await fetch(uri);
if (!response.ok) {
return null;
}
const buffer = Buffer.from(await response.arrayBuffer());
const blob = buffer.toString("base64");
const mimeType = await getMimeType(uri, response.headers.get("content-type"), buffer);
return {
type: "image",
data: blob,
mimeType,
_meta: {
uri,
},
};
}
catch {
const image = await fetchBlobFromUrl(uri);
if (!image) {
return null;
}
return {
type: "image",
data: image.blob,
mimeType: image.mimeType,
_meta: {
uri,
},
};
}));
return embeddedResources.filter((r) => r != null);
}
export function extractPageImageResourceLinks(content) {
const seen = new Set();
const links = [];
for (const match of content.matchAll(MARKDOWN_IMAGE_REGEX)) {
const altText = match[1].trim();
const url = parseMarkdownImageTarget(match[2]);
if (!url || !isHttpUrl(url) || seen.has(url))
continue;
seen.add(url);
links.push({
type: "resource_link",
uri: `zeroheight://image/${url}`,
name: altText || "Page image",
});
}
return links;
}
export function pageHasAnnotations(content) {
return ANNOTATIONS_BLOCK_REGEX.test(content);
}
export function extractPageAttachments(content) {
const attachments = [];
for (const match of content.matchAll(MARKDOWN_ATTACHMENT_REGEX)) {
const url = match[2].trim();
if (!isHttpUrl(url))
continue;
attachments.push({
name: match[1].trim(),
url,
size: match[3].trim(),
type: match[4].trim(),
date: match[5].trim(),
});
}
return attachments;
}
export function extractPageAttachmentResourceLinks(content) {
const seen = new Set();
return extractPageAttachments(content).flatMap((attachment) => {
if (seen.has(attachment.url))
return [];
seen.add(attachment.url);
return [
{
type: "resource_link",
uri: attachment.url,
name: attachment.name,
mimeType: attachment.type,
},
];
});
}
function extractImageUrls(content) {
const markdownImageMatches = Array.from(content.matchAll(MARKDOWN_IMAGE_REGEX))
.map((match) => parseMarkdownImageTarget(match[1]))
const fromMarkdownImages = Array.from(content.matchAll(MARKDOWN_IMAGE_REGEX))
.map((match) => parseMarkdownImageTarget(match[2]))
.filter((url) => !!url);
const htmlImageMatches = Array.from(content.matchAll(HTML_IMAGE_REGEX))
.map((match) => match[1] ?? match[2] ?? match[3] ?? "")
.map((url) => url.trim())
.filter((url) => url.length > 0);
return [...new Set([...markdownImageMatches, ...htmlImageMatches])];
const fromImageAttachments = extractPageAttachments(content)
.filter((attachment) => attachment.type.startsWith("image/"))
.map((attachment) => attachment.url);
return [...fromMarkdownImages, ...fromImageAttachments].filter((url, index, self) => self.indexOf(url) === index);
}

@@ -102,2 +182,36 @@ function parseMarkdownImageTarget(target) {

}
function formatCoverShortcutTiles(tiles) {
if (!tiles || tiles.length === 0) {
return undefined;
}
return [
`<shortcut_tiles type="cover">`,
tiles.map(formatCoverShortcutTile).join("\n"),
`</shortcut_tiles>`,
].join("\n");
}
function formatCoverShortcutTile(tile) {
const attributes = [`url="${escapeAttribute(tile.url)}"`];
if (tile.page_id != null) {
attributes.push(`page-id="${tile.page_id}"`);
}
const lines = [`<shortcut_tile ${attributes.join(" ")}>`];
if (tile.image_url) {
lines.push(`![${escapeMarkdownText(tile.title)}](${tile.image_url})`, "");
}
if (tile.title) {
lines.push(`**${escapeMarkdownText(tile.title)}**`, "");
}
if (tile.description) {
lines.push(tile.description);
}
lines.push(`</shortcut_tile>`);
return lines.join("\n");
}
function escapeAttribute(value) {
return value.replace(/"/g, "&quot;");
}
function escapeMarkdownText(value) {
return value.replace(/([\\[\]()])/g, "\\$1");
}
function isHttpUrl(value) {

@@ -113,7 +227,14 @@ try {

async function getMimeType(uri, contentTypeHeader, buffer) {
const normalizedContentType = contentTypeHeader?.split(";")[0]?.trim();
const normalizedContentType = contentTypeHeader
?.split(";")[0]
?.trim()
.toLowerCase();
if (normalizedContentType &&
normalizedContentType !== "application/octet-stream") {
!GENERIC_CONTENT_TYPES.has(normalizedContentType)) {
return normalizedContentType;
}
const detectedType = await fileTypeFromBuffer(buffer);
if (detectedType) {
return detectedType.mime;
}
try {

@@ -129,9 +250,5 @@ const pathname = new URL(uri).pathname;

}
const detectedType = await fileTypeFromBuffer(buffer);
if (detectedType) {
return detectedType.mime;
}
return "application/octet-stream";
}
//# sourceMappingURL=page.js.map
//# debugId=3000168b-a645-5f50-addb-16c879ac1e7c
//# debugId=dc74ce91-deab-514a-85e8-cc24b0850600

@@ -1,1 +0,1 @@

{"version":3,"file":"page.js","sources":["common/formatters/page.ts"],"sourceRoot":"/","sourcesContent":["import {\n Page,\n PageListItem,\n PageSearchResultItem,\n} from \"../../api/types/page.js\";\nimport type { ImageContent } from \"@modelcontextprotocol/sdk/types.js\";\nimport { fileTypeFromBuffer } from \"file-type\";\n\nconst MARKDOWN_IMAGE_REGEX = /!\\[[^\\]]*\\]\\(([^)]+)\\)/g;\nconst HTML_IMAGE_REGEX =\n /<img\\b[^>]*\\bsrc\\s*=\\s*(?:\"([^\"]+)\"|'([^']+)'|([^\\s>]+))/gi;\n\nconst MIME_TYPE_BY_EXTENSION: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n svg: \"image/svg+xml\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n ico: \"image/x-icon\",\n tif: \"image/tiff\",\n tiff: \"image/tiff\",\n};\n\nexport function formatPageAsMarkdown(page: Page): string {\n const content =\n page.content ||\n page.tabs?.map((tab) => `# ${tab.name}\\n${tab.content}\\n---\\n`).join(\"\\n\");\n return [\n `---`,\n `title: ${page.name}`,\n `url: ${page.url}`,\n page.introduction ? `introduction: ${page.introduction}\\n---` : `---`,\n \"\",\n content,\n ].join(\"\\n\");\n}\n\nexport function formatPageListItemsAsMarkdown(\n pages: (PageListItem | PageSearchResultItem)[],\n): string {\n return pages\n .map((page) => `- ${page.name ?? \"Untitled page\"} (ID: ${page.id})`)\n .join(\"\\n\");\n}\n\nexport async function extractImageUrlsFromPage(\n content: string,\n): Promise<ImageContent[]> {\n const imageUrls = extractImageUrls(content);\n\n const embeddedResources: Array<ImageContent | null> = await Promise.all(\n imageUrls.map(async (uri) => {\n if (!isHttpUrl(uri)) {\n return null;\n }\n\n try {\n const response = await fetch(uri);\n if (!response.ok) {\n return null;\n }\n\n const buffer = Buffer.from(await response.arrayBuffer());\n const blob = buffer.toString(\"base64\");\n const mimeType = await getMimeType(\n uri,\n response.headers.get(\"content-type\"),\n buffer,\n );\n\n return {\n type: \"image\",\n data: blob,\n mimeType,\n _meta: {\n uri,\n },\n } satisfies ImageContent;\n } catch {\n return null;\n }\n }),\n );\n\n return embeddedResources.filter((r) => r != null);\n}\n\nfunction extractImageUrls(content: string): string[] {\n const markdownImageMatches = Array.from(\n content.matchAll(MARKDOWN_IMAGE_REGEX),\n )\n .map((match) => parseMarkdownImageTarget(match[1]))\n .filter((url): url is string => !!url);\n\n const htmlImageMatches = Array.from(content.matchAll(HTML_IMAGE_REGEX))\n .map((match) => match[1] ?? match[2] ?? match[3] ?? \"\")\n .map((url) => url.trim())\n .filter((url) => url.length > 0);\n\n return [...new Set([...markdownImageMatches, ...htmlImageMatches])];\n}\n\nfunction parseMarkdownImageTarget(target: string): string | null {\n const trimmedTarget = target.trim();\n if (trimmedTarget.length === 0) {\n return null;\n }\n\n if (trimmedTarget.startsWith(\"<\")) {\n const closingBracketIndex = trimmedTarget.indexOf(\">\", 1);\n if (closingBracketIndex > 1) {\n return trimmedTarget.slice(1, closingBracketIndex).trim();\n }\n }\n\n const firstWhitespaceIndex = trimmedTarget.search(/\\s/);\n const url =\n firstWhitespaceIndex === -1\n ? trimmedTarget\n : trimmedTarget.slice(0, firstWhitespaceIndex);\n\n return stripWrappingQuotes(url.trim());\n}\n\nfunction stripWrappingQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n\n return value;\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nasync function getMimeType(\n uri: string,\n contentTypeHeader: string | null,\n buffer: Buffer,\n): Promise<string> {\n const normalizedContentType = contentTypeHeader?.split(\";\")[0]?.trim();\n if (\n normalizedContentType &&\n normalizedContentType !== \"application/octet-stream\"\n ) {\n return normalizedContentType;\n }\n\n try {\n const pathname = new URL(uri).pathname;\n const extension = pathname.split(\".\").pop()?.toLowerCase();\n if (extension && MIME_TYPE_BY_EXTENSION[extension]) {\n return MIME_TYPE_BY_EXTENSION[extension];\n }\n } catch {\n // noop\n }\n\n const detectedType = await fileTypeFromBuffer(buffer);\n if (detectedType) {\n return detectedType.mime;\n }\n\n return \"application/octet-stream\";\n}\n"],"names":[],"mappings":";;AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,oBAAoB,GAAG,yBAAyB,CAAC;AACvD,MAAM,gBAAgB,GACpB,4DAA4D,CAAC;AAE/D,MAAM,sBAAsB,GAA2B;IACrD,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;CACnB,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,IAAU;IAC7C,MAAM,OAAO,GACX,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7E,OAAO;QACL,KAAK;QACL,UAAU,IAAI,CAAC,IAAI,EAAE;QACrB,QAAQ,IAAI,CAAC,GAAG,EAAE;QAClB,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK;QACrE,EAAE;QACF,OAAO;KACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,KAA8C;IAE9C,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,eAAe,SAAS,IAAI,CAAC,EAAE,GAAG,CAAC;SACnE,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAe;IAEf,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE5C,MAAM,iBAAiB,GAA+B,MAAM,OAAO,CAAC,GAAG,CACrE,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC1B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,GAAG,EACH,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EACpC,MAAM,CACP,CAAC;YAEF,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,IAAI;gBACV,QAAQ;gBACR,KAAK,EAAE;oBACL,GAAG;iBACJ;aACqB,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,oBAAoB,GAAG,KAAK,CAAC,IAAI,CACrC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CACvC;SACE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;SAClD,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEzC,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;SACpE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACtD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,oBAAoB,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAc;IAC9C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1D,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,GAAG,GACP,oBAAoB,KAAK,CAAC,CAAC;QACzB,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAEnD,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,IACE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC9C,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,GAAW,EACX,iBAAgC,EAChC,MAAc;IAEd,MAAM,qBAAqB,GAAG,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACvE,IACE,qBAAqB;QACrB,qBAAqB,KAAK,0BAA0B,EACpD,CAAC;QACD,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;QAC3D,IAAI,SAAS,IAAI,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,OAAO,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,OAAO,0BAA0B,CAAC;AACpC,CAAC","debug_id":"3000168b-a645-5f50-addb-16c879ac1e7c"}
{"version":3,"file":"page.js","sources":["common/formatters/page.ts"],"sourceRoot":"/","sourcesContent":["import {\n CoverShortcutTile,\n Page,\n PageListItem,\n PageSearchResultItem,\n} from \"../../api/types/page.js\";\nimport type {\n ImageContent,\n ResourceLink,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { fileTypeFromBuffer } from \"file-type\";\n\nconst MARKDOWN_IMAGE_REGEX = /!\\[([^\\]]*)\\]\\(([^)]+)\\)/g;\n\nconst ANNOTATIONS_BLOCK_REGEX = /<annotations\\b[^>]*>/i;\n\n// Matches attachment lines emitted by the Rails prosemirror_to_markdown adapter:\n// - [name](url) | size | mimeType | date\nconst MARKDOWN_ATTACHMENT_REGEX =\n /^- \\[([^\\]]+)\\]\\(([^)]+)\\) \\| ([^|]+) \\| ([^|]+) \\| ([^\\n|]+)$/gm;\n\nexport interface PageAttachment {\n name: string;\n url: string;\n size: string;\n type: string;\n date: string;\n}\n\nconst MIME_TYPE_BY_EXTENSION: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n svg: \"image/svg+xml\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n ico: \"image/x-icon\",\n tif: \"image/tiff\",\n tiff: \"image/tiff\",\n txt: \"text/plain\",\n csv: \"text/csv\",\n json: \"application/json\",\n xml: \"application/xml\",\n};\n\nconst GENERIC_CONTENT_TYPES: ReadonlySet<string> = new Set([\n \"application/octet-stream\",\n \"binary/octet-stream\",\n \"application/x-octet-stream\",\n \"*/*\",\n \"\",\n]);\n\nexport function formatPageAsMarkdown(page: Page): string {\n const content =\n page.content ||\n page.tabs?.map((tab) => `# ${tab.name}\\n${tab.content}\\n---\\n`).join(\"\\n\");\n const shortcutTiles = formatCoverShortcutTiles(page.cover_shortcut_tiles);\n const frontmatter = [\n `---`,\n `title: ${page.name}`,\n `url: ${page.url}`,\n page.introduction ? `introduction: ${page.introduction}` : undefined,\n `---`,\n ]\n .filter((part) => part != null)\n .join(\"\\n\");\n\n return shortcutTiles\n ? [frontmatter, \"\", shortcutTiles, \"\", content].join(\"\\n\")\n : [frontmatter, \"\", content].join(\"\\n\");\n}\n\nexport function formatPageListItemsAsMarkdown(\n pages: (PageListItem | PageSearchResultItem)[],\n): string {\n return pages\n .map((page) => `- ${page.name ?? \"Untitled page\"} (ID: ${page.id})`)\n .join(\"\\n\");\n}\n\nexport async function fetchBlobFromUrl(\n resourceUrl: string,\n): Promise<{ blob: string; mimeType: string } | null> {\n // Presigned S3 URLs embedded in page content may be double-encoded\n // (e.g. %252F instead of %2F). Normalise one level of %25-encoding so the\n // URL reaches S3 with the single-encoded query params it expects.\n const fetchUrl = resourceUrl.replace(/%25([0-9A-Fa-f]{2})/gi, \"%$1\");\n try {\n const response = await fetch(fetchUrl);\n if (!response.ok) {\n return null;\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n const mimeType = await getMimeType(\n fetchUrl,\n response.headers.get(\"content-type\"),\n buffer,\n );\n return { blob: buffer.toString(\"base64\"), mimeType };\n } catch {\n return null;\n }\n}\n\nexport async function extractImageUrlsFromPage(\n content: string,\n): Promise<ImageContent[]> {\n const imageUrls = extractImageUrls(content);\n\n const embeddedResources: Array<ImageContent | null> = await Promise.all(\n imageUrls.map(async (uri) => {\n if (!isHttpUrl(uri)) {\n return null;\n }\n\n const image = await fetchBlobFromUrl(uri);\n if (!image) {\n return null;\n }\n\n return {\n type: \"image\",\n data: image.blob,\n mimeType: image.mimeType,\n _meta: {\n uri,\n },\n } satisfies ImageContent;\n }),\n );\n\n return embeddedResources.filter((r) => r != null);\n}\n\nexport function extractPageImageResourceLinks(content: string): ResourceLink[] {\n const seen = new Set<string>();\n const links: ResourceLink[] = [];\n\n for (const match of content.matchAll(MARKDOWN_IMAGE_REGEX)) {\n const altText = match[1].trim();\n const url = parseMarkdownImageTarget(match[2]);\n if (!url || !isHttpUrl(url) || seen.has(url)) continue;\n seen.add(url);\n links.push({\n type: \"resource_link\" as const,\n uri: `zeroheight://image/${url}`,\n name: altText || \"Page image\",\n });\n }\n\n return links;\n}\n\nexport function pageHasAnnotations(content: string): boolean {\n return ANNOTATIONS_BLOCK_REGEX.test(content);\n}\n\nexport function extractPageAttachments(content: string): PageAttachment[] {\n const attachments: PageAttachment[] = [];\n for (const match of content.matchAll(MARKDOWN_ATTACHMENT_REGEX)) {\n const url = match[2].trim();\n if (!isHttpUrl(url)) continue;\n attachments.push({\n name: match[1].trim(),\n url,\n size: match[3].trim(),\n type: match[4].trim(),\n date: match[5].trim(),\n });\n }\n return attachments;\n}\n\nexport function extractPageAttachmentResourceLinks(\n content: string,\n): ResourceLink[] {\n const seen = new Set<string>();\n return extractPageAttachments(content).flatMap((attachment) => {\n if (seen.has(attachment.url)) return [];\n seen.add(attachment.url);\n return [\n {\n type: \"resource_link\" as const,\n uri: attachment.url,\n name: attachment.name,\n mimeType: attachment.type,\n },\n ];\n });\n}\n\nfunction extractImageUrls(content: string): string[] {\n const fromMarkdownImages = Array.from(content.matchAll(MARKDOWN_IMAGE_REGEX))\n .map((match) => parseMarkdownImageTarget(match[2]))\n .filter((url): url is string => !!url);\n\n const fromImageAttachments = extractPageAttachments(content)\n .filter((attachment) => attachment.type.startsWith(\"image/\"))\n .map((attachment) => attachment.url);\n\n return [...fromMarkdownImages, ...fromImageAttachments].filter(\n (url, index, self) => self.indexOf(url) === index,\n );\n}\n\nfunction parseMarkdownImageTarget(target: string): string | null {\n const trimmedTarget = target.trim();\n if (trimmedTarget.length === 0) {\n return null;\n }\n\n if (trimmedTarget.startsWith(\"<\")) {\n const closingBracketIndex = trimmedTarget.indexOf(\">\", 1);\n if (closingBracketIndex > 1) {\n return trimmedTarget.slice(1, closingBracketIndex).trim();\n }\n }\n\n const firstWhitespaceIndex = trimmedTarget.search(/\\s/);\n const url =\n firstWhitespaceIndex === -1\n ? trimmedTarget\n : trimmedTarget.slice(0, firstWhitespaceIndex);\n\n return stripWrappingQuotes(url.trim());\n}\n\nfunction stripWrappingQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n return value.slice(1, -1);\n }\n\n return value;\n}\n\nfunction formatCoverShortcutTiles(\n tiles?: CoverShortcutTile[],\n): string | undefined {\n if (!tiles || tiles.length === 0) {\n return undefined;\n }\n\n return [\n `<shortcut_tiles type=\"cover\">`,\n tiles.map(formatCoverShortcutTile).join(\"\\n\"),\n `</shortcut_tiles>`,\n ].join(\"\\n\");\n}\n\nfunction formatCoverShortcutTile(tile: CoverShortcutTile): string {\n const attributes = [`url=\"${escapeAttribute(tile.url)}\"`];\n\n if (tile.page_id != null) {\n attributes.push(`page-id=\"${tile.page_id}\"`);\n }\n\n const lines = [`<shortcut_tile ${attributes.join(\" \")}>`];\n\n if (tile.image_url) {\n lines.push(`![${escapeMarkdownText(tile.title)}](${tile.image_url})`, \"\");\n }\n\n if (tile.title) {\n lines.push(`**${escapeMarkdownText(tile.title)}**`, \"\");\n }\n\n if (tile.description) {\n lines.push(tile.description);\n }\n\n lines.push(`</shortcut_tile>`);\n\n return lines.join(\"\\n\");\n}\n\nfunction escapeAttribute(value: string): string {\n return value.replace(/\"/g, \"&quot;\");\n}\n\nfunction escapeMarkdownText(value: string): string {\n return value.replace(/([\\\\[\\]()])/g, \"\\\\$1\");\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nasync function getMimeType(\n uri: string,\n contentTypeHeader: string | null,\n buffer: Buffer,\n): Promise<string> {\n const normalizedContentType = contentTypeHeader\n ?.split(\";\")[0]\n ?.trim()\n .toLowerCase();\n if (\n normalizedContentType &&\n !GENERIC_CONTENT_TYPES.has(normalizedContentType)\n ) {\n return normalizedContentType;\n }\n\n const detectedType = await fileTypeFromBuffer(buffer);\n if (detectedType) {\n return detectedType.mime;\n }\n\n try {\n const pathname = new URL(uri).pathname;\n const extension = pathname.split(\".\").pop()?.toLowerCase();\n if (extension && MIME_TYPE_BY_EXTENSION[extension]) {\n return MIME_TYPE_BY_EXTENSION[extension];\n }\n } catch {\n // noop\n }\n\n return \"application/octet-stream\";\n}\n"],"names":[],"mappings":"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","debug_id":"dc74ce91-deab-514a-85e8-cc24b0850600"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="30b81d5e-e94d-5bce-a3f1-4fe8a6b66d72")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ff63079c-c318-594e-b1b7-e6b57d0ce65a")}catch(e){}}();
export class InvalidRemoteSingleStyleguideContextError extends Error {

@@ -9,6 +9,16 @@ constructor() {

}
function getFeatureOverrides() {
const overrides = process.env["FEATURE_OVERRIDES"];
if (!overrides)
return {};
return Object.fromEntries(overrides
.split(",")
.map((name) => name.trim())
.filter(Boolean)
.map((name) => [name, true]));
}
export function createLocalServerContext() {
return {
connectionMode: "local",
features: {},
features: getFeatureOverrides(),
};

@@ -19,3 +29,3 @@ }

connectionMode: "remote_oauth",
features,
features: { ...features, ...getFeatureOverrides() },
};

@@ -30,3 +40,3 @@ }

connectionMode: "remote_single_styleguide",
features: credentials.features,
features: { ...credentials.features, ...getFeatureOverrides() },
styleguideId: credentials.styleguideId,

@@ -38,2 +48,2 @@ styleguideName: credentials.styleguideName,

//# sourceMappingURL=context.js.map
//# debugId=30b81d5e-e94d-5bce-a3f1-4fe8a6b66d72
//# debugId=ff63079c-c318-594e-b1b7-e6b57d0ce65a

@@ -1,1 +0,1 @@

{"version":3,"file":"context.js","sources":["context.ts"],"sourceRoot":"/","sourcesContent":["import { Credentials } from \"./common/credentials.js\";\nimport { ServerContext } from \"./types/server.js\";\n\nexport class InvalidRemoteSingleStyleguideContextError extends Error {\n constructor() {\n super(\n \"Single-styleguide remote MCP requires JWT credentials with styleguideId\",\n );\n this.name = \"InvalidRemoteSingleStyleguideContextError\";\n }\n}\n\nexport function createLocalServerContext(): ServerContext {\n return {\n connectionMode: \"local\",\n features: {},\n };\n}\n\nexport function createRemoteOauthServerContext(\n features: Record<string, boolean> = {},\n): ServerContext {\n return {\n connectionMode: \"remote_oauth\",\n features,\n };\n}\n\nexport function createRemoteSingleStyleguideServerContext(\n credentials: Credentials,\n): ServerContext {\n if (\n credentials.type !== \"jwt\" ||\n typeof credentials.styleguideId !== \"number\"\n ) {\n throw new InvalidRemoteSingleStyleguideContextError();\n }\n\n return {\n connectionMode: \"remote_single_styleguide\",\n features: credentials.features,\n styleguideId: credentials.styleguideId,\n styleguideName: credentials.styleguideName,\n tokenSets: credentials.tokenSets,\n };\n}\n"],"names":[],"mappings":";;AAGA,MAAM,OAAO,yCAA0C,SAAQ,KAAK;IAClE;QACE,KAAK,CACH,yEAAyE,CAC1E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,2CAA2C,CAAC;IAC1D,CAAC;CACF;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,cAAc,EAAE,OAAO;QACvB,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,WAAoC,EAAE;IAEtC,OAAO;QACL,cAAc,EAAE,cAAc;QAC9B,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,WAAwB;IAExB,IACE,WAAW,CAAC,IAAI,KAAK,KAAK;QAC1B,OAAO,WAAW,CAAC,YAAY,KAAK,QAAQ,EAC5C,CAAC;QACD,MAAM,IAAI,yCAAyC,EAAE,CAAC;IACxD,CAAC;IAED,OAAO;QACL,cAAc,EAAE,0BAA0B;QAC1C,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,YAAY,EAAE,WAAW,CAAC,YAAY;QACtC,cAAc,EAAE,WAAW,CAAC,cAAc;QAC1C,SAAS,EAAE,WAAW,CAAC,SAAS;KACjC,CAAC;AACJ,CAAC","debug_id":"30b81d5e-e94d-5bce-a3f1-4fe8a6b66d72"}
{"version":3,"file":"context.js","sources":["context.ts"],"sourceRoot":"/","sourcesContent":["import { Credentials } from \"./common/credentials.js\";\nimport { ServerContext } from \"./types/server.js\";\n\nexport class InvalidRemoteSingleStyleguideContextError extends Error {\n constructor() {\n super(\n \"Single-styleguide remote MCP requires JWT credentials with styleguideId\",\n );\n this.name = \"InvalidRemoteSingleStyleguideContextError\";\n }\n}\n\nfunction getFeatureOverrides(): Record<string, boolean> {\n const overrides = process.env[\"FEATURE_OVERRIDES\"];\n if (!overrides) return {};\n\n return Object.fromEntries(\n overrides\n .split(\",\")\n .map((name) => name.trim())\n .filter(Boolean)\n .map((name) => [name, true]),\n );\n}\n\nexport function createLocalServerContext(): ServerContext {\n return {\n connectionMode: \"local\",\n features: getFeatureOverrides(),\n };\n}\n\nexport function createRemoteOauthServerContext(\n features: Record<string, boolean> = {},\n): ServerContext {\n return {\n connectionMode: \"remote_oauth\",\n features: { ...features, ...getFeatureOverrides() },\n };\n}\n\nexport function createRemoteSingleStyleguideServerContext(\n credentials: Credentials,\n): ServerContext {\n if (\n credentials.type !== \"jwt\" ||\n typeof credentials.styleguideId !== \"number\"\n ) {\n throw new InvalidRemoteSingleStyleguideContextError();\n }\n\n return {\n connectionMode: \"remote_single_styleguide\",\n features: { ...credentials.features, ...getFeatureOverrides() },\n styleguideId: credentials.styleguideId,\n styleguideName: credentials.styleguideName,\n tokenSets: credentials.tokenSets,\n };\n}\n"],"names":[],"mappings":";;AAGA,MAAM,OAAO,yCAA0C,SAAQ,KAAK;IAClE;QACE,KAAK,CACH,yEAAyE,CAC1E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,2CAA2C,CAAC;IAC1D,CAAC;CACF;AAED,SAAS,mBAAmB;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnD,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAE1B,OAAO,MAAM,CAAC,WAAW,CACvB,SAAS;SACN,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,cAAc,EAAE,OAAO;QACvB,QAAQ,EAAE,mBAAmB,EAAE;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,WAAoC,EAAE;IAEtC,OAAO;QACL,cAAc,EAAE,cAAc;QAC9B,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,mBAAmB,EAAE,EAAE;KACpD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,WAAwB;IAExB,IACE,WAAW,CAAC,IAAI,KAAK,KAAK;QAC1B,OAAO,WAAW,CAAC,YAAY,KAAK,QAAQ,EAC5C,CAAC;QACD,MAAM,IAAI,yCAAyC,EAAE,CAAC;IACxD,CAAC;IAED,OAAO;QACL,cAAc,EAAE,0BAA0B;QAC1C,QAAQ,EAAE,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,mBAAmB,EAAE,EAAE;QAC/D,YAAY,EAAE,WAAW,CAAC,YAAY;QACtC,cAAc,EAAE,WAAW,CAAC,cAAc;QAC1C,SAAS,EAAE,WAAW,CAAC,SAAS;KACjC,CAAC;AACJ,CAAC","debug_id":"ff63079c-c318-594e-b1b7-e6b57d0ce65a"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="de5a1ebe-3d68-5029-910b-6ef417fd9863")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6a7b671d-75a6-5622-b415-31dca427879b")}catch(e){}}();
import * as amplitude from "@amplitude/analytics-node";
import * as Sentry from "@sentry/node";
import { ApiType, internalRequest, request } from "./api/api.js";
import { getCredentials, isLocalMCP } from "./common/credentials.js";
import { captureMessage } from "./common/errors.js";
import { log } from "./common/logger.js";
import { setActiveTool, setRequestUser } from "./common/requestContext.js";
import { getCredentials, isLocalMCP, } from "./common/credentials.js";
import packageJson from "../package.json" with { type: "json" };

@@ -13,3 +17,3 @@ let enabled = false;

if (process.env["NODE_ENV"] !== "dev") {
amplitude.init(key);
amplitude.init(key, { minIdLength: 1 });
}

@@ -22,3 +26,3 @@ enabled = true;

if (process.env["NODE_ENV"] === "dev") {
console.log("Amplitude track:", ...args);
log.info("Amplitude track:", ...args);
}

@@ -29,2 +33,11 @@ else {

};
export function getAmplitudeUserId(credentials) {
if (credentials.type === "client_token")
return undefined;
if (credentials.userId)
return `${credentials.userId}`;
if (credentials.viewerId)
return `${credentials.viewerId}`;
return undefined;
}
function sendMcpLog(payload, credentials) {

@@ -34,3 +47,3 @@ const promise = isLocalMCP(credentials)

: internalRequest("/mcp/log", "POST", payload);
promise.catch((err) => console.error("Failed to send MCP log:", err));
promise.catch((err) => log.error("Failed to send MCP log:", err));
}

@@ -74,2 +87,27 @@ function buildLogPayload(toolName, toolParameters, credentials, clientUserAgent, serverVersion, durationMs, success, errorMessage) {

}
// Lambda timeout is 30s (defined in app-stack.ts)
// when we approach this, log the tool call so we can investigate why
const TOOL_TIMEOUT_WARNING_MS = 28_000;
async function runWithTimeoutWarning(toolName, toolArgs, fn) {
if (!process.env["SENTRY_DSN"])
return fn();
const startTime = Date.now();
const timer = setTimeout(() => {
captureMessage("MCP call approaching timeout", {
level: "warning",
tags: {
tool_name: toolName,
tool_args: JSON.stringify(toolArgs),
elapsed_seconds: (Date.now() - startTime) / 1000,
},
});
Sentry.flush(1500).catch(() => { });
}, TOOL_TIMEOUT_WARNING_MS);
try {
return await fn();
}
finally {
clearTimeout(timer);
}
}
/**

@@ -80,3 +118,7 @@ * Wraps a tool handler to track tool calls via Amplitude and DB logging.

export function registerTrackedToolCall(server, name, config, handler) {
server.registerTool(name, config, (async (args, context) => {
server.registerTool(name, config, (async (
// @ts-expect-error - implicit any from generic type
args,
// @ts-expect-error - implicit any from generic type
context) => {
const clientVersion = server.server.getClientVersion();

@@ -87,15 +129,20 @@ const fallbackUserAgent = clientVersion

const userAgent = getUserAgent(context.requestInfo?.headers, fallbackUserAgent);
const credentials = await getCredentials(context.authInfo);
setRequestUser(credentials);
const sanitizedArgs = sanitizeToolParams(name, args);
setActiveTool(name, sanitizedArgs);
const startTime = Date.now();
// args is loosely typed by the SDK callback; the schema guarantees correctness
const result = await handler(args, context, userAgent);
const result = await runWithTimeoutWarning(name, sanitizedArgs, () => handler(args, context, userAgent));
const durationMs = Date.now() - startTime;
const isError = result.isError ?? false;
const errorMessage = isError
? result.content.filter((item) => item.type === "text").map((item) => item.text).join("\n")
? result.content
.filter((item) => item.type === "text")
.map((item) => item.text)
.join("\n")
: undefined;
const credentials = await getCredentials(context.authInfo);
if (enabled) {
const eventProperties = {
tool_name: name,
tool_parameters: sanitizeToolParams(name, args),
tool_parameters: sanitizedArgs,
success: !isError,

@@ -106,20 +153,102 @@ progress_token: context._meta?.progressToken,

};
// @todo: Enable tracking for `oauth_jwt` once we have unique ID to use for McpConsumers
// Currently McpConsumers have an int id which will clash with normal Users in Amplitude
if (credentials.type === "jwt") {
track({
event_type: "mcp:tool_call",
event_properties: eventProperties,
user_properties: {
team_id: credentials.teamId,
viewer_id: credentials.viewerId,
styleguide_id: credentials.styleguideId,
},
user_agent: userAgent,
user_id: credentials.userId ? `${credentials.userId}` : undefined,
});
const userId = getAmplitudeUserId(credentials);
if (userId) {
track({
event_type: "mcp:tool_call",
event_properties: eventProperties,
user_properties: {
team_id: credentials.teamId,
viewer_id: credentials.viewerId,
styleguide_id: credentials.styleguideId,
},
user_agent: userAgent,
user_id: userId,
});
}
else {
captureMessage("Amplitude event skipped: missing user identifier", {
level: "warning",
extra: {
tool_name: name,
credentials_type: credentials.type,
auth_id: credentials.mcpAuthId,
},
});
}
}
}
sendMcpLog(buildLogPayload(name, sanitizeToolParams(name, args), credentials, userAgent, packageJson.version, durationMs, !isError, errorMessage), credentials);
sendMcpLog(buildLogPayload(name, sanitizedArgs, credentials, userAgent, packageJson.version, durationMs, !isError, errorMessage), credentials);
return result;
}));
}
export function registerTrackedResource(server, name, template, metadata, handler) {
server.registerResource(name, template, metadata, async (uri, variables, extra) => {
const clientVersion = server.server.getClientVersion();
const fallbackUserAgent = clientVersion
? `${clientVersion.name}/${clientVersion.version}`
: undefined;
const userAgent = getUserAgent(extra.requestInfo?.headers, fallbackUserAgent);
const credentials = await getCredentials(extra.authInfo);
setRequestUser(credentials);
const startTime = Date.now();
let result;
let errorMessage;
let success = true;
try {
result = await handler(uri, variables, extra);
}
catch (err) {
success = false;
errorMessage = err instanceof Error ? err.message : String(err);
throw err;
}
finally {
const durationMs = Date.now() - startTime;
const resourceParams = { ...variables };
if (enabled) {
const eventProperties = {
tool_name: `resource:${name}`,
tool_parameters: resourceParams,
success,
progress_token: extra._meta?.progressToken,
mcp_client_user_agent: userAgent,
duration_ms: durationMs,
};
// @todo: Enable tracking for `oauth_jwt` once we have unique ID to use for McpConsumers
// Currently McpConsumers have an int id which will clash with normal Users in Amplitude
if (credentials.type === "jwt") {
const userId = getAmplitudeUserId(credentials);
if (userId) {
track({
event_type: "mcp:resource_read",
event_properties: eventProperties,
user_properties: {
team_id: credentials.teamId,
viewer_id: credentials.viewerId,
styleguide_id: credentials.styleguideId,
},
user_agent: userAgent,
user_id: userId,
});
}
else {
captureMessage("Amplitude event skipped: missing user identifier", {
level: "warning",
extra: {
resource_name: name,
credentials_type: credentials.type,
auth_id: credentials.mcpAuthId,
},
});
}
}
sendMcpLog(buildLogPayload(`resource:${name}`, resourceParams, credentials, userAgent, packageJson.version, durationMs, success, errorMessage), credentials);
}
return result;
}
});
}
const getUserAgent = (headers, fallback) => {

@@ -137,2 +266,2 @@ if (headers) {

//# sourceMappingURL=logging.js.map
//# debugId=de5a1ebe-3d68-5029-910b-6ef417fd9863
//# debugId=6a7b671d-75a6-5622-b415-31dca427879b

@@ -1,1 +0,1 @@

{"version":3,"file":"logging.js","sources":["logging.ts"],"sourceRoot":"/","sourcesContent":["import * as amplitude from \"@amplitude/analytics-node\";\nimport {\n McpServer,\n ToolCallback,\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport {\n CallToolResult,\n ServerNotification,\n ServerRequest,\n ToolAnnotations,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport z, { ZodRawShape } from \"zod\";\nimport { ApiType, internalRequest, request } from \"./api/api.js\";\nimport { Credentials, getCredentials, isLocalMCP } from \"./common/credentials.js\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\nlet enabled = false;\nexport function initAmplitude() {\n const key = process.env[\"AMPLITUDE_API_KEY\"];\n if (!key) return;\n\n if (process.env[\"NODE_ENV\"] !== \"dev\") {\n amplitude.init(key);\n }\n enabled = true;\n}\n\nconst track = (...args: Parameters<typeof amplitude.track>) => {\n if (!enabled) return;\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n console.log(\"Amplitude track:\", ...args);\n } else {\n amplitude.track(...args);\n }\n};\n\ninterface EventProperties {\n tool_name: string;\n tool_parameters: Record<string, unknown>;\n success: boolean;\n error_message?: string;\n progress_token?: string | number | undefined;\n mcp_client_user_agent?: string;\n duration_ms?: number;\n}\n\ninterface UserProperties {\n team_id?: number;\n viewer_id?: string;\n styleguide_id?: number;\n token?: string;\n}\n\ninterface McpLogPayload {\n tool_name: string;\n tool_parameters: Record<string, unknown>;\n success: boolean;\n error_message?: string;\n mcp_client_user_agent?: string;\n mcp_server_version?: string;\n transport: string;\n duration_ms?: number;\n team_id?: number;\n user_id?: number;\n styleguide_id?: number;\n mcp_auth_id?: number;\n viewer_id?: string;\n oauth_client_id?: string;\n client_id?: string;\n}\n\nfunction sendMcpLog(payload: McpLogPayload, credentials: Credentials): void {\n const promise =\n isLocalMCP(credentials)\n ? request(\"/mcp/log\", credentials, { method: \"POST\", body: JSON.stringify(payload) }, undefined, ApiType.Internal)\n : internalRequest(\"/mcp/log\", \"POST\", payload);\n\n promise.catch((err) => console.error(\"Failed to send MCP log:\", err));\n}\n\nfunction buildLogPayload(\n toolName: string,\n toolParameters: Record<string, unknown>,\n credentials: Credentials,\n clientUserAgent: string | undefined,\n serverVersion: string,\n durationMs: number,\n success: boolean,\n errorMessage?: string,\n): McpLogPayload {\n const base: McpLogPayload = {\n tool_name: toolName,\n tool_parameters: toolParameters,\n success,\n transport: isLocalMCP(credentials) ? \"local\" : \"remote\",\n mcp_client_user_agent: clientUserAgent,\n mcp_server_version: serverVersion,\n duration_ms: durationMs,\n };\n\n if (errorMessage !== undefined) {\n base.error_message = errorMessage;\n }\n\n if (credentials.type === \"jwt\") {\n base.team_id = credentials.teamId;\n base.user_id = credentials.userId;\n base.styleguide_id = credentials.styleguideId;\n base.mcp_auth_id = credentials.mcpAuthId;\n base.viewer_id = credentials.viewerId;\n } else if (credentials.type === \"oauth_jwt\") {\n base.team_id = credentials.teamId;\n base.user_id = credentials.userId;\n base.oauth_client_id = credentials.clientId;\n } else if (isLocalMCP(credentials)) {\n base.client_id = credentials.client;\n }\n\n return base;\n}\n\nfunction sanitizeToolParams(\n toolName: string,\n params: Record<string, unknown>,\n): Record<string, unknown> {\n const sanitized = { ...params };\n if (toolName === \"lint-code\") {\n delete sanitized.code;\n }\n return sanitized;\n}\n\nexport type TrackedToolCallback<Args extends ZodRawShape> = (\n args: z.objectOutputType<Args, z.ZodTypeAny>,\n context: RequestHandlerExtra<ServerRequest, ServerNotification>,\n clientUserAgent: string | undefined,\n) => CallToolResult | Promise<CallToolResult>;\n\n/**\n * Wraps a tool handler to track tool calls via Amplitude and DB logging.\n * Resolves the client user agent centrally and passes it to the handler.\n */\nexport function registerTrackedToolCall<\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n>(\n server: McpServer,\n name: string,\n config: {\n title?: string;\n description?: string;\n inputSchema?: InputArgs;\n outputSchema?: OutputArgs;\n annotations?: ToolAnnotations;\n },\n handler: TrackedToolCallback<InputArgs>,\n) {\n server.registerTool<InputArgs, OutputArgs>(name, config, (async (\n args,\n context,\n ) => {\n const clientVersion = server.server.getClientVersion();\n const fallbackUserAgent = clientVersion\n ? `${clientVersion.name}/${clientVersion.version}`\n : undefined;\n const userAgent = getUserAgent(context.requestInfo?.headers, fallbackUserAgent);\n\n const startTime = Date.now();\n // args is loosely typed by the SDK callback; the schema guarantees correctness\n const result = await handler(args as any, context, userAgent);\n const durationMs = Date.now() - startTime;\n\n const isError = result.isError ?? false;\n const errorMessage = isError\n ? result.content.filter((item) => item.type === \"text\").map((item) => item.text).join(\"\\n\")\n : undefined;\n\n const credentials = await getCredentials(context.authInfo);\n\n if (enabled) {\n const eventProperties: EventProperties = {\n tool_name: name,\n tool_parameters: sanitizeToolParams(name, args),\n success: !isError,\n progress_token: context._meta?.progressToken,\n mcp_client_user_agent: userAgent,\n duration_ms: durationMs,\n };\n\n if (credentials.type === \"jwt\") {\n track({\n event_type: \"mcp:tool_call\",\n event_properties: eventProperties,\n user_properties: {\n team_id: credentials.teamId,\n viewer_id: credentials.viewerId,\n styleguide_id: credentials.styleguideId,\n } satisfies UserProperties,\n user_agent: userAgent,\n user_id: credentials.userId ? `${credentials.userId}` : undefined,\n });\n }\n }\n\n sendMcpLog(\n buildLogPayload(\n name,\n sanitizeToolParams(name, args),\n credentials,\n userAgent,\n packageJson.version,\n durationMs,\n !isError,\n errorMessage,\n ),\n credentials,\n );\n\n return result;\n }) as ToolCallback<InputArgs>);\n}\n\nconst getUserAgent = (\n headers: Record<string, string | string[] | undefined> | undefined,\n fallback?: string,\n) => {\n if (headers) {\n if (Array.isArray(headers[\"user-agent\"])) {\n return headers[\"user-agent\"].join(\" \");\n }\n if (typeof headers[\"user-agent\"] === \"string\") {\n return headers[\"user-agent\"];\n }\n }\n return fallback;\n};\n"],"names":[],"mappings":"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","debug_id":"de5a1ebe-3d68-5029-910b-6ef417fd9863"}
{"version":3,"file":"logging.js","sources":["logging.ts"],"sourceRoot":"/","sourcesContent":["import * as amplitude from \"@amplitude/analytics-node\";\nimport {\n McpServer,\n ReadResourceTemplateCallback,\n ResourceMetadata,\n ResourceTemplate,\n ToolCallback,\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport {\n CallToolResult,\n ReadResourceResult,\n ServerNotification,\n ServerRequest,\n ToolAnnotations,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { ZodRawShape, ZodType, output } from \"zod\";\nimport * as Sentry from \"@sentry/node\";\nimport { ApiType, internalRequest, request } from \"./api/api.js\";\nimport { captureMessage } from \"./common/errors.js\";\nimport { log } from \"./common/logger.js\";\nimport { setActiveTool, setRequestUser } from \"./common/requestContext.js\";\nimport {\n Credentials,\n getCredentials,\n isLocalMCP,\n} from \"./common/credentials.js\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\nlet enabled = false;\nexport function initAmplitude() {\n const key = process.env[\"AMPLITUDE_API_KEY\"];\n if (!key) return;\n\n if (process.env[\"NODE_ENV\"] !== \"dev\") {\n amplitude.init(key, { minIdLength: 1 });\n }\n enabled = true;\n}\n\nconst track = (...args: Parameters<typeof amplitude.track>) => {\n if (!enabled) return;\n\n if (process.env[\"NODE_ENV\"] === \"dev\") {\n log.info(\"Amplitude track:\", ...args);\n } else {\n amplitude.track(...args);\n }\n};\n\ninterface EventProperties {\n tool_name: string;\n tool_parameters: Record<string, unknown>;\n success: boolean;\n error_message?: string;\n progress_token?: string | number | undefined;\n mcp_client_user_agent?: string;\n duration_ms?: number;\n}\n\ninterface UserProperties {\n team_id?: number;\n viewer_id?: string;\n styleguide_id?: number;\n token?: string;\n}\n\ninterface McpLogPayload {\n tool_name: string;\n tool_parameters: Record<string, unknown>;\n success: boolean;\n error_message?: string;\n mcp_client_user_agent?: string;\n mcp_server_version?: string;\n transport: string;\n duration_ms?: number;\n team_id?: number;\n user_id?: number;\n styleguide_id?: number;\n mcp_auth_id?: number;\n viewer_id?: string;\n oauth_client_id?: string;\n client_id?: string;\n}\n\nexport function getAmplitudeUserId(\n credentials: Credentials,\n): string | undefined {\n if (credentials.type === \"client_token\") return undefined;\n if (credentials.userId) return `${credentials.userId}`;\n if (credentials.viewerId) return `${credentials.viewerId}`;\n return undefined;\n}\n\nfunction sendMcpLog(payload: McpLogPayload, credentials: Credentials): void {\n const promise = isLocalMCP(credentials)\n ? request(\n \"/mcp/log\",\n credentials,\n { method: \"POST\", body: JSON.stringify(payload) },\n undefined,\n ApiType.Internal,\n )\n : internalRequest(\"/mcp/log\", \"POST\", payload);\n\n promise.catch((err) => log.error(\"Failed to send MCP log:\", err));\n}\n\nfunction buildLogPayload(\n toolName: string,\n toolParameters: Record<string, unknown>,\n credentials: Credentials,\n clientUserAgent: string | undefined,\n serverVersion: string,\n durationMs: number,\n success: boolean,\n errorMessage?: string,\n): McpLogPayload {\n const base: McpLogPayload = {\n tool_name: toolName,\n tool_parameters: toolParameters,\n success,\n transport: isLocalMCP(credentials) ? \"local\" : \"remote\",\n mcp_client_user_agent: clientUserAgent,\n mcp_server_version: serverVersion,\n duration_ms: durationMs,\n };\n\n if (errorMessage !== undefined) {\n base.error_message = errorMessage;\n }\n\n if (credentials.type === \"jwt\") {\n base.team_id = credentials.teamId;\n base.user_id = credentials.userId;\n base.styleguide_id = credentials.styleguideId;\n base.mcp_auth_id = credentials.mcpAuthId;\n base.viewer_id = credentials.viewerId;\n } else if (credentials.type === \"oauth_jwt\") {\n base.team_id = credentials.teamId;\n base.user_id = credentials.userId;\n base.oauth_client_id = credentials.clientId;\n } else if (isLocalMCP(credentials)) {\n base.client_id = credentials.client;\n }\n\n return base;\n}\n\nfunction sanitizeToolParams(\n toolName: string,\n params: Record<string, unknown>,\n): Record<string, unknown> {\n const sanitized = { ...params };\n if (toolName === \"lint-code\") {\n delete sanitized.code;\n }\n return sanitized;\n}\n\n// Lambda timeout is 30s (defined in app-stack.ts)\n// when we approach this, log the tool call so we can investigate why\nconst TOOL_TIMEOUT_WARNING_MS = 28_000;\nasync function runWithTimeoutWarning<T>(\n toolName: string,\n toolArgs: Record<string, unknown>,\n fn: () => T | Promise<T>,\n): Promise<T> {\n if (!process.env[\"SENTRY_DSN\"]) return fn();\n\n const startTime = Date.now();\n const timer = setTimeout(() => {\n captureMessage(\"MCP call approaching timeout\", {\n level: \"warning\",\n tags: {\n tool_name: toolName,\n tool_args: JSON.stringify(toolArgs),\n elapsed_seconds: (Date.now() - startTime) / 1000,\n },\n });\n Sentry.flush(1500).catch(() => {});\n }, TOOL_TIMEOUT_WARNING_MS);\n\n try {\n return await fn();\n } finally {\n clearTimeout(timer);\n }\n}\n\ntype Map<T> = T extends ZodRawShape ? { [K in keyof T]: output<T[K]> } : never;\n\ntype inferOutput<T> = T extends ZodRawShape ? Map<T> : output<T>;\n\nexport type TrackedToolCallback<\n Args extends ZodRawShape | ZodType | undefined,\n> = (\n args: inferOutput<Args>,\n context: RequestHandlerExtra<ServerRequest, ServerNotification>,\n clientUserAgent: string | undefined,\n) => CallToolResult | Promise<CallToolResult>;\n\n/**\n * Wraps a tool handler to track tool calls via Amplitude and DB logging.\n * Resolves the client user agent centrally and passes it to the handler.\n */\nexport function registerTrackedToolCall<\n OutputArgs extends ZodRawShape | ZodType,\n InputArgs extends undefined | ZodRawShape | ZodType = undefined,\n>(\n server: McpServer,\n name: string,\n config: {\n title?: string;\n description?: string;\n inputSchema?: InputArgs;\n outputSchema?: OutputArgs;\n annotations?: ToolAnnotations;\n _meta?: Record<string, unknown>;\n },\n handler: TrackedToolCallback<InputArgs>,\n) {\n server.registerTool<OutputArgs, InputArgs>(name, config, (async (\n // @ts-expect-error - implicit any from generic type\n args,\n // @ts-expect-error - implicit any from generic type\n context,\n ) => {\n const clientVersion = server.server.getClientVersion();\n const fallbackUserAgent = clientVersion\n ? `${clientVersion.name}/${clientVersion.version}`\n : undefined;\n const userAgent = getUserAgent(\n context.requestInfo?.headers,\n fallbackUserAgent,\n );\n\n const credentials = await getCredentials(context.authInfo);\n setRequestUser(credentials);\n\n const sanitizedArgs = sanitizeToolParams(name, args);\n setActiveTool(name, sanitizedArgs);\n\n const startTime = Date.now();\n const result = await runWithTimeoutWarning(name, sanitizedArgs, () =>\n handler(args as any, context, userAgent),\n );\n const durationMs = Date.now() - startTime;\n\n const isError = result.isError ?? false;\n const errorMessage = isError\n ? result.content\n .filter((item) => item.type === \"text\")\n .map((item) => item.text)\n .join(\"\\n\")\n : undefined;\n\n if (enabled) {\n const eventProperties: EventProperties = {\n tool_name: name,\n tool_parameters: sanitizedArgs,\n success: !isError,\n progress_token: context._meta?.progressToken,\n mcp_client_user_agent: userAgent,\n duration_ms: durationMs,\n };\n\n // @todo: Enable tracking for `oauth_jwt` once we have unique ID to use for McpConsumers\n // Currently McpConsumers have an int id which will clash with normal Users in Amplitude\n if (credentials.type === \"jwt\") {\n const userId = getAmplitudeUserId(credentials);\n if (userId) {\n track({\n event_type: \"mcp:tool_call\",\n event_properties: eventProperties,\n user_properties: {\n team_id: credentials.teamId,\n viewer_id: credentials.viewerId,\n styleguide_id: credentials.styleguideId,\n } satisfies UserProperties,\n user_agent: userAgent,\n user_id: userId,\n });\n } else {\n captureMessage(\"Amplitude event skipped: missing user identifier\", {\n level: \"warning\",\n extra: {\n tool_name: name,\n credentials_type: credentials.type,\n auth_id: credentials.mcpAuthId,\n },\n });\n }\n }\n }\n\n sendMcpLog(\n buildLogPayload(\n name,\n sanitizedArgs,\n credentials,\n userAgent,\n packageJson.version,\n durationMs,\n !isError,\n errorMessage,\n ),\n credentials,\n );\n\n return result;\n }) as ToolCallback<InputArgs>);\n}\n\nexport function registerTrackedResource(\n server: McpServer,\n name: string,\n template: ResourceTemplate,\n metadata: ResourceMetadata,\n handler: ReadResourceTemplateCallback,\n) {\n server.registerResource(\n name,\n template,\n metadata,\n async (uri, variables, extra) => {\n const clientVersion = server.server.getClientVersion();\n const fallbackUserAgent = clientVersion\n ? `${clientVersion.name}/${clientVersion.version}`\n : undefined;\n const userAgent = getUserAgent(\n extra.requestInfo?.headers,\n fallbackUserAgent,\n );\n\n const credentials = await getCredentials(extra.authInfo);\n setRequestUser(credentials);\n\n const startTime = Date.now();\n let result: ReadResourceResult;\n let errorMessage: string | undefined;\n let success = true;\n\n try {\n result = await handler(uri, variables, extra);\n } catch (err) {\n success = false;\n errorMessage = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n const durationMs = Date.now() - startTime;\n const resourceParams: Record<string, unknown> = { ...variables };\n\n if (enabled) {\n const eventProperties: EventProperties = {\n tool_name: `resource:${name}`,\n tool_parameters: resourceParams,\n success,\n progress_token: extra._meta?.progressToken,\n mcp_client_user_agent: userAgent,\n duration_ms: durationMs,\n };\n\n // @todo: Enable tracking for `oauth_jwt` once we have unique ID to use for McpConsumers\n // Currently McpConsumers have an int id which will clash with normal Users in Amplitude\n if (credentials.type === \"jwt\") {\n const userId = getAmplitudeUserId(credentials);\n if (userId) {\n track({\n event_type: \"mcp:resource_read\",\n event_properties: eventProperties,\n user_properties: {\n team_id: credentials.teamId,\n viewer_id: credentials.viewerId,\n styleguide_id: credentials.styleguideId,\n } satisfies UserProperties,\n user_agent: userAgent,\n user_id: userId,\n });\n } else {\n captureMessage(\n \"Amplitude event skipped: missing user identifier\",\n {\n level: \"warning\",\n extra: {\n resource_name: name,\n credentials_type: credentials.type,\n auth_id: credentials.mcpAuthId,\n },\n },\n );\n }\n }\n\n sendMcpLog(\n buildLogPayload(\n `resource:${name}`,\n resourceParams,\n credentials,\n userAgent,\n packageJson.version,\n durationMs,\n success,\n errorMessage,\n ),\n credentials,\n );\n }\n\n return result!;\n }\n },\n );\n}\n\nconst getUserAgent = (\n headers: Record<string, string | string[] | undefined> | undefined,\n fallback?: string,\n) => {\n if (headers) {\n if (Array.isArray(headers[\"user-agent\"])) {\n return headers[\"user-agent\"].join(\" \");\n }\n if (typeof headers[\"user-agent\"] === \"string\") {\n return headers[\"user-agent\"];\n }\n }\n return fallback;\n};\n"],"names":[],"mappings":"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","debug_id":"6a7b671d-75a6-5622-b415-31dca427879b"}
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="90977dea-fb56-575a-aa98-e6b90076a20e")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bdd8de84-5c0d-5016-b161-0414e740d95a")}catch(e){}}();
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

@@ -9,2 +9,3 @@ import packageJson from "../package.json" with { type: "json" };

import { registerLintCodeTool } from "./tools/lint.js";
import { registerPageImageResource } from "./resources/page.js";
import { recommendSummarizePagePrompt } from "./prompts/page.js";

@@ -19,5 +20,2 @@ import { registerRecommendPagesPrompt } from "./prompts/styleguide.js";

version: packageJson.version,
capabilities: {
tools: {},
},
});

@@ -38,2 +36,4 @@ // Register tools

].forEach((fn) => fn(server, context));
// Register resources
registerPageImageResource(server, context);
// Register all prompts

@@ -45,2 +45,2 @@ registerRecommendPagesPrompt(server, context);

//# sourceMappingURL=mcp-server.js.map
//# debugId=90977dea-fb56-575a-aa98-e6b90076a20e
//# debugId=bdd8de84-5c0d-5016-b161-0414e740d95a

@@ -1,1 +0,1 @@

{"version":3,"file":"mcp-server.js","sources":["mcp-server.ts"],"sourceRoot":"/","sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n registerListPagesTool,\n registerListReleasesTool,\n registerListStyleguidesTool,\n} from \"./tools/styleguide.js\";\nimport {\n registerGetPageTool,\n registerGetPageImagesTool,\n registerSearchPagesTool,\n} from \"./tools/page.js\";\nimport {\n registerGetTokensTool,\n registerListTokenSetsTool,\n} from \"./tools/token.js\";\nimport { registerLintCodeTool } from \"./tools/lint.js\";\nimport { recommendSummarizePagePrompt } from \"./prompts/page.js\";\nimport { registerRecommendPagesPrompt } from \"./prompts/styleguide.js\";\nimport { ServerContext } from \"./types/server.js\";\n\nexport function createServer(\n context: ServerContext = {\n connectionMode: \"local\",\n features: {},\n },\n) {\n const server = new McpServer({\n name: \"zeroheight\",\n version: packageJson.version,\n capabilities: {\n tools: {},\n },\n });\n\n // Register tools\n if (context.connectionMode !== \"remote_single_styleguide\") {\n registerListStyleguidesTool(server);\n }\n\n [\n registerListPagesTool,\n registerListReleasesTool,\n registerGetPageTool,\n registerGetPageImagesTool,\n registerSearchPagesTool,\n registerListTokenSetsTool,\n registerGetTokensTool,\n registerLintCodeTool,\n ].forEach((fn) => fn(server, context));\n\n // Register all prompts\n registerRecommendPagesPrompt(server, context);\n recommendSummarizePagePrompt(server);\n\n return server;\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAGvE,MAAM,UAAU,YAAY,CAC1B,UAAyB;IACvB,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,EAAE;CACb;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CAAC,CAAC;IAEH,iBAAiB;IACjB,IAAI,OAAO,CAAC,cAAc,KAAK,0BAA0B,EAAE,CAAC;QAC1D,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED;QACE,qBAAqB;QACrB,wBAAwB;QACxB,mBAAmB;QACnB,yBAAyB;QACzB,uBAAuB;QACvB,yBAAyB;QACzB,qBAAqB;QACrB,oBAAoB;KACrB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEvC,uBAAuB;IACvB,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAErC,OAAO,MAAM,CAAC;AAChB,CAAC","debug_id":"90977dea-fb56-575a-aa98-e6b90076a20e"}
{"version":3,"file":"mcp-server.js","sources":["mcp-server.ts"],"sourceRoot":"/","sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport {\n registerListPagesTool,\n registerListReleasesTool,\n registerListStyleguidesTool,\n} from \"./tools/styleguide.js\";\nimport {\n registerGetPageTool,\n registerGetPageImagesTool,\n registerSearchPagesTool,\n} from \"./tools/page.js\";\nimport {\n registerGetTokensTool,\n registerListTokenSetsTool,\n} from \"./tools/token.js\";\nimport { registerLintCodeTool } from \"./tools/lint.js\";\nimport { registerPageImageResource } from \"./resources/page.js\";\nimport { recommendSummarizePagePrompt } from \"./prompts/page.js\";\nimport { registerRecommendPagesPrompt } from \"./prompts/styleguide.js\";\nimport { ServerContext } from \"./types/server.js\";\n\nexport function createServer(\n context: ServerContext = {\n connectionMode: \"local\",\n features: {},\n },\n) {\n const server = new McpServer({\n name: \"zeroheight\",\n version: packageJson.version,\n });\n\n // Register tools\n if (context.connectionMode !== \"remote_single_styleguide\") {\n registerListStyleguidesTool(server);\n }\n\n [\n registerListPagesTool,\n registerListReleasesTool,\n registerGetPageTool,\n registerGetPageImagesTool,\n registerSearchPagesTool,\n registerListTokenSetsTool,\n registerGetTokensTool,\n registerLintCodeTool,\n ].forEach((fn) => fn(server, context));\n\n // Register resources\n registerPageImageResource(server, context);\n\n // Register all prompts\n registerRecommendPagesPrompt(server, context);\n recommendSummarizePagePrompt(server);\n\n return server;\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAGvE,MAAM,UAAU,YAAY,CAC1B,UAAyB;IACvB,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,EAAE;CACb;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,WAAW,CAAC,OAAO;KAC7B,CAAC,CAAC;IAEH,iBAAiB;IACjB,IAAI,OAAO,CAAC,cAAc,KAAK,0BAA0B,EAAE,CAAC;QAC1D,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED;QACE,qBAAqB;QACrB,wBAAwB;QACxB,mBAAmB;QACnB,yBAAyB;QACzB,uBAAuB;QACvB,yBAAyB;QACzB,qBAAqB;QACrB,oBAAoB;KACrB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEvC,qBAAqB;IACrB,yBAAyB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3C,uBAAuB;IACvB,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAErC,OAAO,MAAM,CAAC;AAChB,CAAC","debug_id":"bdd8de84-5c0d-5016-b161-0414e740d95a"}
#!/usr/bin/env node
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="50865840-a409-51b5-ad76-8c41f2644aa6")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1d22cd5f-2efc-5125-9f6c-fba2597efacf")}catch(e){}}();
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { initSentry } from "./api/sentry.js";
import { captureException } from "./common/errors.js";
import { useStderrOnly } from "./common/logger.js";
import { createLocalServerContext } from "./context.js";
import { createServer } from "./mcp-server.js";
useStderrOnly();
/**

@@ -28,2 +30,2 @@ * Start server on STDIO

//# sourceMappingURL=stdio.js.map
//# debugId=50865840-a409-51b5-ad76-8c41f2644aa6
//# debugId=1d22cd5f-2efc-5125-9f6c-fba2597efacf

@@ -1,1 +0,1 @@

{"version":3,"file":"stdio.js","sources":["stdio.ts"],"sourceRoot":"/","sourcesContent":["#!/usr/bin/env node\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { initSentry } from \"./api/sentry.js\";\nimport { captureException } from \"./common/errors.js\";\nimport { createLocalServerContext } from \"./context.js\";\nimport { createServer } from \"./mcp-server.js\";\n\n/**\n * Start server on STDIO\n */\nasync function main() {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n if (!disableTelemetry) {\n initSentry();\n }\n\n const server = createServer(createLocalServerContext());\n const transport = new StdioServerTransport();\n\n await server.connect(transport);\n console.error(\"zeroheight MCP Server running on stdio\");\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error in main():\", error);\n captureException(error);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,UAAU,EAAE,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,wBAAwB,EAAE,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC1D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IAC/C,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC","debug_id":"50865840-a409-51b5-ad76-8c41f2644aa6"}
{"version":3,"file":"stdio.js","sources":["stdio.ts"],"sourceRoot":"/","sourcesContent":["#!/usr/bin/env node\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { initSentry } from \"./api/sentry.js\";\nimport { captureException } from \"./common/errors.js\";\nimport { useStderrOnly } from \"./common/logger.js\";\nimport { createLocalServerContext } from \"./context.js\";\nimport { createServer } from \"./mcp-server.js\";\n\nuseStderrOnly();\n\n/**\n * Start server on STDIO\n */\nasync function main() {\n const disableTelemetry = process.env[\"ZEROHEIGHT_MCP_DISABLE_TELEMETRY\"];\n if (!disableTelemetry) {\n initSentry();\n }\n\n const server = createServer(createLocalServerContext());\n const transport = new StdioServerTransport();\n\n await server.connect(transport);\n console.error(\"zeroheight MCP Server running on stdio\");\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error in main():\", error);\n captureException(error);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,aAAa,EAAE,CAAC;AAEhB;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACzE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,UAAU,EAAE,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,wBAAwB,EAAE,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC1D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IAC/C,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC","debug_id":"1d22cd5f-2efc-5125-9f6c-fba2597efacf"}

@@ -5,12 +5,15 @@ /**

!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="694bee8d-7ded-5054-9a83-2310df4ae0e6")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c75dd78d-13de-5f8b-b764-1ba34508622c")}catch(e){}}();
import z from "zod";
import { getPage, searchPages } from "../api/page.js";
import { formatPageAsMarkdown, formatPageListItemsAsMarkdown, extractImageUrlsFromPage, } from "../common/formatters/page.js";
import { formatPageAsMarkdown, formatPageListItemsAsMarkdown, extractImageUrlsFromPage, extractPageImageResourceLinks, extractPageAttachmentResourceLinks, pageHasAnnotations, } from "../common/formatters/page.js";
import { getCredentials } from "../common/credentials.js";
import { registerTrackedToolCall } from "../logging.js";
export function registerGetPageTool(server, _context) {
export function registerGetPageTool(server, context) {
const imageResourcesEnabled = context.features["OAK-37_mcp_image_resources"];
registerTrackedToolCall(server, "get-page", {
title: "Get a styleguide page",
description: "Fetch guidance from a specific design system page, including usage notes, recommendations, and supporting context.\n\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\n\n*If images from the page are needed, call `get-page-images` afterwards with the same page ID to retrieve them as base64-encoded content.*",
description: imageResourcesEnabled
? "Fetch guidance from a specific design system page, including usage notes, recommendations, supporting context, and any file attachments.\n\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\n\n*The response may include embedded image resource URIs (`zeroheight://image/...`) — use these to fetch individual images as needed. Only use `get-page-images` if you need every image from the page at once. File attachments are emitted as resource links pointing to their direct download URL.*"
: "Fetch guidance from a specific design system page, including usage notes, recommendations, supporting context, and any file attachments.\n\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\n\n*If images from the page are needed, call `get-page-images` afterwards with the same page ID to retrieve them as base64-encoded content. Non-image attachments are linked inline in the page content and can be shared with the user by URL.*",
inputSchema: {

@@ -49,2 +52,11 @@ pageId: z

const textContent = formatPageAsMarkdown(page);
const resourceLinks = context.features["OAK-37_mcp_image_resources"]
? [
...extractPageImageResourceLinks(textContent),
...extractPageAttachmentResourceLinks(textContent),
]
: [];
const annotatedText = pageHasAnnotations(textContent)
? `${textContent}\n\n*Note on annotations: marker positions are coordinate metadata only. Without fetching the corresponding image, you can list the labels but cannot determine what visual element each marker points at — be explicit about that limit rather than inferring from coordinates.*`
: textContent;
return {

@@ -54,5 +66,6 @@ content: [

type: "text",
text: textContent,
text: annotatedText,
mimeType: "text/markdown",
},
...resourceLinks,
],

@@ -62,6 +75,9 @@ };

}
export function registerGetPageImagesTool(server, _context) {
export function registerGetPageImagesTool(server, context) {
const imageResourcesEnabled = context.features["OAK-37_mcp_image_resources"];
registerTrackedToolCall(server, "get-page-images", {
title: "Get images from a styleguide page",
description: "Fetch all images from a specific design system page as base64-encoded content.\n\n*Call this after `get-page` with the same page ID if images are needed for the task — for example, when referencing visual examples, screenshots, or diagrams from the page.*",
description: imageResourcesEnabled
? "Fetch all images from a specific design system page as base64-encoded content. Includes both inline page images and image-typed file attachments.\n\n*Prefer using the image resource URIs embedded in `get-page` responses to fetch only the images you need. Use this tool only when you need every image from the page at once.*"
: "Fetch all images from a specific design system page as base64-encoded content. Includes both inline page images and image-typed file attachments.\n\n*Call this after `get-page` with the same page ID if images are needed for the task — for example, when referencing visual examples, screenshots, or diagrams from the page.*",
inputSchema: {

@@ -207,2 +223,2 @@ pageId: z

//# sourceMappingURL=page.js.map
//# debugId=694bee8d-7ded-5054-9a83-2310df4ae0e6
//# debugId=c75dd78d-13de-5f8b-b764-1ba34508622c

@@ -1,1 +0,1 @@

{"version":3,"file":"page.js","sources":["tools/page.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Page Tools\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport z from \"zod\";\n\nimport { getPage, searchPages } from \"../api/page.js\";\nimport {\n formatPageAsMarkdown,\n formatPageListItemsAsMarkdown,\n extractImageUrlsFromPage,\n} from \"../common/formatters/page.js\";\nimport { getCredentials } from \"../common/credentials.js\";\nimport { registerTrackedToolCall } from \"../logging.js\";\nimport { ServerContext } from \"../types/server.js\";\n\nexport function registerGetPageTool(\n server: McpServer,\n _context: ServerContext,\n) {\n registerTrackedToolCall(\n server,\n \"get-page\",\n {\n title: \"Get a styleguide page\",\n description:\n \"Fetch guidance from a specific design system page, including usage notes, recommendations, and supporting context.\\n\\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\\n\\n*If images from the page are needed, call `get-page-images` afterwards with the same page ID to retrieve them as base64-encoded content.*\",\n inputSchema: {\n pageId: z\n .number()\n .int()\n .describe(\n \"Identifies the page containing relevant guidance. Use `list-pages` to locate it. Important: page IDs differ between releases — if using a `releaseId`, call `list-pages` with the same `releaseId` first to get the correct page ID.\",\n ),\n releaseId: z\n .number()\n .int()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Use `list-releases` to discover available releases. When provided, you must also use the page ID from `list-pages` called with this same release ID.\",\n )\n .optional(),\n },\n annotations: {\n title: \"Get a styleguide page\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ pageId, releaseId }, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const page = await getPage(\n credentials,\n pageId,\n { releaseId },\n clientUserAgent,\n );\n\n if (!page) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Could not find the page. Verify the page ID by calling \\`list-pages\\`${releaseId ? ` with releaseId ${releaseId}` : \"\"}.`,\n },\n ],\n };\n }\n\n const textContent = formatPageAsMarkdown(page);\n\n return {\n content: [\n {\n type: \"text\",\n text: textContent,\n mimeType: \"text/markdown\",\n },\n ],\n };\n },\n );\n}\n\nexport function registerGetPageImagesTool(\n server: McpServer,\n _context: ServerContext,\n) {\n registerTrackedToolCall(\n server,\n \"get-page-images\",\n {\n title: \"Get images from a styleguide page\",\n description:\n \"Fetch all images from a specific design system page as base64-encoded content.\\n\\n*Call this after `get-page` with the same page ID if images are needed for the task — for example, when referencing visual examples, screenshots, or diagrams from the page.*\",\n inputSchema: {\n pageId: z\n .number()\n .int()\n .describe(\n \"The page to fetch images from. Use the same page ID as a previous `get-page` call. Page IDs differ between releases — ensure the ID matches the release.\",\n ),\n releaseId: z\n .number()\n .int()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Should match the release ID used with `get-page`.\",\n )\n .optional(),\n },\n annotations: {\n title: \"Get images from a styleguide page\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ pageId, releaseId }, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const page = await getPage(\n credentials,\n pageId,\n { releaseId },\n clientUserAgent,\n );\n\n if (!page) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Could not find the page. Verify the page ID by calling \\`list-pages\\`${releaseId ? ` with releaseId ${releaseId}` : \"\"}.`,\n },\n ],\n };\n }\n\n const textContent = formatPageAsMarkdown(page);\n const images = await extractImageUrlsFromPage(textContent);\n\n if (images.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"No images found on this page.\",\n },\n ],\n };\n }\n\n return {\n content: images,\n };\n },\n );\n}\n\nexport function registerSearchPagesTool(\n server: McpServer,\n context: ServerContext,\n) {\n if (context.features[\"SKI_2466_bedrock_indexing\"] !== true) {\n return;\n }\n\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"search-pages\",\n {\n title: \"Search pages in a styleguide\",\n description: \"Search for pages in a styleguide by a search term\",\n inputSchema: singleStyleguideMode\n ? {\n releaseId: z.number().int().min(1).optional(),\n searchTerm: z.string(),\n responseFormat: z.enum([\"markdown\", \"json\"]).default(\"json\"),\n }\n : {\n styleguideId: z.number().int().min(1),\n releaseId: z.number().int().min(1).optional(),\n searchTerm: z.string(),\n responseFormat: z.enum([\"markdown\", \"json\"]).default(\"json\"),\n },\n annotations: {\n title: \"Search pages in a styleguide\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const { searchTerm, releaseId, responseFormat } = args as {\n searchTerm: string;\n releaseId?: number;\n responseFormat: \"markdown\" | \"json\";\n };\n const styleguideId =\n context.connectionMode === \"remote_single_styleguide\"\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"Could not determine which styleguide to search.\",\n },\n ],\n };\n }\n\n if (\n credentials.type === \"jwt\" &&\n credentials.styleguideId !== styleguideId\n ) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"You do not have access to this styleguide\",\n },\n ],\n };\n }\n\n const results = await searchPages(\n credentials,\n styleguideId,\n searchTerm,\n releaseId,\n clientUserAgent,\n );\n\n if (results.length === 0) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"No pages match that search term, try something else.\",\n },\n ],\n };\n }\n\n if (responseFormat === \"markdown\") {\n return {\n content: [\n {\n type: \"text\",\n text: formatPageListItemsAsMarkdown(results),\n mimeType: \"text/markdown\",\n },\n ],\n };\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(results, null, 2),\n mimeType: \"application/json\",\n },\n ],\n };\n },\n );\n}\n"],"names":[],"mappings":"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","debug_id":"694bee8d-7ded-5054-9a83-2310df4ae0e6"}
{"version":3,"file":"page.js","sources":["tools/page.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Page Tools\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport z from \"zod\";\n\nimport { getPage, searchPages } from \"../api/page.js\";\nimport {\n formatPageAsMarkdown,\n formatPageListItemsAsMarkdown,\n extractImageUrlsFromPage,\n extractPageImageResourceLinks,\n extractPageAttachmentResourceLinks,\n pageHasAnnotations,\n} from \"../common/formatters/page.js\";\nimport { getCredentials } from \"../common/credentials.js\";\nimport { registerTrackedToolCall } from \"../logging.js\";\nimport { ServerContext } from \"../types/server.js\";\n\nexport function registerGetPageTool(server: McpServer, context: ServerContext) {\n const imageResourcesEnabled = context.features[\"OAK-37_mcp_image_resources\"];\n\n registerTrackedToolCall(\n server,\n \"get-page\",\n {\n title: \"Get a styleguide page\",\n description: imageResourcesEnabled\n ? \"Fetch guidance from a specific design system page, including usage notes, recommendations, supporting context, and any file attachments.\\n\\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\\n\\n*The response may include embedded image resource URIs (`zeroheight://image/...`) — use these to fetch individual images as needed. Only use `get-page-images` if you need every image from the page at once. File attachments are emitted as resource links pointing to their direct download URL.*\"\n : \"Fetch guidance from a specific design system page, including usage notes, recommendations, supporting context, and any file attachments.\\n\\n*Particularly helpful ahead of UI generation to increase the likelihood that outputs reflect the intent of the design system.*\\n\\n*If images from the page are needed, call `get-page-images` afterwards with the same page ID to retrieve them as base64-encoded content. Non-image attachments are linked inline in the page content and can be shared with the user by URL.*\",\n inputSchema: {\n pageId: z\n .number()\n .int()\n .describe(\n \"Identifies the page containing relevant guidance. Use `list-pages` to locate it. Important: page IDs differ between releases — if using a `releaseId`, call `list-pages` with the same `releaseId` first to get the correct page ID.\",\n ),\n releaseId: z\n .number()\n .int()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Use `list-releases` to discover available releases. When provided, you must also use the page ID from `list-pages` called with this same release ID.\",\n )\n .optional(),\n },\n annotations: {\n title: \"Get a styleguide page\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ pageId, releaseId }, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const page = await getPage(\n credentials,\n pageId,\n { releaseId },\n clientUserAgent,\n );\n\n if (!page) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Could not find the page. Verify the page ID by calling \\`list-pages\\`${releaseId ? ` with releaseId ${releaseId}` : \"\"}.`,\n },\n ],\n };\n }\n\n const textContent = formatPageAsMarkdown(page);\n const resourceLinks = context.features[\"OAK-37_mcp_image_resources\"]\n ? [\n ...extractPageImageResourceLinks(textContent),\n ...extractPageAttachmentResourceLinks(textContent),\n ]\n : [];\n\n const annotatedText = pageHasAnnotations(textContent)\n ? `${textContent}\\n\\n*Note on annotations: marker positions are coordinate metadata only. Without fetching the corresponding image, you can list the labels but cannot determine what visual element each marker points at — be explicit about that limit rather than inferring from coordinates.*`\n : textContent;\n\n return {\n content: [\n {\n type: \"text\",\n text: annotatedText,\n mimeType: \"text/markdown\",\n },\n ...resourceLinks,\n ],\n };\n },\n );\n}\n\nexport function registerGetPageImagesTool(\n server: McpServer,\n context: ServerContext,\n) {\n const imageResourcesEnabled = context.features[\"OAK-37_mcp_image_resources\"];\n\n registerTrackedToolCall(\n server,\n \"get-page-images\",\n {\n title: \"Get images from a styleguide page\",\n description: imageResourcesEnabled\n ? \"Fetch all images from a specific design system page as base64-encoded content. Includes both inline page images and image-typed file attachments.\\n\\n*Prefer using the image resource URIs embedded in `get-page` responses to fetch only the images you need. Use this tool only when you need every image from the page at once.*\"\n : \"Fetch all images from a specific design system page as base64-encoded content. Includes both inline page images and image-typed file attachments.\\n\\n*Call this after `get-page` with the same page ID if images are needed for the task — for example, when referencing visual examples, screenshots, or diagrams from the page.*\",\n inputSchema: {\n pageId: z\n .number()\n .int()\n .describe(\n \"The page to fetch images from. Use the same page ID as a previous `get-page` call. Page IDs differ between releases — ensure the ID matches the release.\",\n ),\n releaseId: z\n .number()\n .int()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Should match the release ID used with `get-page`.\",\n )\n .optional(),\n },\n annotations: {\n title: \"Get images from a styleguide page\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async ({ pageId, releaseId }, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const page = await getPage(\n credentials,\n pageId,\n { releaseId },\n clientUserAgent,\n );\n if (!page) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Could not find the page. Verify the page ID by calling \\`list-pages\\`${releaseId ? ` with releaseId ${releaseId}` : \"\"}.`,\n },\n ],\n };\n }\n const textContent = formatPageAsMarkdown(page);\n const images = await extractImageUrlsFromPage(textContent);\n if (images.length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"No images found on this page.\",\n },\n ],\n };\n }\n return {\n content: images,\n };\n },\n );\n}\n\nexport function registerSearchPagesTool(\n server: McpServer,\n context: ServerContext,\n) {\n if (context.features[\"SKI_2466_bedrock_indexing\"] !== true) {\n return;\n }\n\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"search-pages\",\n {\n title: \"Search pages in a styleguide\",\n description: \"Search for pages in a styleguide by a search term\",\n inputSchema: singleStyleguideMode\n ? {\n releaseId: z.number().int().min(1).optional(),\n searchTerm: z.string(),\n responseFormat: z.enum([\"markdown\", \"json\"]).default(\"json\"),\n }\n : {\n styleguideId: z.number().int().min(1),\n releaseId: z.number().int().min(1).optional(),\n searchTerm: z.string(),\n responseFormat: z.enum([\"markdown\", \"json\"]).default(\"json\"),\n },\n annotations: {\n title: \"Search pages in a styleguide\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const { searchTerm, releaseId, responseFormat } = args as {\n searchTerm: string;\n releaseId?: number;\n responseFormat: \"markdown\" | \"json\";\n };\n const styleguideId =\n context.connectionMode === \"remote_single_styleguide\"\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"Could not determine which styleguide to search.\",\n },\n ],\n };\n }\n\n if (\n credentials.type === \"jwt\" &&\n credentials.styleguideId !== styleguideId\n ) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"You do not have access to this styleguide\",\n },\n ],\n };\n }\n\n const results = await searchPages(\n credentials,\n styleguideId,\n searchTerm,\n releaseId,\n clientUserAgent,\n );\n\n if (results.length === 0) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"No pages match that search term, try something else.\",\n },\n ],\n };\n }\n\n if (responseFormat === \"markdown\") {\n return {\n content: [\n {\n type: \"text\",\n text: formatPageListItemsAsMarkdown(results),\n mimeType: \"text/markdown\",\n },\n ],\n };\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(results, null, 2),\n mimeType: \"application/json\",\n },\n ],\n };\n },\n );\n}\n"],"names":[],"mappings":"AAAA;;GAEG;;;AAGH,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,wBAAwB,EACxB,6BAA6B,EAC7B,kCAAkC,EAClC,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,OAAsB;IAC3E,MAAM,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAE7E,uBAAuB,CACrB,MAAM,EACN,UAAU,EACV;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EAAE,qBAAqB;YAChC,CAAC,CAAC,ojBAAojB;YACtjB,CAAC,CAAC,6fAA6f;QACjgB,WAAW,EAAE;YACX,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,CACP,sOAAsO,CACvO;YACH,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,CACP,4OAA4O,CAC7O;iBACA,QAAQ,EAAE;SACd;QACD,WAAW,EAAE;YACX,KAAK,EAAE,uBAAuB;YAC9B,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QAC7D,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,WAAW,EACX,MAAM,EACN,EAAE,SAAS,EAAE,EACb,eAAe,CAChB,CAAC;QAEF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wEAAwE,SAAS,CAAC,CAAC,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;qBACjI;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC;YAClE,CAAC,CAAC;gBACE,GAAG,6BAA6B,CAAC,WAAW,CAAC;gBAC7C,GAAG,kCAAkC,CAAC,WAAW,CAAC;aACnD;YACH,CAAC,CAAC,EAAE,CAAC;QAEP,MAAM,aAAa,GAAG,kBAAkB,CAAC,WAAW,CAAC;YACnD,CAAC,CAAC,GAAG,WAAW,mRAAmR;YACnS,CAAC,CAAC,WAAW,CAAC;QAEhB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,aAAa;oBACnB,QAAQ,EAAE,eAAe;iBAC1B;gBACD,GAAG,aAAa;aACjB;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IAE7E,uBAAuB,CACrB,MAAM,EACN,iBAAiB,EACjB;QACE,KAAK,EAAE,mCAAmC;QAC1C,WAAW,EAAE,qBAAqB;YAChC,CAAC,CAAC,qUAAqU;YACvU,CAAC,CAAC,oUAAoU;QACxU,WAAW,EAAE;YACX,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,CACP,0JAA0J,CAC3J;YACH,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,CACP,yIAAyI,CAC1I;iBACA,QAAQ,EAAE;SACd;QACD,WAAW,EAAE;YACX,KAAK,EAAE,mCAAmC;YAC1C,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QAC7D,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,WAAW,EACX,MAAM,EACN,EAAE,SAAS,EAAE,EACb,eAAe,CAChB,CAAC;QACF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wEAAwE,SAAS,CAAC,CAAC,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;qBACjI;iBACF;aACF,CAAC;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,+BAA+B;qBACtC;iBACF;aACF,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,MAAM;SAChB,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,OAAsB;IAEtB,IAAI,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3D,OAAO;IACT,CAAC;IAED,MAAM,oBAAoB,GACxB,OAAO,CAAC,cAAc,KAAK,0BAA0B,CAAC;IAExD,uBAAuB,CACrB,MAAM,EACN,cAAc,EACd;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EAAE,mDAAmD;QAChE,WAAW,EAAE,oBAAoB;YAC/B,CAAC,CAAC;gBACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;gBAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;gBACtB,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;aAC7D;YACH,CAAC,CAAC;gBACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;gBAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;gBACtB,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;aAC7D;QACL,WAAW,EAAE;YACX,KAAK,EAAE,8BAA8B;YACrC,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QAC5C,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,IAIjD,CAAC;QACF,MAAM,YAAY,GAChB,OAAO,CAAC,cAAc,KAAK,0BAA0B;YACnD,CAAC,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAE,IAAiC,CAAC,YAAY,CAAC;QAEtD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,iDAAiD;qBACxD;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IACE,WAAW,CAAC,IAAI,KAAK,KAAK;YAC1B,WAAW,CAAC,YAAY,KAAK,YAAY,EACzC,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,2CAA2C;qBAClD;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAC/B,WAAW,EACX,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,CAChB,CAAC;QAEF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,sDAAsD;qBAC7D;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;YAClC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,6BAA6B,CAAC,OAAO,CAAC;wBAC5C,QAAQ,EAAE,eAAe;qBAC1B;iBACF;aACF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;oBACtC,QAAQ,EAAE,kBAAkB;iBAC7B;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC","debug_id":"c75dd78d-13de-5f8b-b764-1ba34508622c"}

@@ -5,6 +5,6 @@ /**

!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1f896b4f-8093-5778-8702-a6f5a6ba909b")}catch(e){}}();
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9d2fcdf8-0f09-502a-8acc-ddd745ec0d39")}catch(e){}}();
import z from "zod";
import { ApiError } from "../api/errors.js";
import { getStyleguideTree, listStyleguides, listStyleguideVersions } from "../api/styleguide.js";
import { getStyleguideTree, listStyleguides, listStyleguideVersions, } from "../api/styleguide.js";
import { formatStyleguideListAsJson, formatTreeAsJson, } from "../common/formatters/styleguide.js";

@@ -72,8 +72,17 @@ import { getCredentials } from "../common/credentials.js";

.array(z.object({
id: z.number().describe("The unique identifier for the release. Pass as `releaseId` to other tools when the user requests a specific release."),
id: z
.number()
.describe("The unique identifier for the release. Pass as `releaseId` to other tools when the user requests a specific release."),
name: z.string().describe("The name of the release."),
default: z.boolean().describe("Whether this is the default release shown to viewers."),
working_version: z.boolean().describe("Whether this is the current work-in-progress release."),
default: z
.boolean()
.describe("Whether this is the default release shown to viewers."),
working_version: z
.boolean()
.describe("Whether this is the current work-in-progress release."),
created_at: z.string().describe("When the release was created."),
release_notes: z.string().nullable().describe("Release notes for this release."),
release_notes: z
.string()
.nullable()
.describe("Release notes for this release."),
}))

@@ -224,2 +233,2 @@ .describe("Available releases for the styleguide, newest first.");

//# sourceMappingURL=styleguide.js.map
//# debugId=1f896b4f-8093-5778-8702-a6f5a6ba909b
//# debugId=9d2fcdf8-0f09-502a-8acc-ddd745ec0d39

@@ -1,1 +0,1 @@

{"version":3,"file":"styleguide.js","sources":["tools/styleguide.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Styleguide Tools\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport z from \"zod\";\n\nimport { ApiError } from \"../api/errors.js\";\nimport { getStyleguideTree, listStyleguides, listStyleguideVersions } from \"../api/styleguide.js\";\nimport {\n formatStyleguideListAsJson,\n formatTreeAsJson,\n} from \"../common/formatters/styleguide.js\";\nimport { getCredentials } from \"../common/credentials.js\";\nimport { registerTrackedToolCall } from \"../logging.js\";\nimport { ServerContext } from \"../types/server.js\";\n\nexport function registerListStyleguidesTool(server: McpServer) {\n registerTrackedToolCall(\n server,\n \"list-styleguides\",\n {\n title: \"List styleguides\",\n description:\n \"Discover available design systems that provide documented guidance for components, patterns, and styles. Call this tool first. If multiple systems are available, confirm with the user which should be used.\\n\\n*Helpful to reference before generating UI so decisions can reflect established design approaches.*\",\n inputSchema: {},\n outputSchema: {\n styleguides: z\n .array(\n z.object({\n id: z\n .number()\n .describe(\"The unique identifier for the styleguide.\"),\n name: z.string().describe(\"The name of the styleguide.\"),\n }),\n )\n .describe(\"List of available design system styleguides.\"),\n },\n annotations: {\n title: \"List styleguides\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (_, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const styleguides = await listStyleguides(credentials, clientUserAgent);\n\n if (styleguides.length === 0) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"There are no accessible styleguides. Check your auth credentials and make sure you have at least one styleguide in zeroheight.\",\n },\n ],\n };\n }\n\n const structuredContent = formatStyleguideListAsJson(styleguides);\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n },\n );\n}\n\nconst pageNodeSchema: z.ZodType = z.lazy(() =>\n z.union([\n z.object({\n id: z\n .number()\n .describe(\"The page ID. Use with `get-page` to fetch its content.\"),\n url: z.string().describe(\"The URL of the page.\"),\n }),\n z.record(z.string(), pageNodeSchema),\n ]),\n);\n\nconst releasesSchema = z\n .array(\n z.object({\n id: z.number().describe(\"The unique identifier for the release. Pass as `releaseId` to other tools when the user requests a specific release.\"),\n name: z.string().describe(\"The name of the release.\"),\n default: z.boolean().describe(\"Whether this is the default release shown to viewers.\"),\n working_version: z.boolean().describe(\"Whether this is the current work-in-progress release.\"),\n created_at: z.string().describe(\"When the release was created.\"),\n release_notes: z.string().nullable().describe(\"Release notes for this release.\"),\n }),\n )\n .describe(\"Available releases for the styleguide, newest first.\");\n\nexport function registerListReleasesTool(server: McpServer, context: ServerContext) {\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"list-releases\",\n {\n title: \"List releases in a styleguide\",\n description:\n \"List available releases for a styleguide. Only call this when the user has explicitly asked about releases or wants content from a specific release. Do not use `releaseId` in other tools unless the user has requested a particular release — all tools default to the latest published content.\",\n inputSchema: {\n ...(singleStyleguideMode\n ? {}\n : {\n styleguideId: z\n .number()\n .int()\n .min(1)\n .describe(\n \"The design system to list releases for. Use `list-styleguides` to discover available systems.\",\n ),\n }),\n },\n outputSchema: {\n releases: releasesSchema,\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n try {\n const credentials = await getCredentials(authInfo);\n const styleguideId =\n singleStyleguideMode\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n throw new Error(\"Missing styleguideId\");\n }\n\n const versions = await listStyleguideVersions(credentials, styleguideId, clientUserAgent);\n const structuredContent = { releases: releasesSchema.parse(versions) };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n } catch (e) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: e instanceof ApiError\n ? e.message\n : \"Could not get releases for this styleguide.\",\n },\n ],\n };\n }\n },\n );\n}\n\nexport function registerListPagesTool(server: McpServer, context: ServerContext) {\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"list-pages\",\n {\n title: \"List pages in a styleguide\",\n description:\n singleStyleguideMode\n ? \"View the navigation hierarchy of the current design system — including categories, pages, and tabs — to better understand how guidance is organized.\\n\\n*Helpful when determining where to look for component or pattern documentation before generating UI.*\"\n : \"View the navigation hierarchy of a design system — including categories, pages, and tabs — to better understand how guidance is organized. Call this tool immediately after list-styleguides with the desired styleguide ID.\\n\\n*Helpful when determining where to look for component or pattern documentation before generating UI.*\",\n inputSchema: {\n ...(singleStyleguideMode\n ? {}\n : {\n styleguideId: z\n .number()\n .int()\n .min(1)\n .describe(\n \"The design system to reference. Use `list-styleguides` to discover available systems.\",\n ),\n }),\n releaseId: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Use `list-releases` to discover available releases.\",\n ),\n },\n outputSchema: {\n ...(singleStyleguideMode\n ? {\n styleguideName: z\n .string()\n .describe(\"The name of the styleguide.\"),\n }\n : {}),\n pages: z\n .record(z.string(), pageNodeSchema)\n .describe(\n \"A hierarchical navigation tree of the design system. Keys are category or page names. Page leaf nodes have { id, url } properties; category nodes contain further nested objects.\",\n ),\n },\n annotations: {\n title: \"List pages in a styleguide\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n const releaseId = (args as { releaseId?: number }).releaseId;\n try {\n const credentials = await getCredentials(authInfo);\n const styleguideId =\n context.connectionMode === \"remote_single_styleguide\"\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n throw new Error(\"Missing styleguideId\");\n }\n\n const tree = await getStyleguideTree(\n credentials,\n styleguideId,\n clientUserAgent,\n releaseId,\n );\n\n if (tree.length === 0) {\n throw new Error(\"Empty styleguide tree\");\n }\n\n const formattedTree = formatTreeAsJson(tree);\n const structuredContent = singleStyleguideMode\n ? { styleguideName: context.styleguideName, pages: formattedTree }\n : { pages: formattedTree };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n } catch {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"Could not get the navigation tree for this styleguide.\",\n },\n ],\n };\n }\n },\n );\n}\n"],"names":[],"mappings":"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","debug_id":"1f896b4f-8093-5778-8702-a6f5a6ba909b"}
{"version":3,"file":"styleguide.js","sources":["tools/styleguide.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Styleguide Tools\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport z from \"zod\";\n\nimport { ApiError } from \"../api/errors.js\";\nimport {\n getStyleguideTree,\n listStyleguides,\n listStyleguideVersions,\n} from \"../api/styleguide.js\";\nimport {\n formatStyleguideListAsJson,\n formatTreeAsJson,\n} from \"../common/formatters/styleguide.js\";\nimport { getCredentials } from \"../common/credentials.js\";\nimport { registerTrackedToolCall } from \"../logging.js\";\nimport { ServerContext } from \"../types/server.js\";\nimport { captureException } from \"../common/errors.js\";\n\nexport function registerListStyleguidesTool(server: McpServer) {\n registerTrackedToolCall(\n server,\n \"list-styleguides\",\n {\n title: \"List styleguides\",\n description:\n \"Discover available design systems that provide documented guidance for components, patterns, and styles. Call this tool first. If multiple systems are available, confirm with the user which should be used.\\n\\n*Helpful to reference before generating UI so decisions can reflect established design approaches.*\",\n inputSchema: {},\n outputSchema: {\n styleguides: z\n .array(\n z.object({\n id: z\n .number()\n .describe(\"The unique identifier for the styleguide.\"),\n name: z.string().describe(\"The name of the styleguide.\"),\n }),\n )\n .describe(\"List of available design system styleguides.\"),\n },\n annotations: {\n title: \"List styleguides\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (_, { authInfo }, clientUserAgent) => {\n const credentials = await getCredentials(authInfo);\n const styleguides = await listStyleguides(credentials, clientUserAgent);\n\n if (styleguides.length === 0) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"There are no accessible styleguides. Check your auth credentials and make sure you have at least one styleguide in zeroheight.\",\n },\n ],\n };\n }\n\n const structuredContent = formatStyleguideListAsJson(styleguides);\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n },\n );\n}\n\nconst pageNodeSchema: z.ZodType = z.lazy(() =>\n z.union([\n z.object({\n id: z\n .number()\n .describe(\"The page ID. Use with `get-page` to fetch its content.\"),\n url: z.string().describe(\"The URL of the page.\"),\n }),\n z.record(z.string(), pageNodeSchema),\n ]),\n);\n\nconst releasesSchema = z\n .array(\n z.object({\n id: z\n .number()\n .describe(\n \"The unique identifier for the release. Pass as `releaseId` to other tools when the user requests a specific release.\",\n ),\n name: z.string().describe(\"The name of the release.\"),\n default: z\n .boolean()\n .describe(\"Whether this is the default release shown to viewers.\"),\n working_version: z\n .boolean()\n .describe(\"Whether this is the current work-in-progress release.\"),\n created_at: z.string().describe(\"When the release was created.\"),\n release_notes: z\n .string()\n .nullable()\n .describe(\"Release notes for this release.\"),\n }),\n )\n .describe(\"Available releases for the styleguide, newest first.\");\n\nexport function registerListReleasesTool(\n server: McpServer,\n context: ServerContext,\n) {\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"list-releases\",\n {\n title: \"List releases in a styleguide\",\n description:\n \"List available releases for a styleguide. Only call this when the user has explicitly asked about releases or wants content from a specific release. Do not use `releaseId` in other tools unless the user has requested a particular release — all tools default to the latest published content.\",\n inputSchema: {\n ...(singleStyleguideMode\n ? {}\n : {\n styleguideId: z\n .number()\n .int()\n .min(1)\n .describe(\n \"The design system to list releases for. Use `list-styleguides` to discover available systems.\",\n ),\n }),\n },\n outputSchema: {\n releases: releasesSchema,\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n try {\n const credentials = await getCredentials(authInfo);\n const styleguideId = singleStyleguideMode\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n throw new Error(\"Missing styleguideId\");\n }\n\n const versions = await listStyleguideVersions(\n credentials,\n styleguideId,\n clientUserAgent,\n );\n const structuredContent = { releases: releasesSchema.parse(versions) };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n } catch (e) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text:\n e instanceof ApiError\n ? e.message\n : \"Could not get releases for this styleguide.\",\n },\n ],\n };\n }\n },\n );\n}\n\nexport function registerListPagesTool(\n server: McpServer,\n context: ServerContext,\n) {\n const singleStyleguideMode =\n context.connectionMode === \"remote_single_styleguide\";\n\n registerTrackedToolCall(\n server,\n \"list-pages\",\n {\n title: \"List pages in a styleguide\",\n description: singleStyleguideMode\n ? \"View the navigation hierarchy of the current design system — including categories, pages, and tabs — to better understand how guidance is organized.\\n\\n*Helpful when determining where to look for component or pattern documentation before generating UI.*\"\n : \"View the navigation hierarchy of a design system — including categories, pages, and tabs — to better understand how guidance is organized. Call this tool immediately after list-styleguides with the desired styleguide ID.\\n\\n*Helpful when determining where to look for component or pattern documentation before generating UI.*\",\n inputSchema: {\n ...(singleStyleguideMode\n ? {}\n : {\n styleguideId: z\n .number()\n .int()\n .min(1)\n .describe(\n \"The design system to reference. Use `list-styleguides` to discover available systems.\",\n ),\n }),\n releaseId: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n \"Optional. Do not provide unless the user has explicitly asked for a specific release. Use `list-releases` to discover available releases.\",\n ),\n },\n outputSchema: {\n ...(singleStyleguideMode\n ? {\n styleguideName: z\n .string()\n .describe(\"The name of the styleguide.\"),\n }\n : {}),\n pages: z\n .record(z.string(), pageNodeSchema)\n .describe(\n \"A hierarchical navigation tree of the design system. Keys are category or page names. Page leaf nodes have { id, url } properties; category nodes contain further nested objects.\",\n ),\n },\n annotations: {\n title: \"List pages in a styleguide\",\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async (args, { authInfo }, clientUserAgent) => {\n const releaseId = (args as { releaseId?: number }).releaseId;\n try {\n const credentials = await getCredentials(authInfo);\n const styleguideId =\n context.connectionMode === \"remote_single_styleguide\"\n ? context.styleguideId\n : (args as { styleguideId: number }).styleguideId;\n\n if (typeof styleguideId !== \"number\") {\n throw new Error(\"Missing styleguideId\");\n }\n\n const tree = await getStyleguideTree(\n credentials,\n styleguideId,\n clientUserAgent,\n releaseId,\n );\n\n if (tree.length === 0) {\n throw new Error(\"Empty styleguide tree\");\n }\n\n const formattedTree = formatTreeAsJson(tree);\n const structuredContent = singleStyleguideMode\n ? { styleguideName: context.styleguideName, pages: formattedTree }\n : { pages: formattedTree };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(structuredContent, null, 2),\n },\n ],\n structuredContent,\n };\n } catch {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: \"Could not get the navigation tree for this styleguide.\",\n },\n ],\n };\n }\n },\n );\n}\n"],"names":[],"mappings":"AAAA;;GAEG;;;AAGH,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAIxD,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,uBAAuB,CACrB,MAAM,EACN,kBAAkB,EAClB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,sTAAsT;QACxT,WAAW,EAAE,EAAE;QACf,YAAY,EAAE;YACZ,WAAW,EAAE,CAAC;iBACX,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;gBACP,EAAE,EAAE,CAAC;qBACF,MAAM,EAAE;qBACR,QAAQ,CAAC,2CAA2C,CAAC;gBACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;aACzD,CAAC,CACH;iBACA,QAAQ,CAAC,8CAA8C,CAAC;SAC5D;QACD,WAAW,EAAE;YACX,KAAK,EAAE,kBAAkB;YACzB,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QACzC,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;QAExE,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,gIAAgI;qBACvI;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,WAAW,CAAC,CAAC;QAElE,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;iBACjD;aACF;YACD,iBAAiB;SAClB,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAc,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAC5C,CAAC,CAAC,KAAK,CAAC;IACN,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,CAAC,wDAAwD,CAAC;QACrE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACjD,CAAC;IACF,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC;CACrC,CAAC,CACH,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC;KACrB,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;IACP,EAAE,EAAE,CAAC;SACF,MAAM,EAAE;SACR,QAAQ,CACP,sHAAsH,CACvH;IACH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IACrD,OAAO,EAAE,CAAC;SACP,OAAO,EAAE;SACT,QAAQ,CAAC,uDAAuD,CAAC;IACpE,eAAe,EAAE,CAAC;SACf,OAAO,EAAE;SACT,QAAQ,CAAC,uDAAuD,CAAC;IACpE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;IAChE,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,iCAAiC,CAAC;CAC/C,CAAC,CACH;KACA,QAAQ,CAAC,sDAAsD,CAAC,CAAC;AAEpE,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,oBAAoB,GACxB,OAAO,CAAC,cAAc,KAAK,0BAA0B,CAAC;IAExD,uBAAuB,CACrB,MAAM,EACN,eAAe,EACf;QACE,KAAK,EAAE,+BAA+B;QACtC,WAAW,EACT,oSAAoS;QACtS,WAAW,EAAE;YACX,GAAG,CAAC,oBAAoB;gBACtB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,YAAY,EAAE,CAAC;yBACZ,MAAM,EAAE;yBACR,GAAG,EAAE;yBACL,GAAG,CAAC,CAAC,CAAC;yBACN,QAAQ,CACP,+FAA+F,CAChG;iBACJ,CAAC;SACP;QACD,YAAY,EAAE;YACZ,QAAQ,EAAE,cAAc;SACzB;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;SACnB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QAC5C,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,oBAAoB;gBACvC,CAAC,CAAC,OAAO,CAAC,YAAY;gBACtB,CAAC,CAAE,IAAiC,CAAC,YAAY,CAAC;YAEpD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAC3C,WAAW,EACX,YAAY,EACZ,eAAe,CAChB,CAAC;YACF,MAAM,iBAAiB,GAAG,EAAE,QAAQ,EAAE,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAEvE,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;qBACjD;iBACF;gBACD,iBAAiB;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,CAAC,YAAY,QAAQ;4BACnB,CAAC,CAAC,CAAC,CAAC,OAAO;4BACX,CAAC,CAAC,6CAA6C;qBACpD;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,MAAiB,EACjB,OAAsB;IAEtB,MAAM,oBAAoB,GACxB,OAAO,CAAC,cAAc,KAAK,0BAA0B,CAAC;IAExD,uBAAuB,CACrB,MAAM,EACN,YAAY,EACZ;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE,oBAAoB;YAC/B,CAAC,CAAC,+PAA+P;YACjQ,CAAC,CAAC,uUAAuU;QAC3U,WAAW,EAAE;YACX,GAAG,CAAC,oBAAoB;gBACtB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,YAAY,EAAE,CAAC;yBACZ,MAAM,EAAE;yBACR,GAAG,EAAE;yBACL,GAAG,CAAC,CAAC,CAAC;yBACN,QAAQ,CACP,uFAAuF,CACxF;iBACJ,CAAC;YACN,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,EAAE;iBACV,QAAQ,CACP,2IAA2I,CAC5I;SACJ;QACD,YAAY,EAAE;YACZ,GAAG,CAAC,oBAAoB;gBACtB,CAAC,CAAC;oBACE,cAAc,EAAE,CAAC;yBACd,MAAM,EAAE;yBACR,QAAQ,CAAC,6BAA6B,CAAC;iBAC3C;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,KAAK,EAAE,CAAC;iBACL,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC;iBAClC,QAAQ,CACP,mLAAmL,CACpL;SACJ;QACD,WAAW,EAAE;YACX,KAAK,EAAE,4BAA4B;YACnC,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,EAAE;QAC5C,MAAM,SAAS,GAAI,IAA+B,CAAC,SAAS,CAAC;QAC7D,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,YAAY,GAChB,OAAO,CAAC,cAAc,KAAK,0BAA0B;gBACnD,CAAC,CAAC,OAAO,CAAC,YAAY;gBACtB,CAAC,CAAE,IAAiC,CAAC,YAAY,CAAC;YAEtD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YAC1C,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAClC,WAAW,EACX,YAAY,EACZ,eAAe,EACf,SAAS,CACV,CAAC;YAEF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YAED,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,iBAAiB,GAAG,oBAAoB;gBAC5C,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE;gBAClE,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;YAE7B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;qBACjD;iBACF;gBACD,iBAAiB;aAClB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wDAAwD;qBAC/D;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC","debug_id":"9d2fcdf8-0f09-502a-8acc-ddd745ec0d39"}
{
"name": "@zeroheight/mcp-server",
"version": "2.7.0",
"version": "2.8.0",
"description": "MCP server for zeroheight",

@@ -12,5 +12,6 @@ "mcpName": "com.zeroheight/zeroheight",

"build:local": "tsc -p tsconfig.stdio.json && chmod 755 dist/stdio.js && npm run sentry:sourcemaps:local",
"dev:local": "tsc -p tsconfig.stdio.json && chmod 755 dist/stdio.js",
"dev:local": "tsx --watch --env-file=local.env src/stdio.ts",
"start:local": "node --env-file=local.env dist/stdio.js",
"build:remote": "tsc && chmod 755 dist/http.js",
"dev:remote": "tsx --watch --env-file=remote.env src/http.ts",
"dev:remote:build": "tsc && chmod 755 dist/http.js",

@@ -44,2 +45,4 @@ "dev:remote:start": "node --env-file=remote.env dist/http.js",

"@amplitude/analytics-node": "^1.5.29",
"@hono/mcp": "^0.2.5",
"@hono/node-server": "^1.19.13",
"@modelcontextprotocol/sdk": "^1.17.1",

@@ -50,4 +53,4 @@ "@sentry/aws-serverless": "^10.17.0",

"culori": "^4.0.2",
"express": "^5.1.0",
"file-type": "^21.3.0",
"hono": "^4.12.12",
"known-css-properties": "^0.37.0",

@@ -58,3 +61,3 @@ "postcss": "^8.5.6",

"typescript": "^5.9.2",
"zod": "^3.25.76"
"zod": "^4.3.6"
},

@@ -64,7 +67,7 @@ "devDependencies": {

"@types/culori": "^4.0.1",
"@types/express": "^5.0.3",
"@types/node": "^24.2.0",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"prettier": "^3.6.2"
"prettier": "^3.6.2",
"tsx": "^4.19.0"
},

@@ -71,0 +74,0 @@ "lint-staged": {