From e2f55db5c83caac88c9ea5f95567e30c5b0e6d30 Mon Sep 17 00:00:00 2001 From: MasonChow Date: Sat, 27 Sep 2025 01:15:16 +0800 Subject: [PATCH 1/4] feat: Enhance README with npm package usage and build instructions - Added section for using the package as an npm module in custom MCP services. - Included minimal TypeScript example for integration. - Updated Node.js version requirement to 20+. - Documented build artifacts and TypeScript declaration files. build: Improve build script and TypeScript configuration - Added error handling and cleanup in build.sh. - Configured TypeScript to generate declaration files and bundled them. - Created rollup configuration for bundling TypeScript declarations. refactor: Update package.json for module exports and types - Set main, module, and types fields to point to built files. - Added exports field for better module resolution. refactor: Implement tools registration for MCP server - Created tools.ts for registering MCP tools. - Refactored server.ts to use the new tools registration. - Added detailed documentation for the parse_stack tool. fix: Enhance parser validation and error handling - Improved type validation for raw tokens from WebAssembly. - Added type guards and refined error messages in the parser. chore: Remove unused guide.xml file and update tsconfig - Deleted guide.xml as it was no longer needed. - Updated tsconfig to include types directory for better type resolution. test: Add TypeScript declaration file for source_map_parser_node - Created source_map_parser_node.d.ts for better type support in the project. style: Update Vite configuration for library entry points - Modified Vite config to specify multiple entry points for better modularity. --- README.md | 77 ++- README.zh-CN.md | 76 ++- build.sh | 19 +- package.json | 13 +- rollup.config.dts.mjs | 10 + src/cachingFetch.ts | 9 +- src/external/docs/guide.xml | 645 ------------------ src/index.ts | 3 + src/parser.ts | 62 +- src/server.ts | 136 ++-- src/tools.ts | 103 +++ tsconfig.build.json | 13 + tsconfig.json | 1 + .../source_map_parser_node.d.ts | 0 vite.config.mjs | 5 +- 15 files changed, 410 insertions(+), 762 deletions(-) create mode 100644 rollup.config.dts.mjs delete mode 100644 src/external/docs/guide.xml create mode 100644 src/index.ts create mode 100644 src/tools.ts create mode 100644 tsconfig.build.json rename {src/types => types}/source_map_parser_node.d.ts (100%) diff --git a/README.md b/README.md index 54e07ec..103a4f3 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This project implements a WebAssembly-based Source Map parser that can map JavaS ## MCP Integration -> Note: Requires Node.js 18+ support +> Note: Requires Node.js 20+ support Option 1: Run directly with NPX @@ -35,6 +35,77 @@ Download the corresponding version of the build artifacts from the [GitHub Relea node dist/main.es.js ``` +### Use as an npm package (bring your own MCP server) + +You can embed the tools into your own MCP server process and customize behavior. + +Install: + +```bash +npm install source-map-parser-mcp +``` + +Minimal server (TypeScript): + +```ts +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { + registerTools, + Parser, + type ToolsRegistryOptions, +} from 'source-map-parser-mcp'; + +const server = new McpServer( + { name: 'your-org.source-map-parser', version: '0.0.1' }, + { capabilities: { tools: {} } } +); + +// Optional: control context lines via env +const options: ToolsRegistryOptions = { + contextOffsetLine: + Number(process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE) || 1, +}; + +registerTools(server, options); + +// Start as stdio server +const transport = new StdioServerTransport(); +await server.connect(transport); + +// If you need programmatic parsing without MCP: +const parser = new Parser({ contextOffsetLine: 1 }); +// await parser.parseStack({ line: 10, column: 5, sourceMapUrl: 'https://...' }); +// await parser.batchParseStack([{ line, column, sourceMapUrl }]); +``` + +### Build and Type Declarations + +This project ships both ESM and CJS builds and a single bundled TypeScript declaration file. + +- Build outputs: + - ESM: `dist/index.es.js` + - CJS: `dist/index.cjs.js` + - CLI entry: `dist/main.es.js` + - Types: `dist/index.d.ts` (single bundled d.ts) + +Quick build locally: + +```bash +npm install +npm run build +``` + +Using types in your project: + +```ts +import { + Parser, + registerTools, + type ToolsRegistryOptions, +} from 'source-map-parser-mcp'; +``` + ### Runtime Parameter Configuration > System runtime parameters can be flexibly configured through environment variables to meet the needs of different scenarios @@ -156,8 +227,8 @@ If the tool returns the following error message, please troubleshoot as follows: > parser init error: WebAssembly.instantiate(): invalid value type 'externref', enable with --experimental-wasm-reftypes @+86 -1. **Check Node.js Version**: Ensure Node.js version is 18 or higher. If it's lower than 18, please upgrade Node.js. -2. **Enable Experimental Flag**: If Node.js version is 18+ but you still encounter issues, use the following command to start the tool: +1. **Check Node.js Version**: Ensure Node.js version is 20 or higher. If it's lower than 20, please upgrade Node.js. +2. **Enable Experimental Flag**: If Node.js version is 20+ but you still encounter issues, use the following command to start the tool: ```bash npx --node-arg=--experimental-wasm-reftypes -y source-map-parser-mcp@latest ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index f9724fe..0129438 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,3 +1,46 @@ +### 作为 npm 包在自定义 MCP 服务中使用 + +你可以在自己的 MCP 进程中嵌入本项目提供的工具,并按需定制行为。 +安装: + +```bash +npm install source-map-parser-mcp +``` + +最小示例(TypeScript): + +```ts +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { + registerTools, + Parser, + type ToolsRegistryOptions, +} from 'source-map-parser-mcp'; + +const server = new McpServer( + { name: 'your-org.source-map-parser', version: '0.0.1' }, + { capabilities: { tools: {} } } +); + +// 可选:通过环境变量控制上下文行数 +const options: ToolsRegistryOptions = { + contextOffsetLine: + Number(process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE) || 1, +}; + +registerTools(server, options); + +// 以 stdio 方式启动 +const transport = new StdioServerTransport(); +await server.connect(transport); + +// 如果不通过 MCP,也可以在代码中直接调用解析: +const parser = new Parser({ contextOffsetLine: 1 }); +// await parser.parseStack({ line: 10, column: 5, sourceMapUrl: 'https://...' }); +// await parser.batchParseStack([{ line, column, sourceMapUrl }]); +``` + # Source Map 解析器 🌐 **语言**: [English](README.md) | [简体中文](README.zh-CN.md) @@ -17,7 +60,7 @@ ## MCP 串接 -> 注意: 需要 Node.js 18+ 版本支持 +> 注意: 需要 Node.js 20+ 版本支持 方式一:NPX 直接运行 @@ -33,6 +76,33 @@ npx -y source-map-parser-mcp@latest node dist/main.es.js ``` +### 构建与类型声明 + +本项目同时提供 ESM 与 CJS 构建,并打包为单一的 TypeScript 声明文件: + +- 构建产物: + - ESM: `dist/index.es.js` + - CJS: `dist/index.cjs.js` + - CLI 入口: `dist/main.es.js` + - 类型声明: `dist/index.d.ts`(单文件打包) + +本地快速构建: + +```bash +npm install +npm run build +``` + +在你的项目中使用类型: + +```ts +import { + Parser, + registerTools, + type ToolsRegistryOptions, +} from 'source-map-parser-mcp'; +``` + ### 运行参数配置 > 通过环境变量可灵活配置系统运行参数,满足不同场景需求 @@ -153,8 +223,8 @@ Uncaught Error: This is a error > parser init error: WebAssembly.instantiate(): invalid value type 'externref', enable with --experimental-wasm-reftypes @+86 -1. **检查 Node.js 版本**:确保 Node.js 版本为 18 或更高。如果版本低于 18,请升级 Node.js。 -2. **启用实验性标志**:如果 Node.js 版本为 18+ 但仍然遇到问题,请使用以下命令启动工具: +1. **检查 Node.js 版本**:确保 Node.js 版本为 20 或更高。如果版本低于 20,请升级 Node.js。 +2. **启用实验性标志**:如果 Node.js 版本为 20+ 但仍然遇到问题,请使用以下命令启动工具: ```bash npx --node-arg=--experimental-wasm-reftypes -y source-map-parser-mcp@latest ``` diff --git a/build.sh b/build.sh index 0a653e0..5c8c266 100755 --- a/build.sh +++ b/build.sh @@ -1,15 +1,22 @@ #!/bin/bash +set -e + +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +cd "$SCRIPT_DIR" + # Run Vite build npm run build:vite -# Run repomix to gen the operating guide -npx -y repomix +# Generate TypeScript declaration files +npx tsc -p "$SCRIPT_DIR/tsconfig.build.json" + +# Bundle declarations into a single file +npx rollup -c "$SCRIPT_DIR/rollup.config.dts.mjs" -# Check if the build was successful -if [ $? -ne 0 ]; then - echo "Build failed, exiting script." - exit 1 +# Remove intermediate declaration artifacts +if [ -d "$SCRIPT_DIR/dist/types" ]; then + rm -rf "$SCRIPT_DIR/dist/types" fi # Note: External directory copying has been removed as we now use source_map_parser_node npm package directly \ No newline at end of file diff --git a/package.json b/package.json index 31ff6eb..f9a78d3 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,16 @@ "type": "module", "description": "Parse JavaScript error stack traces back to original source code using source maps", "mcpName": "io.github.MasonChow/source-map-parser-mcp", - "main": "index.js", + "main": "dist/index.cjs.js", + "module": "dist/index.es.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.es.js", + "require": "./dist/index.cjs.js" + } + }, "scripts": { "build": "bash build.sh", "build:vite": "vite build", @@ -34,6 +43,8 @@ "@types/node": "^22.13.14", "@vitest/coverage-v8": "^3.1.1", "@vitest/ui": "^3.1.1", + "rollup": "^4.52.2", + "rollup-plugin-dts": "^6.2.3", "typescript": "^5.8.2", "vite": "^6.2.4", "vite-plugin-top-level-await": "^1.6.0", diff --git a/rollup.config.dts.mjs b/rollup.config.dts.mjs new file mode 100644 index 0000000..99fcf25 --- /dev/null +++ b/rollup.config.dts.mjs @@ -0,0 +1,10 @@ +import dts from 'rollup-plugin-dts'; + +export default { + input: 'dist/types/index.d.ts', + output: { + file: 'dist/index.d.ts', + format: 'es', + }, + plugins: [dts()], +}; diff --git a/src/cachingFetch.ts b/src/cachingFetch.ts index 504adc4..311e3ac 100644 --- a/src/cachingFetch.ts +++ b/src/cachingFetch.ts @@ -9,6 +9,13 @@ const cacheManager = new MemoryCacheManager({ maxSize: cacheSizeMB // Size in MB }); +const bufferToArrayBuffer = (buffer: Buffer): ArrayBuffer => { + const arrayBuffer = new ArrayBuffer(buffer.length); + const view = new Uint8Array(arrayBuffer); + view.set(buffer); + return arrayBuffer; +}; + /** * Enhanced fetch function that supports ETag-based memory caching * @param url Request URL @@ -41,7 +48,7 @@ export async function cachingFetch( // Handle 304 Not Modified response if (response.status === 304 && cachedEntry) { // Create new response from cache - const cachedResponse = new Response(cachedEntry.data, { + const cachedResponse = new Response(bufferToArrayBuffer(cachedEntry.data), { status: 200, statusText: 'OK', headers: response.headers diff --git a/src/external/docs/guide.xml b/src/external/docs/guide.xml deleted file mode 100644 index 092c6f4..0000000 --- a/src/external/docs/guide.xml +++ /dev/null @@ -1,645 +0,0 @@ -This file is a merged representation of a subset of the codebase, containing specifically included files and files not matching ignore patterns, combined into a single document by Repomix. -The content has been processed where empty lines have been removed, content has been compressed (code blocks are separated by ⋮---- delimiter). - - -This section contains a summary of this file. - - -This file contains a packed representation of a subset of the repository's contents that is considered the most important context. -It is designed to be easily consumable by AI systems for analysis, code review, -or other automated processes. - - - -The content is organized as follows: -1. This summary section -2. Repository information -3. Directory structure -4. Repository files (if enabled) -5. Multiple file entries, each consisting of: - - File path as an attribute - - Full contents of the file - - - -- This file should be treated as read-only. Any changes should be made to the - original repository files, not this packed version. -- When processing this file, use the file path to distinguish - between different files in the repository. -- Be aware that this file may contain sensitive information. Handle it with - the same level of security as you would the original repository. - - - -- Some files may have been excluded based on .gitignore rules and Repomix's configuration -- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files -- Only files matching these patterns are included: README.md, **/*.ts -- Files matching these patterns are excluded: src/external/ -- Files matching patterns in .gitignore are excluded -- Files matching default ignore patterns are excluded -- Empty lines have been removed from all files -- Content has been compressed - code blocks are separated by ⋮---- delimiter -- Files are sorted by Git change count (files with more changes are at the bottom) - - - - - -src/ - types/ - source_map_parser_node.d.ts - cachingFetch.ts - main.ts - memoryCacheManager.ts - parser.ts - server.ts -tests/ - client.test.ts - issue-21-fix.test.ts - memoryCacheManager.test.ts -README.md - - - -This section contains the contents of the repository's files. - - -export function init(): Promise; -export function generate_token_by_single_stack( - line: number, - column: number, - sourceMap: string, - contextOffset?: number - ): string; -// Add other functions from the package as needed -export function lookup_token( - sourceMap: string, - line: number, - column: number - ): string; -export function lookup_token_with_context( - sourceMap: string, - line: number, - column: number, - contextLines: number - ): string; -export function map_error_stack( - sourceMap: string, - errorStack: string, - contextLines?: number - ): string; - - - -// Cache entry type -interface CacheEntry { - url: string; - etag: string; - data: Buffer; - size: number; - lastAccessed: number; -} -// Cache configuration interface -interface CacheConfig { - /** - * Maximum cache size in MB - * - * @description - * Default is 200MB. - * */ - maxSize?: number; -} -⋮---- -/** - * Maximum cache size in MB - * - * @description - * Default is 200MB. - * */ -⋮---- -// Memory cache manager -class MemoryCacheManager -⋮---- -private readonly maxSize: number; // Maximum cache size in bytes -constructor(config: CacheConfig = -⋮---- -// Default to 200MB if not specified -this.maxSize = (config.maxSize || 200) * 1024 * 1024; // 200MB in bytes -⋮---- -// Get cache entry -public get(url: string): CacheEntry | null -⋮---- -// Update last accessed time -⋮---- -// Set cache entry -public set(url: string, data: Buffer, etag: string): void -⋮---- -// If adding a new entry would exceed the maximum cache size, clean up space first -⋮---- -// If entry already exists, update the cache size first -⋮---- -// Create new cache entry -⋮---- -// Save to memory -⋮---- -// Clean up cache to free up space -private cleanup(neededSpace: number): void -⋮---- -// If a single request already exceeds the maximum cache size, it cannot be cached -⋮---- -// Sort by last accessed time -⋮---- -// Remove oldest entries until there is enough space -⋮---- -// Get current cache size information -public getStats(): -// Clear cache -public clear(): void - - - -import { Client } from '@modelcontextprotocol/sdk/client/index.js'; -import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; -import { afterAll, beforeAll, expect, test } from 'vitest'; - - - -import { describe, it, expect, beforeEach } from 'vitest'; -import MemoryCacheManager from '../src/memoryCacheManager'; -⋮---- -cache = new MemoryCacheManager({ maxSize: 1 }); // 1MB for testing -⋮---- -// Wait a bit and get again -⋮---- -// maxSize = 1MB, each buffer is 600KB -⋮---- -cache.set('b', bufB, 'etag-b'); // should evict 'a' -⋮---- -const bigBuf = Buffer.alloc(2 * 1024 * 1024, 1); // 2MB - - - -import MemoryCacheManager from './memoryCacheManager'; -// Read cache size from environment variable or use default value -⋮---- -// Global cache manager instance with size from environment variable -⋮---- -maxSize: cacheSizeMB // Size in MB -⋮---- -/** - * Enhanced fetch function that supports ETag-based memory caching - * @param url Request URL - * @param options Fetch options - * @returns Promise - */ -export async function cachingFetch( - url: string, - options: RequestInit = {} -): Promise -⋮---- -// Only cache GET requests -⋮---- -// Try to get cache entry -⋮---- -// If there is a cache, add If-None-Match header -⋮---- -// Send request -⋮---- -// Handle 304 Not Modified response -⋮---- -// Create new response from cache -⋮---- -// If the response is successful and has an ETag header, cache the response -⋮---- -// Also export the cache manager to allow access to cache statistics or manual cache clearing when needed -⋮---- -// Export the enhanced fetch function - - - -import { describe, it, expect } from 'vitest'; -import Parser from '../src/parser.js'; -import fs from 'fs/promises'; -import path from 'path'; -⋮---- -// Read the local source map file mentioned in the issue -⋮---- -// Test the exact stack traces from the issue -⋮---- -// Verify the token structure is correct -⋮---- -// Verify sourceCode array contains SourceCode objects with correct structure -⋮---- -// Use the local source map file for consistent results -⋮---- -// For file:// URLs, we expect fetch to fail, which is OK - - - -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import server from './server'; -export const stdio = async () => - - - -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import packageJson from "../package.json"; -import Parser from "./parser"; -import fs from 'node:fs/promises'; -import path from 'node:path'; -⋮---- -// Sanitize error messages to avoid exposing internal details - - - -import fetch from './cachingFetch' -interface Stack { - /** Line number in the stack trace */ - line: number; - /** Column number in the stack trace */ - column: number; - /** URL of the source map file */ - sourceMapUrl: string; -} -⋮---- -/** Line number in the stack trace */ -⋮---- -/** Column number in the stack trace */ -⋮---- -/** URL of the source map file */ -⋮---- -interface SourceCode { - /** Line number in the source code */ - line: number; - /** Whether this line is part of the error stack trace */ - isStackLine: boolean; - /** Raw code of the corresponding line */ - raw: string; -} -⋮---- -/** Line number in the source code */ -⋮---- -/** Whether this line is part of the error stack trace */ -⋮---- -/** Raw code of the corresponding line */ -⋮---- -interface Token { - /** Line number in the source map */ - line: number; - /** Column number in the source map */ - column: number; - /** Contextual source code lines */ - sourceCode: SourceCode[]; - /** File path of the source map */ - src: string; -} -⋮---- -/** Line number in the source map */ -⋮---- -/** Column number in the source map */ -⋮---- -/** Contextual source code lines */ -⋮---- -/** File path of the source map */ -⋮---- -type BatchParseResult = Array<{ - /** Indicates a failed parsing result */ - success: false; - /** Error object describing the failure */ - error: Error; -} | { - /** Indicates a successful parsing result */ - success: true; - /** Parsed token object */ - token: Token; -}>; -⋮---- -/** Indicates a failed parsing result */ -⋮---- -/** Error object describing the failure */ -⋮---- -/** Indicates a successful parsing result */ -⋮---- -/** Parsed token object */ -⋮---- -const arrayBufferToString = (buffer: ArrayBuffer): string => -/** - * Validates a URL to prevent SSRF attacks - * @param url - The URL to validate - * @throws Error if the URL is invalid or potentially malicious - */ -const validateUrl = (url: string): void => -⋮---- -// Allow only HTTP and HTTPS protocols -⋮---- -// Optional: Add domain allowlist/blocklist here if needed -// Example: if (parsedUrl.hostname.endsWith('.internal.company.com')) { -// throw new Error('Access to internal domains is not allowed'); -// } -⋮---- -class Parser -⋮---- -/** Indicates whether the parser has been initialized */ -⋮---- -/** Context offset line for source code */ -⋮---- -constructor(config: { - /** Context offset line for source code */ - contextOffsetLine?: number; -} = -⋮---- -/** Context offset line for source code */ -⋮---- -/** - * Initializes the parser by loading necessary dependencies. - * This method ensures initialization is performed only once. - */ -private async init() -/** - * Fetches the content of a source map file from a given URL. - * - * @param url - The URL of the source map file. - * @returns The content of the source map file as a string. - * @throws An error if the fetch operation fails or URL is invalid. - * - * @todo Add caching for fetched source maps. - */ -private async fetchSourceMapContent(url: string) -⋮---- -// Validate URL to prevent SSRF attacks -⋮---- -/** - * Parses an array of stack trace objects and returns the results in batch. - * - * @param stackArr - An array of stack trace objects to parse. - * @returns A batch parse result containing success or failure for each stack trace. - */ -public async batchParseStack(stackArr: Stack[]): Promise -⋮---- -// Ensure initialization is complete -⋮---- -// Step 1: Get all necessary source map contents, eliminating duplicates -⋮---- -// Fetch all unique source maps in parallel -⋮---- -// Step 2: Generate tokens using the fetched source map contents -⋮---- -// If source map fetch failed, return an error directly -⋮---- -// Use the fetched source map content -⋮---- -// Use the dedicated method to get the token -⋮---- -/** - * Parses a single stack trace object and returns the corresponding token. - * - * @param stack - The stack trace object to parse. - * @returns A parsed token object. - */ -public async parseStack(stack: Stack): Promise -/** - * Validates that the parsed token matches the expected Token interface - * @param token - The parsed token object to validate - * @throws Error if the token doesn't match the expected structure - */ -private validateToken(token: any): asserts token is Token -⋮---- -// Validate each source code entry -⋮---- -/** - * Transforms the raw response from WebAssembly module to match the expected Token interface - * @param rawToken - The raw token object from WebAssembly (uses snake_case) - * @returns Transformed token object matching the Token interface (uses camelCase) - */ -private transformToken(rawToken: any): Token -/** - * Retrieves the source token for a given line and column in the source map. - * - * @param line - The line number in the source map. - * @param column - The column number in the source map. - * @param sourceMap - The content of the source map file. - * @returns A parsed token object. - * @throws An error if the token generation fails. - */ -public async getSourceToken(line: number, column: number, sourceMap: string): Promise -⋮---- -// Transform the raw token to match the expected interface -⋮---- -// Validate the token structure - - - -[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/masonchow-source-map-parser-mcp-badge.png)](https://mseep.ai/app/masonchow-source-map-parser-mcp) - -# Source Map Parser - -🌐 **语言**: [English](README.md) | [简体中文](README.zh-CN.md) - -[![Node Version](https://img.shields.io/node/v/source-map-parser-mcp)](https://nodejs.org) -[![npm](https://img.shields.io/npm/v/source-map-parser-mcp.svg)](https://www.npmjs.com/package/source-map-parser-mcp) -[![Downloads](https://img.shields.io/npm/dm/source-map-parser-mcp)](https://npmjs.com/package/source-map-parser-mcp) -[![Build Status](https://github.com/MasonChow/source-map-parser-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MasonChow/source-map-parser-mcp/actions) -[![codecov](https://codecov.io/gh/MasonChow/source-map-parser-mcp/graph/badge.svg)](https://codecov.io/gh/MasonChow/source-map-parser-mcp) -![](https://badge.mcpx.dev?type=server&features=tools 'MCP server with tools') - - - - - -This project implements a WebAssembly-based Source Map parser that can map JavaScript error stack traces back to source code and extract relevant context information. Developers can easily map JavaScript error stack traces back to source code for quick problem identification and resolution. This documentation aims to help developers better understand and use this tool. - -## MCP Integration - -> Note: Requires Node.js 18+ support - -Option 1: Run directly with NPX - -```bash -npx -y source-map-parser-mcp@latest -``` - -Option 2: Download the build artifacts - -Download the corresponding version of the build artifacts from the [GitHub Release](https://github.com/MasonChow/source-map-parser-mcp/releases) page, then run: - -```bash -node dist/main.es.js -``` - -### Runtime Parameter Configuration - -> System runtime parameters can be flexibly configured through environment variables to meet the needs of different scenarios - -- `SOURCE_MAP_PARSER_RESOURCE_CACHE_MAX_SIZE`: Sets the maximum memory space occupied by resource cache, default is 200MB. Adjusting this value appropriately can balance performance and memory usage. -- `SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE`: Defines the number of context code lines to display around the error location, default is 1 line. Increasing this value provides more context information, facilitating problem diagnosis. - -**Example:** - -```bash -# Set 500MB cache and display 3 lines of context -export SOURCE_MAP_PARSER_RESOURCE_CACHE_MAX_SIZE=500 -export SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE=3 -npx -y source-map-parser-mcp@latest -``` - -## Feature Overview - -1. **Stack Parsing**: Parse the corresponding source code location based on provided line number, column number, and Source Map file. -2. **Batch Processing**: Support parsing multiple stack traces simultaneously and return batch results. -3. **Context Extraction**: Extract context code for a specified number of lines to help developers better understand the environment where errors occur. - -## MCP Service Tool Description - -### `operating_guide` - -Get usage instructions for the MCP service. Provides information on how to use the MCP service through chat interaction. - -### `parse_stack` - -Parse stack information by providing stack traces and Source Map addresses. - -#### Request Example - -- stacks: Stack information including line number, column number, and Source Map address. - - line: Line number, required. - - column: Column number, required. - - sourceMapUrl: Source Map address, required. - -```json -{ - "stacks": [ - { - "line": 10, - "column": 5, - "sourceMapUrl": "https://example.com/source.map" - } - ] -} -``` - -#### Response Example - -```json -{ - "content": [ - { - "type": "text", - "text": "[{\"success\":true,\"token\":{\"line\":10,\"column\":5,\"sourceCode\":[{\"line\":8,\"isStackLine\":false,\"raw\":\"function foo() {\"},{\"line\":9,\"isStackLine\":false,\"raw\":\" console.log('bar');\"},{\"line\":10,\"isStackLine\":true,\"raw\":\" throw new Error('test');\"},{\"line\":11,\"isStackLine\":false,\"raw\":\"}\"}],\"src\":\"index.js\"}}]" - } - ] -} -``` - -### Parsing Result Description - -- `success`: Indicates whether the parsing was successful. -- `token`: The Token object returned when parsing is successful, containing source code line number, column number, context code, and other information. -- `error`: Error information returned when parsing fails. - -## Example Run - -### System Prompt - -According to actual needs, you can use system prompts to guide the model on how to parse stack information. For security or performance reasons, some teams may not want to expose Source Maps directly to the browser for parsing, but instead process the upload path of the Source Map. For example, converting the path `bar-special.js` to `special/bar.js.map`. In this case, you can instruct the model to perform path conversion through prompt rules. - -Here is an example: - -```markdown -# Error Stack Trace Parsing Rules - -When performing source map parsing, please follow these rules: - -1. If the URL contains `special`, the file should be parsed into the `special/` directory, while removing `-special` from the filename. -2. All source map files are stored in the following CDN directory: - `https://cdn.jsdelivr.net/gh/MasonChow/source-map-parser-mcp@main/example/` - -## Examples - -- Source map address for `bar-special.js`: - `https://cdn.jsdelivr.net/gh/MasonChow/source-map-parser-mcp@main/example/special/bar.js.map` -``` - -### Runtime Example - -Error Stack - -``` -Uncaught Error: This is a error - at foo-special.js:49:34832 - at ka (foo-special.js:48:83322) - at Vs (foo-special.js:48:98013) - at Et (foo-special.js:48:97897) - at Vs (foo-special.js:48:98749) - at Et (foo-special.js:48:97897) - at Vs (foo-special.js:48:98059) - at sv (foo-special.js:48:110550) - at foo-special.js:48:107925 - at MessagePort.Ot (foo-special.js:25:1635) -``` - -![Runtime Example](https://cdn.jsdelivr.net/gh/MasonChow/source-map-parser-mcp@main/example/example_en.png) - -## FAQ - -### 1. WebAssembly Module Loading Failure - -If the tool returns the following error message, please troubleshoot as follows: - -> parser init error: WebAssembly.instantiate(): invalid value type 'externref', enable with --experimental-wasm-reftypes @+86 - -1. **Check Node.js Version**: Ensure Node.js version is 18 or higher. If it's lower than 18, please upgrade Node.js. -2. **Enable Experimental Flag**: If Node.js version is 18+ but you still encounter issues, use the following command to start the tool: - ```bash - npx --node-arg=--experimental-wasm-reftypes -y source-map-parser-mcp@latest - ``` - -## Local Development Guide - -### 1. Install Dependencies - -Ensure Node.js and npm are installed, then run the following command to install project dependencies: - -```bash -npm install -``` - -### 2. Link MCP Service - -Run the following command to start the MCP server: - -```bash -npx tsx src/main.ts -``` - -### Internal Logic Overview - -#### 1. Main File Description - -- **`stack_parser_js_sdk.js`**: JavaScript wrapper for the WebAssembly module, providing core stack parsing functionality. -- **`parser.ts`**: Main implementation of the parser, responsible for initializing the WebAssembly module, retrieving Source Map content, and parsing stack information. -- **`server.ts`**: Implementation of the MCP server, providing the `parse_stack` tool interface for external calls. - -#### 2. Modify Parsing Logic - -To modify the parsing logic, edit the `getSourceToken` method in the `parser.ts` file. - -#### 3. Add New Tools - -In the `server.ts` file, new tool interfaces can be added using the `server.tool` method. - -## Notes - -1. **Source Map Files**: Ensure that the provided Source Map file address is accessible and the file format is correct. -2. **Error Handling**: During parsing, network errors, file format errors, and other issues may be encountered; it's recommended to implement proper error handling when making calls. - -## Contribution Guidelines - -Contributions via Issues and Pull Requests are welcome to improve this project. - -## License - -This project is licensed under the MIT License. See the LICENSE file for details. - - - diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..29d903e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +export { registerTools } from './tools.js'; +export type { ToolsRegistryOptions } from './tools.js'; +export { default as Parser } from './parser.js'; \ No newline at end of file diff --git a/src/parser.ts b/src/parser.ts index 9c7ac41..ecf3d14 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,5 +1,19 @@ import * as sourceMapParser from 'source_map_parser_node'; import fetch from './cachingFetch' +// Raw token interface from WebAssembly (snake_case) +interface RawToken { + line: number; + column: number; + src: string; + source_code?: RawSourceCode[]; +} + +interface RawSourceCode { + line: number; + is_stack_line: boolean; + raw: string; +} + interface Stack { /** Line number in the stack trace */ line: number; @@ -220,41 +234,63 @@ class Parser { return this.getSourceToken(stack.line, stack.column, sourceMapContent); } + /** + * Type guard to validate raw token structure from WebAssembly + */ + private isRawToken(obj: unknown): obj is RawToken { + if (!obj || typeof obj !== 'object') { + return false; + } + + return ( + 'line' in obj && typeof obj.line === 'number' && + 'column' in obj && typeof obj.column === 'number' && + 'src' in obj && typeof obj.src === 'string' && + ('source_code' in obj && (obj.source_code === undefined || Array.isArray(obj.source_code))) + ); + } + /** * Validates that the parsed token matches the expected Token interface * @param token - The parsed token object to validate * @throws Error if the token doesn't match the expected structure */ - private validateToken(token: any): asserts token is Token { + private validateToken(token: unknown): asserts token is Token { if (!token || typeof token !== 'object') { throw new Error('Invalid token: expected an object'); } - if (typeof token.line !== 'number' || token.line < 0) { + const obj = token as Record; + + if (typeof obj.line !== 'number' || obj.line < 0) { throw new Error('Invalid token: line must be a non-negative number'); } - if (typeof token.column !== 'number' || token.column < 0) { + if (typeof obj.column !== 'number' || obj.column < 0) { throw new Error('Invalid token: column must be a non-negative number'); } - if (typeof token.src !== 'string') { + if (typeof obj.src !== 'string') { throw new Error('Invalid token: src must be a string'); } - if (!Array.isArray(token.sourceCode)) { + if (!Array.isArray(obj.sourceCode)) { throw new Error('Invalid token: sourceCode must be an array'); } // Validate each source code entry - for (const code of token.sourceCode) { - if (typeof code.line !== 'number' || code.line < 0) { + for (const code of obj.sourceCode) { + if (!code || typeof code !== 'object') { + throw new Error('Invalid source code entry: expected an object'); + } + const codeObj = code as Record; + if (typeof codeObj.line !== 'number' || codeObj.line < 0) { throw new Error('Invalid source code entry: line must be a non-negative number'); } - if (typeof code.isStackLine !== 'boolean') { + if (typeof codeObj.isStackLine !== 'boolean') { throw new Error('Invalid source code entry: isStackLine must be a boolean'); } - if (typeof code.raw !== 'string') { + if (typeof codeObj.raw !== 'string') { throw new Error('Invalid source code entry: raw must be a string'); } } @@ -265,12 +301,12 @@ class Parser { * @param rawToken - The raw token object from WebAssembly (uses snake_case) * @returns Transformed token object matching the Token interface (uses camelCase) */ - private transformToken(rawToken: any): Token { + private transformToken(rawToken: RawToken): Token { return { line: rawToken.line, column: rawToken.column, src: rawToken.src, - sourceCode: rawToken.source_code?.map((sourceCode: any) => ({ + sourceCode: rawToken.source_code?.map((sourceCode: RawSourceCode) => ({ line: sourceCode.line, isStackLine: sourceCode.is_stack_line, raw: sourceCode.raw @@ -303,6 +339,10 @@ class Parser { } // Transform the raw token to match the expected interface + if (!this.isRawToken(rawToken)) { + throw new Error('Invalid raw token structure from WebAssembly'); + } + const token = this.transformToken(rawToken); // Validate the token structure diff --git a/src/server.ts b/src/server.ts index abd0e62..0b7facd 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,14 +1,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; import packageJson from "../package.json"; -import Parser from "./parser"; -import fs from 'node:fs/promises'; -import path from 'node:path'; - -const parser = new Parser({ - contextOffsetLine: process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE ? parseInt(process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE) : 1, -}); +import { registerTools } from "./tools.js"; const server = new McpServer({ name: packageJson.name, @@ -16,100 +9,61 @@ const server = new McpServer({ }, { capabilities: { tools: {} - } -}); - -server.tool('operating_guide', ` - # Parse Error Stack Trace + }, + instructions: ` +# Source Map Parser MCP Server - This tool allows you to parse error stack traces by mapping them to the corresponding source code locations using source maps. - It is particularly useful for debugging production errors where the stack trace points to minified or obfuscated code. -`, async () => { +这是一个专门用于解析 JavaScript 错误堆栈跟踪的 MCP 服务器,通过 Source Map 将压缩/混淆后的错误位置映射回原始源代码位置。 - try { - const content = await fs.readFile(path.join(process.cwd(), 'README.md'), 'utf-8'); +## 主要功能 - return { - content: [ - { - type: "text", - text: content - } - ] - } - } catch (error) { - return { - isError: true, - content: [ - { - type: "text", - text: "Error reading the documentation file. Please check the README.md file in the project root." - } - ] - } - } -}) +### parse_stack 工具 +解析错误堆栈跟踪,将压缩代码中的行号列号映射到原始源代码位置。 -server.tool("parse_stack", ` - # Parse Error Stack Trace +**使用场景:** +- 生产环境错误调试 +- 压缩代码错误定位 +- 源代码映射分析 - This tool allows you to parse error stack traces by providing the following: - - A downloadable source map URL. - - The line and column numbers from the stack trace. +**参数说明:** +- \`stacks\`: 堆栈跟踪对象数组,每个对象包含: + - \`line\`: 错误所在行号 + - \`column\`: 错误所在列号 + - \`sourceMapUrl\`: 对应的 Source Map 文件 URL - The tool will map the provided stack trace information to the corresponding source code location using the source map. - It also supports fetching additional context lines around the error location for better debugging. +**返回结果:** +- 成功时返回映射后的源代码位置和上下文代码 +- 失败时返回错误信息 - ## Parameters: - - **stacks**: An array of stack trace objects, each containing: - - **line**: The line number in the stack trace. - - **column**: The column number in the stack trace. - - **sourceMapUrl**: The URL of the source map file corresponding to the stack trace. +## 环境变量配置 - - **ctxOffset** (optional): The number of additional context lines to include before and after the error location in the source code. Defaults to 5. +- \`SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE\`: 设置源代码上下文行数(默认: 1) +- \`SOURCE_MAP_PARSER_RESOURCE_CACHE_MAX_SIZE\`: 缓存大小限制(默认: 200MB) - ## Returns: - - A JSON object containing the parsed stack trace information, including the mapped source code location and context lines. - - If parsing fails, an error message will be returned for the corresponding stack trace. -`, { - stacks: z.array( - z.object({ - line: z.number({ - description: "The line number in the stack trace.", - }), - column: z.number({ - description: "The column number in the stack trace.", - }), - sourceMapUrl: z.string({ - description: "The URL of the source map file corresponding to the stack trace.", - }), - }) - ) -}, async ({ stacks }) => { - const parserRes = await parser.batchParseStack(stacks); +## 使用示例 - if (parserRes.length === 0) { - return { - isError: true, - content: [{ type: "text", text: "No data could be parsed from the provided stack traces." }], - } +\`\`\`json +{ + "tool": "parse_stack", + "arguments": { + "stacks": [ + { + "line": 1, + "column": 1234, + "sourceMapUrl": "https://example.com/assets/main.js.map" + } + ] } +} +\`\`\` - return { - content: [{ - type: "text", text: JSON.stringify(parserRes.map(e => { - if (e.success) { - return e; - } else { - // Sanitize error messages to avoid exposing internal details - const sanitizedMessage = e.error.message.replace(/[^\w\s.:\-\/]/g, ''); - return { - success: false, - msg: sanitizedMessage, - } - } - })) - }], - } +该工具特别适用于调试生产环境中的 JavaScript 错误,能够快速定位到原始源代码中的具体位置。 + `.trim() +}); + +// Register tools with contextOffsetLine from environment variable +registerTools(server, { + contextOffsetLine: process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE ? parseInt(process.env.SOURCE_MAP_PARSER_CONTEXT_OFFSET_LINE) : 1, }); + export default server; \ No newline at end of file diff --git a/src/tools.ts b/src/tools.ts new file mode 100644 index 0000000..0bb5e22 --- /dev/null +++ b/src/tools.ts @@ -0,0 +1,103 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { z } from "zod"; +import type Parser from './parser.js'; + +export interface ToolsRegistryOptions { + contextOffsetLine?: number; +} + +type BatchParseResult = Array<{ + success: false; + error: Error; +} | { + success: true; + token: { + line: number; + column: number; + sourceCode: Array<{ + line: number; + isStackLine: boolean; + raw: string; + }>; + src: string; + }; +}>; + +export function registerTools(server: McpServer, options: ToolsRegistryOptions = {}) { + let parserInstance: Parser | null = null; + + const getParser = async (): Promise => { + if (!parserInstance) { + const { default: ParserClass } = await import('./parser.js'); + parserInstance = new ParserClass({ + contextOffsetLine: options.contextOffsetLine || 1, + }); + } + return parserInstance; + }; + + server.tool("parse_stack", ` + # Parse Error Stack Trace + + This tool allows you to parse error stack traces by providing the following: + - A downloadable source map URL. + - The line and column numbers from the stack trace. + + The tool will map the provided stack trace information to the corresponding source code location using the source map. + It also supports fetching additional context lines around the error location for better debugging. + + ## Parameters: + - **stacks**: An array of stack trace objects, each containing: + - **line**: The line number in the stack trace. + - **column**: The column number in the stack trace. + - **sourceMapUrl**: The URL of the source map file corresponding to the stack trace. + + - **ctxOffset** (optional): The number of additional context lines to include before and after the error location in the source code. Defaults to 5. + + ## Returns: + - A JSON object containing the parsed stack trace information, including the mapped source code location and context lines. + - If parsing fails, an error message will be returned for the corresponding stack trace. +`, { + stacks: z.array( + z.object({ + line: z.number({ + description: "The line number in the stack trace.", + }), + column: z.number({ + description: "The column number in the stack trace.", + }), + sourceMapUrl: z.string({ + description: "The URL of the source map file corresponding to the stack trace.", + }), + }) + ) +}, async ({ stacks }) => { + const parser = await getParser(); + const parserRes: BatchParseResult = await parser.batchParseStack(stacks); + + if (parserRes.length === 0) { + return { + isError: true, + content: [{ type: "text", text: "No data could be parsed from the provided stack traces." }], + } + } + + return { + content: [{ + type: "text", text: JSON.stringify(parserRes.map((e) => { + if (e.success) { + return e; + } else { + // Sanitize error messages to avoid exposing internal details + const sanitizedMessage = e.error.message.replace(/[^\w\s.:\-\/]/g, ''); + return { + success: false, + msg: sanitizedMessage, + } + } + })) + }], + } +}); + +} \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..9c82dd5 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist/types", + "rootDir": "src" + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index dbd549a..2ed87fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,5 +27,6 @@ ], "include": [ "src", + "types", ] } \ No newline at end of file diff --git a/src/types/source_map_parser_node.d.ts b/types/source_map_parser_node.d.ts similarity index 100% rename from src/types/source_map_parser_node.d.ts rename to types/source_map_parser_node.d.ts diff --git a/vite.config.mjs b/vite.config.mjs index f95b2fe..a77abc1 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -9,7 +9,10 @@ export default defineConfig({ build: { target: 'node20', lib: { - entry: ['./src/main.ts'], + entry: { + 'index': './src/index.ts', + 'main': './src/main.ts' + }, fileName: (format, entryName) => `${entryName}.${format}.js`, name: packageJSON.name, formats: ['es', 'cjs'], From 5d9741fcc979807d785e8377b6569734c29b80b8 Mon Sep 17 00:00:00 2001 From: MasonChow Date: Sat, 27 Sep 2025 01:17:30 +0800 Subject: [PATCH 2/4] chore: update package-lock.json to version 1.4.2 and upgrade dependencies --- package-lock.json | 275 +++++++++++++++++++++++++++++----------------- 1 file changed, 177 insertions(+), 98 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5aaf520..d46dd42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "source-map-parser-mcp", - "version": "1.3.2", + "version": "1.4.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "source-map-parser-mcp", - "version": "1.3.2", + "version": "1.4.2", "license": "ISC", "dependencies": { - "source_map_parser_node": "0.3.0" + "source_map_parser_node": "0.3.1" }, "bin": { "source-map-parser-mcp": "dist/main.es.js" @@ -19,6 +19,8 @@ "@types/node": "^22.13.14", "@vitest/coverage-v8": "^3.1.1", "@vitest/ui": "^3.1.1", + "rollup": "^4.52.2", + "rollup-plugin-dts": "^6.2.3", "typescript": "^5.8.2", "vite": "^6.2.4", "vite-plugin-top-level-await": "^1.6.0", @@ -44,6 +46,22 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", @@ -55,9 +73,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -670,9 +688,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz", + "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==", "cpu": [ "arm" ], @@ -684,9 +702,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz", + "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==", "cpu": [ "arm64" ], @@ -698,9 +716,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz", + "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==", "cpu": [ "arm64" ], @@ -712,9 +730,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz", + "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==", "cpu": [ "x64" ], @@ -726,9 +744,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz", + "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==", "cpu": [ "arm64" ], @@ -740,9 +758,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz", + "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==", "cpu": [ "x64" ], @@ -754,9 +772,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz", + "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==", "cpu": [ "arm" ], @@ -768,9 +786,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz", + "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==", "cpu": [ "arm" ], @@ -782,9 +800,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz", + "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==", "cpu": [ "arm64" ], @@ -796,9 +814,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz", + "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==", "cpu": [ "arm64" ], @@ -809,10 +827,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz", + "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==", "cpu": [ "loong64" ], @@ -823,10 +841,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz", + "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==", "cpu": [ "ppc64" ], @@ -838,9 +856,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz", + "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==", "cpu": [ "riscv64" ], @@ -852,9 +870,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz", + "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==", "cpu": [ "riscv64" ], @@ -866,9 +884,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz", + "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==", "cpu": [ "s390x" ], @@ -880,9 +898,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz", + "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==", "cpu": [ "x64" ], @@ -894,9 +912,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz", + "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==", "cpu": [ "x64" ], @@ -907,10 +925,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz", + "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz", + "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==", "cpu": [ "arm64" ], @@ -922,9 +954,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz", + "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==", "cpu": [ "ia32" ], @@ -935,10 +967,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz", + "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz", + "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==", "cpu": [ "x64" ], @@ -1183,9 +1229,9 @@ "license": "Apache-2.0" }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -2304,6 +2350,14 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2732,13 +2786,13 @@ } }, "node_modules/rollup": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz", + "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -2748,29 +2802,54 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.0", - "@rollup/rollup-android-arm64": "4.40.0", - "@rollup/rollup-darwin-arm64": "4.40.0", - "@rollup/rollup-darwin-x64": "4.40.0", - "@rollup/rollup-freebsd-arm64": "4.40.0", - "@rollup/rollup-freebsd-x64": "4.40.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", - "@rollup/rollup-linux-arm-musleabihf": "4.40.0", - "@rollup/rollup-linux-arm64-gnu": "4.40.0", - "@rollup/rollup-linux-arm64-musl": "4.40.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-musl": "4.40.0", - "@rollup/rollup-linux-s390x-gnu": "4.40.0", - "@rollup/rollup-linux-x64-gnu": "4.40.0", - "@rollup/rollup-linux-x64-musl": "4.40.0", - "@rollup/rollup-win32-arm64-msvc": "4.40.0", - "@rollup/rollup-win32-ia32-msvc": "4.40.0", - "@rollup/rollup-win32-x64-msvc": "4.40.0", + "@rollup/rollup-android-arm-eabi": "4.52.2", + "@rollup/rollup-android-arm64": "4.52.2", + "@rollup/rollup-darwin-arm64": "4.52.2", + "@rollup/rollup-darwin-x64": "4.52.2", + "@rollup/rollup-freebsd-arm64": "4.52.2", + "@rollup/rollup-freebsd-x64": "4.52.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.2", + "@rollup/rollup-linux-arm-musleabihf": "4.52.2", + "@rollup/rollup-linux-arm64-gnu": "4.52.2", + "@rollup/rollup-linux-arm64-musl": "4.52.2", + "@rollup/rollup-linux-loong64-gnu": "4.52.2", + "@rollup/rollup-linux-ppc64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-musl": "4.52.2", + "@rollup/rollup-linux-s390x-gnu": "4.52.2", + "@rollup/rollup-linux-x64-gnu": "4.52.2", + "@rollup/rollup-linux-x64-musl": "4.52.2", + "@rollup/rollup-openharmony-arm64": "4.52.2", + "@rollup/rollup-win32-arm64-msvc": "4.52.2", + "@rollup/rollup-win32-ia32-msvc": "4.52.2", + "@rollup/rollup-win32-x64-gnu": "4.52.2", + "@rollup/rollup-win32-x64-msvc": "4.52.2", "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-dts": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.2.3.tgz", + "integrity": "sha512-UgnEsfciXSPpASuOelix7m4DrmyQgiaWBnvI0TM4GxuDh5FkqW8E5hu57bCxXB90VvR1WNfLV80yEDN18UogSA==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "magic-string": "^0.30.17" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/Swatinem" + }, + "optionalDependencies": { + "@babel/code-frame": "^7.27.1" + }, + "peerDependencies": { + "rollup": "^3.29.4 || ^4", + "typescript": "^4.5 || ^5.0" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -3010,9 +3089,9 @@ } }, "node_modules/source_map_parser_node": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/source_map_parser_node/-/source_map_parser_node-0.3.0.tgz", - "integrity": "sha512-agvyOAzAv49jQ71+Ozo+JUbNBX6G635kHGz+sMuAJLfcG2Qwyu0dzrbEuFe4tI8BXOwy2ByXheKS0bv3OtZa2g==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/source_map_parser_node/-/source_map_parser_node-0.3.1.tgz", + "integrity": "sha512-KWgj56n8UuC7iv8MDefuLkvG0L6JrxVdOWFki2lJALfVz9bZl13sT+OLgBsh/pxIbZqz7E5ESqqu9LIso41YTg==", "license": "MIT" }, "node_modules/source-map-js": { From 8da39cabf5211c43afb55d1ff95d4816cce434a6 Mon Sep 17 00:00:00 2001 From: MasonChow Date: Sat, 27 Sep 2025 01:18:07 +0800 Subject: [PATCH 3/4] Update src/parser.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/parser.ts | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index ecf3d14..8fc69a0 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -237,17 +237,42 @@ class Parser { /** * Type guard to validate raw token structure from WebAssembly */ + private isRawSourceCode(obj: unknown): obj is RawSourceCode { + return ( + !!obj && + typeof obj === 'object' && + 'line' in obj && typeof (obj as any).line === 'number' && + 'is_stack_line' in obj && typeof (obj as any).is_stack_line === 'boolean' && + 'raw' in obj && typeof (obj as any).raw === 'string' + ); + } + private isRawToken(obj: unknown): obj is RawToken { if (!obj || typeof obj !== 'object') { return false; } - return ( - 'line' in obj && typeof obj.line === 'number' && - 'column' in obj && typeof obj.column === 'number' && - 'src' in obj && typeof obj.src === 'string' && - ('source_code' in obj && (obj.source_code === undefined || Array.isArray(obj.source_code))) - ); + if ( + !('line' in obj && typeof (obj as any).line === 'number') || + !('column' in obj && typeof (obj as any).column === 'number') || + !('src' in obj && typeof (obj as any).src === 'string') + ) { + return false; + } + + if ('source_code' in obj) { + const sourceCode = (obj as any).source_code; + if (sourceCode !== undefined) { + if (!Array.isArray(sourceCode)) { + return false; + } + if (!sourceCode.every(this.isRawSourceCode)) { + return false; + } + } + } + + return true; } /** From 9f4457b5073de48f84c72a1194284b8b218c5e3d Mon Sep 17 00:00:00 2001 From: MasonChow Date: Sat, 27 Sep 2025 01:18:16 +0800 Subject: [PATCH 4/4] Update src/tools.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tools.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools.ts b/src/tools.ts index 0bb5e22..d40410a 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -89,7 +89,7 @@ export function registerTools(server: McpServer, options: ToolsRegistryOptions = return e; } else { // Sanitize error messages to avoid exposing internal details - const sanitizedMessage = e.error.message.replace(/[^\w\s.:\-\/]/g, ''); + const sanitizedMessage = e.error.message.replace(/[^\w\s.:\-]/g, ''); return { success: false, msg: sanitizedMessage,