diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..e35f8da --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,60 @@ +name: CI/CD Pipeline + +on: + push: + branches: [ main, dev, 7-feat-add-workflow-ci ] + pull_request: + branches: [ main, dev, 7-feat-add-workflow-ci ] + +jobs: + test-and-build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + # Install and test client + - name: Install client dependencies + working-directory: ./client + run: | + npm install + npm run build + + - name: Run client tests + working-directory: ./client + run: | + npm test -- --passWithNoTests --no-watch + + - name: Run client linting + working-directory: ./client + run: | + rm -rf build/ + npm run lint -- --quiet || echo "Linting issues found, but continuing build" + + # Install and test server + - name: Install server dependencies + working-directory: ./server + run: npm install + + # Build server (if needed) + - name: Build server + working-directory: ./server + run: npm run build || echo "No build script found, skipping" + + deploy: + needs: test-and-build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + steps: + - uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' \ No newline at end of file diff --git a/README.md b/README.md index 098fd94..9cf018e 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,275 @@ -# CoreTrace Web Interface +# CoreTrace Web Application -A web-based interface for the CoreTrace tool that uses WebAssembly for core functionality. +A full-stack web application for analyzing C/C++ code using various static and dynamic analysis tools. The application provides a modern web interface for uploading code, configuring analysis options, and viewing security findings. -## Prerequisites +## Features -- [Node.js](https://nodejs.org/) (v16 or higher) +- **Code Analysis**: Analyze C/C++ code using multiple tools (flawfinder, cppcheck, etc.) +- **Sandboxed Execution**: Secure code analysis in isolated environments +- **Modern UI**: React-based interface with Monaco Editor for code editing +- **Real-time Results**: View analysis results with syntax highlighting +- **Tool Selection**: Choose which analysis tools to use +- **Example Code**: Pre-built examples for testing and learning -## Getting Started +## Architecture -These instructions will help you set up the project locally for development and testing purposes. +### Backend (Node.js/Express) +- **Server**: Express.js REST API +- **Analysis Engine**: Custom analyzer with tool integration +- **Sandboxing**: Multiple isolation methods (Firejail, QEMU, Bubblewrap) +- **Job Management**: Asynchronous analysis job handling +- **Logging**: Structured logging with Winston + +### Frontend (React) +- **UI Framework**: React with Tailwind CSS +- **Code Editor**: Monaco Editor with syntax highlighting +- **State Management**: React Context for application state +- **API Integration**: Axios for backend communication + +## Quick Start + +### Prerequisites + +- Node.js 16+ +- npm or yarn +- Linux environment (for sandboxing tools) +- Firejail (recommended) or QEMU ### Installation -1. Clone the repository: +1. **Clone the repository** + ```bash + git clone + cd coretrace-web + ``` + +2. **Install backend dependencies** + ```bash + cd server + npm install + ``` + +3. **Install frontend dependencies** + ```bash + cd ../client + npm install + ``` + +4. **Start the development servers** + ```bash + # Terminal 1 - Backend + cd server + npm run dev + + # Terminal 2 - Frontend + cd client + npm start + ``` + +5. **Access the application** + - Frontend: http://localhost:3000 + - Backend API: http://localhost:5000 + +## Documentation + +### API Documentation + +Comprehensive API documentation is available in [`server/API_DOCUMENTATION.md`](server/API_DOCUMENTATION.md). + +**Key Endpoints:** +- `POST /api/analyze` - Analyze code files +- `GET /api/tools` - Get available analysis tools +- `GET /api/examples` - Get example code snippets + +### Code Documentation + +#### Backend Documentation + +The backend code is documented using JSDoc. Generate documentation by running: + ```bash -git clone -cd ctrace-web +cd server +npm run docs ``` -2. Install dependencies for the client: -```bash -cd client -npm install +Then open `server/docs/index.html` in your browser. + +**Documented Modules:** +- **Services**: Analyzer, JobManager, Logger, Sandbox, SARIF Parser +- **Routes**: Analysis, Examples, Tools endpoints +- **Controllers**: Request handling and validation +- **Configuration**: Environment and sandbox settings + +#### Frontend Documentation + +Frontend components are documented with JSDoc comments: + +**Key Components:** +- `App.jsx` - Main application component +- `AnalysisContext.jsx` - State management context +- `ApiService` - Backend communication +- Editor components for code editing and results display + +### Architecture Documentation + +#### Backend Architecture + +``` +server/ +├── services/ # Business logic +│ ├── analyzer.js # Main analysis orchestrator +│ ├── jobManager.js # Job lifecycle management +│ ├── sandbox.js # Execution isolation +│ ├── logger.js # Logging service +│ └── sarifParser.js # Result parsing +├── routes/ # API endpoints +├── controllers/ # Request handlers +├── middlewares/ # Express middleware +└── config/ # Configuration ``` -3. Install dependencies for the server: -```bash -cd server -npm install +#### Frontend Architecture + +``` +client/src/ +├── components/ # React components +│ └── Editor/ # Code editor components +├── context/ # React context +├── services/ # API services +└── App.jsx # Main component ``` -### Running the Development Server +## Configuration + +### Backend Configuration + +Edit `server/config/index.js` to customize: + +- **Sandbox Settings**: Memory limits, timeouts, isolation methods +- **File Limits**: Maximum file sizes and counts +- **Job Management**: Cleanup delays and retention periods +- **Logging**: Log levels and formats + +### Environment Variables + +**Backend:** +- `PORT` - Server port (default: 5000) +- `NODE_ENV` - Environment mode +- `QEMU_BINARY` - QEMU binary path +- `QEMU_LIB_ROOT` - QEMU library root + +**Frontend:** +- `REACT_APP_API_URL` - Backend API URL + +## Development + +### Backend Development -Start the development server with: ```bash cd server -npm run dev +npm run dev # Start with nodemon +npm run docs # Generate documentation +npm test # Run tests ``` -### Running the Client -In a separate terminal, start the client: +### Frontend Development + ```bash cd client -npm run start +npm start # Start development server +npm test # Run tests +npm run build # Build for production ``` -## Project Structure +### Adding New Analysis Tools + +1. **Backend Integration** + - Add tool binary to `server/bin/` + - Update `services/analyzer.js` to include new tool + - Add tool configuration to `config/index.js` + +2. **Frontend Integration** + - Update tool selection UI in `components/Editor/` + - Add tool-specific result display logic + +### Documentation Standards + +#### JSDoc Comments + +Use standard JSDoc format for all functions and classes: + +```javascript +/** + * @function functionName + * @description Brief description of what the function does + * @param {string} paramName - Description of parameter + * @returns {Promise} Description of return value + * @throws {Error} Description of when error is thrown + */ +``` + +#### API Documentation + +- Update `server/API_DOCUMENTATION.md` for new endpoints +- Include request/response examples +- Document error scenarios + +## Deployment + +### Docker Deployment + +```bash +# Build and run with Docker Compose +docker-compose up --build +``` + +### Production Considerations + +- **Security**: Implement authentication and rate limiting +- **Monitoring**: Add application monitoring and logging +- **Scaling**: Consider job queue systems for high load +- **Backup**: Implement data backup strategies + +## Troubleshooting + +### Common Issues + +1. **Sandbox Failures** + - Ensure Firejail is installed: `sudo apt install firejail` + - Check file permissions in sandbox directories + - Verify resource limits in configuration + +2. **Analysis Tool Errors** + - Verify tool binaries are executable + - Check tool dependencies are installed + - Review tool-specific error logs + +3. **API Connection Issues** + - Verify backend server is running + - Check CORS configuration + - Ensure correct API URL in frontend + +### Logs + +- **Backend**: Check `server/combined.log` and `server/error.log` +- **Frontend**: Browser developer console +- **Sandbox**: Check system logs for sandbox-related errors + +## Contributing + +1. Fork the repository +2. Create a feature branch +3. Add tests for new functionality +4. Update documentation +5. Submit a pull request + +## License -- `client/` - Contains the React frontend application. -- `server/` - Contains the Node.js backend server. +[Add your license information here] -## Technologies Used +## Support -- React -- WebAssembly -- Tailwind CSS \ No newline at end of file +For issues and questions: +- Create an issue in the repository +- Check the documentation +- Review the troubleshooting section \ No newline at end of file diff --git a/client/.eslintignore b/client/.eslintignore new file mode 100644 index 0000000..c1ecd1e --- /dev/null +++ b/client/.eslintignore @@ -0,0 +1,6 @@ +node_modules/ +build/ +dist/ +coverage/ +postcss.config.js +tailwind.config.js diff --git a/client/docs/App.jsx.html b/client/docs/App.jsx.html new file mode 100644 index 0000000..f0281f4 --- /dev/null +++ b/client/docs/App.jsx.html @@ -0,0 +1,221 @@ + + + + + JSDoc: Source: App.jsx + + + + + + + + + + +
+ +

Source: App.jsx

+ + + + + + +
+
+
/**
+ * @module App
+ * @description Main application component for the CoreTrace web interface.
+ * Provides a code editor with analysis capabilities and results display.
+ */
+
+import React, { useState, useEffect } from 'react';
+import CodeEditorPane from './components/Editor/CodeEditorPane';
+import ResultsPane from './components/Editor/ResultsPane';
+import { analyzeCode as analyzeCodeAPI, getAvailableTools } from './services/api/api';
+
+/**
+ * @component App
+ * @description The main application component that renders the code editor and results pane.
+ * Manages the state for the code editor, analysis results, available tools, and user options.
+ * 
+ * @returns {JSX.Element} The rendered App component with code editor and results pane
+ * 
+ * @example
+ * <App />
+ */
+function App() {
+  /**
+   * @type {string}
+   * @description The code entered by the user in the editor
+   */
+  const [code, setCode] = useState('// Write your code here\n#include <iostream>\n\nint main(void)\n{\n  printf("Hello, World !\\n");\n  return 0;\n}');
+
+  /**
+   * @type {Object|null}
+   * @description The results of the code analysis or null if no analysis has been performed
+   */
+  const [results, setResults] = useState(null);
+
+  /**
+   * @type {boolean}
+   * @description Indicates whether the code analysis is in progress
+   */
+  const [loading, setLoading] = useState(false);
+
+  /**
+   * @type {number}
+   * @description The percentage width of the left pane (code editor)
+   */
+  let dividerPosition = 50;
+
+  /**
+   * @type {string}
+   * @description The name of the file being analyzed
+   */
+  const [filename, setFilename] = useState('main.cpp');
+
+  /**
+   * @type {Object}
+   * @description The user-selected options for code analysis
+   * @property {boolean} static - Enable static analysis
+   * @property {boolean} dynamic - Enable dynamic analysis
+   * @property {Array<string>} tools - Selected tools for analysis
+   */
+  const [options, setOptions] = useState({
+    static: true,
+    dynamic: false,
+    tools: [],
+  });
+
+  /**
+   * @type {Object}
+   * @description The list of tools available for analysis
+   * @property {Array<string>} tools - Array of available tool names
+   */
+  const [availableTools, setAvailableTools] = useState({
+    tools: [],
+  });
+
+  /**
+   * @effect
+   * @description Fetches the list of available tools when the component mounts
+   * and updates the state accordingly. Sets default options to include all tools.
+   */
+  useEffect(() => {
+    const fetchTools = async () => {
+      try {
+        const response = await getAvailableTools();
+        const tools = response.tools; // Access the tools array
+        // Default to all tools
+        setAvailableTools((prev) => ({ ...prev, tools: tools.map(tool => tool) }));
+        setOptions((prev) => ({ ...prev, tools: tools.map(tool => tool) }));
+      } catch (error) {
+        console.error('Error fetching tools:', error);
+      }
+    };
+
+    fetchTools();
+  }, []);
+
+  /**
+   * @function handleOptionChange
+   * @description Toggles a boolean option (e.g., static or dynamic analysis)
+   * @param {string} option - The name of the option to toggle
+   */
+  const handleOptionChange = (option) => {
+    setOptions((prev) => ({ ...prev, [option]: !prev[option] }));
+  };
+
+  /**
+   * @function handleToolToggle
+   * @description Toggles the inclusion of a specific tool in the analysis options
+   * @param {string} tool - The name of the tool to toggle
+   */
+  const handleToolToggle = (tool) => {
+    setOptions((prev) => ({
+      ...prev,
+      tools: prev.tools.includes(tool)
+        ? prev.tools.filter((t) => t !== tool)
+        : [...prev.tools, tool],
+    }));
+  };
+
+  /**
+   * @function handleAnalyzeCode
+   * @description Initiates the code analysis process by calling the API
+   * and updates the results state with the analysis findings
+   */
+  const handleAnalyzeCode = async () => {
+    try {
+      setLoading(true);
+      setResults(null);
+
+      const result = await analyzeCodeAPI(filename, code, options);
+      setResults(result);
+    } catch (error) {
+      console.error('Error analyzing code:', error);
+      setResults({ error: error.message });
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  return (
+    <div className="flex h-screen bg-gray-900 text-white">
+      <CodeEditorPane
+        code={code}
+        setCode={setCode}
+        dividerPosition={dividerPosition}
+        filename={filename}
+        setFilename={setFilename}
+      />
+      {/* <Divider handleMouseDown={handleMouseDown} /> */}
+      {availableTools.tools.length > 0 ? (
+        <ResultsPane
+          results={results}
+          loading={loading}
+          filename={filename}
+          setFilename={setFilename}
+          options={options}
+          availableTools={availableTools}
+          handleOptionChange={handleOptionChange}
+          handleToolToggle={handleToolToggle}
+          analyzeCode={handleAnalyzeCode}
+          dividerPosition={dividerPosition}
+        />
+      ) : (
+        <div className="flex items-center justify-center w-full">
+          <p>Loading tools...</p>
+        </div>
+      )}
+    </div>
+  );
+}
+
+export default App;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/client/docs/components_Editor_Editor.jsx.html b/client/docs/components_Editor_Editor.jsx.html new file mode 100644 index 0000000..3fd6aa0 --- /dev/null +++ b/client/docs/components_Editor_Editor.jsx.html @@ -0,0 +1,79 @@ + + + + + JSDoc: Source: components/Editor/Editor.jsx + + + + + + + + + + +
+ +

Source: components/Editor/Editor.jsx

+ + + + + + +
+
+
/**
+ * @module CodeEditor
+ * @description Monaco Editor wrapper component for code editing functionality.
+ * Provides a rich code editing experience with syntax highlighting and IntelliSense.
+ */
+
+import React, { Editor } from "@monaco-editor/react";
+
+/**
+ * @component CodeEditor
+ * @description A wrapper component for the Monaco Editor with default C++ configuration
+ * @returns {JSX.Element} Monaco Editor component with dark theme and C++ language support
+ * 
+ * @example
+ * <CodeEditor />
+ */
+export default function CodeEditor() {
+  return (
+    <div className="h-full w-full">
+      <Editor
+        height="100%"
+        defaultLanguage="cpp"
+        defaultValue="// Hello world"
+        theme="vs-dark"
+      />
+    </div>
+  );
+}
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/client/docs/context_AnalysisContext.jsx.html b/client/docs/context_AnalysisContext.jsx.html new file mode 100644 index 0000000..11e18dd --- /dev/null +++ b/client/docs/context_AnalysisContext.jsx.html @@ -0,0 +1,192 @@ + + + + + JSDoc: Source: context/AnalysisContext.jsx + + + + + + + + + + +
+ +

Source: context/AnalysisContext.jsx

+ + + + + + +
+
+
/**
+ * @module AnalysisContext
+ * @description React context for managing code analysis state and operations.
+ * Provides centralized state management for code editor, analysis options, and results.
+ */
+
+import React, { createContext, useState, useContext } from 'react';
+import { analyzeCode as analyzeCodeAPI } from '../services/api/api';
+import PropTypes from 'prop-types';
+
+/**
+ * @type {React.Context}
+ * @description React context for analysis-related state and functions
+ */
+const AnalysisContext = createContext();
+
+/**
+ * @function useAnalysis
+ * @description Custom hook to access the analysis context
+ * @returns {Object} Analysis context value containing state and functions
+ * @throws {Error} When used outside of AnalysisProvider
+ * 
+ * @example
+ * const { code, setCode, analyzeCode } = useAnalysis();
+ */
+export const useAnalysis = () => useContext(AnalysisContext);
+
+/**
+ * @component AnalysisProvider
+ * @description Provider component that manages analysis state and provides context to children
+ * @param {Object} props - Component props
+ * @param {React.ReactNode} props.children - Child components to wrap with context
+ * @returns {JSX.Element} Provider component with analysis context
+ * 
+ * @example
+ * <AnalysisProvider>
+ *   <App />
+ * </AnalysisProvider>
+ */
+export const AnalysisProvider = ({ children }) => {
+    /**
+     * @type {string}
+     * @description The code content in the editor
+     */
+    const [code, setCode] = useState('// Write your C/C++ code here\n#include <stdio.h>\n\nint main() {\n  printf("Hello, CoreTrace!\\n");\n  return 0;\n}');
+
+    /**
+     * @type {string}
+     * @description The filename for the code being analyzed
+     */
+    const [filename, setFilename] = useState('main.c');
+
+    /**
+     * @type {boolean}
+     * @description Loading state for analysis operations
+     */
+    const [loading, setLoading] = useState(false);
+
+    /**
+     * @type {Object|null}
+     * @description Analysis results or null if no analysis has been performed
+     */
+    const [results, setResults] = useState(null);
+
+    /**
+     * @type {Object}
+     * @description Analysis options and configuration
+     * @property {boolean} static - Enable static analysis
+     * @property {boolean} dynamic - Enable dynamic analysis
+     * @property {Array<string>} tools - Selected tools for analysis
+     */
+    const [options, setOptions] = useState({
+        static: true,
+        dynamic: false,
+        tools: ['cppcheck', 'flawfinder']
+    });
+
+    /**
+     * @function handleOptionChange
+     * @description Toggles boolean analysis options (static/dynamic)
+     * @param {string} option - The option to toggle ('static' or 'dynamic')
+     */
+    const handleOptionChange = (option) => {
+        if (option === 'static' || option === 'dynamic') {
+            setOptions({ ...options, [option]: !options[option] });
+        }
+    };
+
+    /**
+     * @function handleToolToggle
+     * @description Toggles the inclusion of a specific tool in analysis options
+     * @param {string} tool - The name of the tool to toggle
+     */
+    const handleToolToggle = (tool) => {
+        const updatedTools = options.tools.includes(tool)
+            ? options.tools.filter(t => t !== tool)
+            : [...options.tools, tool];
+
+        setOptions({ ...options, tools: updatedTools });
+    };
+
+    /**
+     * @function analyzeCode
+     * @description Performs code analysis using the current code, filename, and options
+     * Updates loading state and results accordingly
+     * @async
+     */
+    const analyzeCode = async () => {
+        try {
+            setLoading(true);
+            setResults(null);
+
+            const result = await analyzeCodeAPI(filename, code, options);
+            setResults(result);
+        } catch (error) {
+            console.error('Error analyzing code:', error);
+            setResults({ error: error.message });
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    return (
+        <AnalysisContext.Provider value={{
+            code, setCode,
+            filename, setFilename,
+            loading,
+            results,
+            options,
+            handleOptionChange,
+            handleToolToggle,
+            analyzeCode
+        }}>
+            {children}
+        </AnalysisContext.Provider>
+    );
+};
+
+AnalysisProvider.propTypes = {
+    children: PropTypes.node.isRequired,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/client/docs/fonts/OpenSans-Bold-webfont.eot b/client/docs/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/client/docs/fonts/OpenSans-Bold-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-Bold-webfont.svg b/client/docs/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/client/docs/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-Bold-webfont.woff b/client/docs/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/client/docs/fonts/OpenSans-Bold-webfont.woff differ diff --git a/client/docs/fonts/OpenSans-BoldItalic-webfont.eot b/client/docs/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/client/docs/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-BoldItalic-webfont.svg b/client/docs/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/client/docs/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-BoldItalic-webfont.woff b/client/docs/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/client/docs/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/client/docs/fonts/OpenSans-Italic-webfont.eot b/client/docs/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/client/docs/fonts/OpenSans-Italic-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-Italic-webfont.svg b/client/docs/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/client/docs/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-Italic-webfont.woff b/client/docs/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/client/docs/fonts/OpenSans-Italic-webfont.woff differ diff --git a/client/docs/fonts/OpenSans-Light-webfont.eot b/client/docs/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/client/docs/fonts/OpenSans-Light-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-Light-webfont.svg b/client/docs/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/client/docs/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-Light-webfont.woff b/client/docs/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/client/docs/fonts/OpenSans-Light-webfont.woff differ diff --git a/client/docs/fonts/OpenSans-LightItalic-webfont.eot b/client/docs/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/client/docs/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-LightItalic-webfont.svg b/client/docs/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/client/docs/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-LightItalic-webfont.woff b/client/docs/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/client/docs/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/client/docs/fonts/OpenSans-Regular-webfont.eot b/client/docs/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/client/docs/fonts/OpenSans-Regular-webfont.eot differ diff --git a/client/docs/fonts/OpenSans-Regular-webfont.svg b/client/docs/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/client/docs/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/docs/fonts/OpenSans-Regular-webfont.woff b/client/docs/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/client/docs/fonts/OpenSans-Regular-webfont.woff differ diff --git a/client/docs/index.html b/client/docs/index.html new file mode 100644 index 0000000..807940d --- /dev/null +++ b/client/docs/index.html @@ -0,0 +1,65 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/client/docs/module-AnalysisContext.html b/client/docs/module-AnalysisContext.html new file mode 100644 index 0000000..a2852e2 --- /dev/null +++ b/client/docs/module-AnalysisContext.html @@ -0,0 +1,822 @@ + + + + + JSDoc: Module: AnalysisContext + + + + + + + + + + +
+ +

Module: AnalysisContext

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
React context for managing code analysis state and operations. +Provides centralized state management for code editor, analysis options, and results.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(static, constant) AnalysisProvider

+ + + + +
+ Provider component that manages analysis state and provides context to children +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + +
Example
+ +
<AnalysisProvider>
+  <App />
+</AnalysisProvider>
+ + + + + +

(inner, constant) AnalysisContext :React.Context

+ + + + +
+ React context for analysis-related state and functions +
+ + + +
Type:
+
    +
  • + +React.Context + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async, inner) analyzeCode()

+ + + + + + +
+ Performs code analysis using the current code, filename, and options +Updates loading state and results accordingly +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) handleOptionChange(option)

+ + + + + + +
+ Toggles boolean analysis options (static/dynamic) +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
option + + +string + + + + The option to toggle ('static' or 'dynamic')
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) handleToolToggle(tool)

+ + + + + + +
+ Toggles the inclusion of a specific tool in analysis options +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tool + + +string + + + + The name of the tool to toggle
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) useAnalysis() → {Object}

+ + + + + + +
+ Custom hook to access the analysis context +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When used outside of AnalysisProvider +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Analysis context value containing state and functions +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + +
Example
+ +
const { code, setCode, analyzeCode } = useAnalysis();
+ + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/client/docs/module-ApiService.html b/client/docs/module-ApiService.html new file mode 100644 index 0000000..bf04356 --- /dev/null +++ b/client/docs/module-ApiService.html @@ -0,0 +1,973 @@ + + + + + JSDoc: Module: ApiService + + + + + + + + + + +
+ +

Module: ApiService

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
API service for communicating with the CoreTrace backend server. +Provides functions for code analysis and tool information retrieval.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) API_URL :string

+ + + + +
+ Base URL for the API server, configurable via environment variable +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(inner, constant) api :Object

+ + + + +
+ Axios instance configured for API communication +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
baseURL + + +string + + + + Base URL for all API requests
headers + + +Object + + + + Default headers for API requests
timeout + + +number + + + + Request timeout in milliseconds
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async, inner) analyzeCode(filename, code, options) → {Promise.<Object>}

+ + + + + + +
+ Analyzes the provided code using the specified options. +Sends code and analysis options to the backend server for processing. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
filename + + +string + + + + The name of the file containing the code to analyze
code + + +string + + + + The source code to be analyzed
options + + +Object + + + + The options to customize the analysis process +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
static + + +boolean + + + + + + <optional>
+ + + + + +
Enable static analysis
dynamic + + +boolean + + + + + + <optional>
+ + + + + +
Enable dynamic analysis
tools + + +Array.<string> + + + + + + <optional>
+ + + + + +
Array of tools to use for analysis
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When the analysis fails, with error message from API or default message +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ The analysis result with tool-specific findings +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + +
Example
+ +
const result = await analyzeCode('main.c', '#include <stdio.h>\nint main() { return 0; }', {
+  static: true,
+  dynamic: false,
+  tools: ['flawfinder']
+});
+ + + + + + + + + +

(async, inner) getAvailableTools() → {Promise.<Object>|Object|Array.<string>}

+ + + + + + +
+ Fetches the list of available analysis tools from the server. +Retrieves information about tools that can be used for code analysis. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When the request fails, with error message from server or default message +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+
    +
  • +
    + Promise that resolves to an object containing available tools +
    + + + +
    +
    + Type +
    +
    + +Promise.<Object> + + +
    +
    +
  • + +
  • +
    + tools - Object containing tool information +
    + + + +
    +
    + Type +
    +
    + +Object + + +
    +
    +
  • + +
  • +
    + tools.tools - Array of available tool names +
    + + + +
    +
    + Type +
    +
    + +Array.<string> + + +
    +
    +
  • +
+ + + + +
Example
+ +
const tools = await getAvailableTools();
+// Returns: { tools: ['flawfinder', 'cppcheck', 'clang-tidy'] }
+ + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/client/docs/module-App.html b/client/docs/module-App.html new file mode 100644 index 0000000..caba3af --- /dev/null +++ b/client/docs/module-App.html @@ -0,0 +1,649 @@ + + + + + JSDoc: Module: App + + + + + + + + + + +
+ +

Module: App

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Main application component for the CoreTrace web interface. +Provides a code editor with analysis capabilities and results display.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) App() → {JSX.Element}

+ + + + + + +
+ The main application component that renders the code editor and results pane. +Manages the state for the code editor, analysis results, available tools, and user options. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The rendered App component with code editor and results pane +
+ + + +
+
+ Type +
+
+ +JSX.Element + + +
+
+ + + + + + +
Example
+ +
<App />
+ + + + + + + + + +

(inner) handleAnalyzeCode()

+ + + + + + +
+ Initiates the code analysis process by calling the API +and updates the results state with the analysis findings +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) handleOptionChange(option)

+ + + + + + +
+ Toggles a boolean option (e.g., static or dynamic analysis) +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
option + + +string + + + + The name of the option to toggle
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) handleToolToggle(tool)

+ + + + + + +
+ Toggles the inclusion of a specific tool in the analysis options +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tool + + +string + + + + The name of the tool to toggle
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/client/docs/module-CodeEditor.html b/client/docs/module-CodeEditor.html new file mode 100644 index 0000000..8e0bf40 --- /dev/null +++ b/client/docs/module-CodeEditor.html @@ -0,0 +1,283 @@ + + + + + JSDoc: Module: CodeEditor + + + + + + + + + + +
+ +

Module: CodeEditor

+ + + + + + +
+ +
+ + + + + + + +
+ +
+
+ + +
Monaco Editor wrapper component for code editing functionality. +Provides a rich code editing experience with syntax highlighting and IntelliSense.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(require("CodeEditor"))() → {JSX.Element}

+ + + + + + +
+ A wrapper component for the Monaco Editor with default C++ configuration +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Monaco Editor component with dark theme and C++ language support +
+ + + +
+
+ Type +
+
+ +JSX.Element + + +
+
+ + + + + + +
Example
+ +
<CodeEditor />
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/client/docs/scripts/linenumber.js b/client/docs/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/client/docs/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/client/docs/scripts/prettify/Apache-License-2.0.txt b/client/docs/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/client/docs/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/client/docs/scripts/prettify/lang-css.js b/client/docs/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/client/docs/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/client/docs/scripts/prettify/prettify.js b/client/docs/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/client/docs/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + JSDoc: Source: services/api/api.jsx + + + + + + + + + + +
+ +

Source: services/api/api.jsx

+ + + + + + +
+
+
/**
+ * @module ApiService
+ * @description API service for communicating with the CoreTrace backend server.
+ * Provides functions for code analysis and tool information retrieval.
+ */
+
+import axios from 'axios';
+
+/**
+ * @type {string}
+ * @description Base URL for the API server, configurable via environment variable
+ */
+const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000';
+
+/**
+ * @type {Object}
+ * @description Axios instance configured for API communication
+ * @property {string} baseURL - Base URL for all API requests
+ * @property {Object} headers - Default headers for API requests
+ * @property {number} timeout - Request timeout in milliseconds
+ */
+const api = axios.create({
+    baseURL: API_URL,
+    headers: {
+        'Content-Type': 'application/json',
+    },
+    timeout: 10000 // 10 seconds timeout
+});
+
+/**
+ * @function analyzeCode
+ * @description Analyzes the provided code using the specified options.
+ * Sends code and analysis options to the backend server for processing.
+ * 
+ * @async
+ * @param {string} filename - The name of the file containing the code to analyze
+ * @param {string} code - The source code to be analyzed
+ * @param {Object} options - The options to customize the analysis process
+ * @param {boolean} [options.static] - Enable static analysis
+ * @param {boolean} [options.dynamic] - Enable dynamic analysis
+ * @param {Array<string>} [options.tools] - Array of tools to use for analysis
+ * @returns {Promise<Object>} The analysis result with tool-specific findings
+ * @throws {Error} When the analysis fails, with error message from API or default message
+ * 
+ * @example
+ * const result = await analyzeCode('main.c', '#include <stdio.h>\nint main() { return 0; }', {
+ *   static: true,
+ *   dynamic: false,
+ *   tools: ['flawfinder']
+ * });
+ */
+export const analyzeCode = async (filename, code, options) => {
+    try {
+        const response = await axios.post(`${API_URL}/api/analyze`, {
+            files: { [filename]: code },
+            options
+        });
+        return response.data;
+    } catch (error) {
+        throw new Error(error.response?.data?.error || 'Failed to analyze code');
+    }
+};
+
+/**
+ * @function getAvailableTools
+ * @description Fetches the list of available analysis tools from the server.
+ * Retrieves information about tools that can be used for code analysis.
+ * 
+ * @async
+ * @returns {Promise<Object>} Promise that resolves to an object containing available tools
+ * @returns {Object} tools - Object containing tool information
+ * @returns {Array<string>} tools.tools - Array of available tool names
+ * @throws {Error} When the request fails, with error message from server or default message
+ * 
+ * @example
+ * const tools = await getAvailableTools();
+ * // Returns: { tools: ['flawfinder', 'cppcheck', 'clang-tidy'] }
+ */
+export const getAvailableTools = async () => {
+    try {
+        const response = await api.get('/api/tools');
+        return response.data;
+    } catch (error) {
+        throw new Error(error.response?.data?.error || 'Failed to retrieve tools');
+    }
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 09:18:55 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/client/docs/styles/jsdoc-default.css b/client/docs/styles/jsdoc-default.css new file mode 100644 index 0000000..7d1729d --- /dev/null +++ b/client/docs/styles/jsdoc-default.css @@ -0,0 +1,358 @@ +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html +{ + overflow: auto; + background-color: #fff; + font-size: 14px; +} + +body +{ + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +a, a:visited, a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header +{ + display: block; + padding: 0px 4px; +} + +tt, code, kbd, samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +#main { + float: left; + width: 70%; +} + +article dl { + margin-bottom: 40px; +} + +article img { + max-width: 100%; +} + +section +{ + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav +{ + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav ul a, nav ul a:visited, nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4D4E53; +} + +nav h3 { + margin-top: 12px; +} + +nav li { + margin-top: 6px; +} + +footer { + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; +} + +h1, h2, h3, h4 { + font-weight: 200; + margin: 0; +} + +h1 +{ + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; +} + +h2, h3.subsection-title +{ + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h3 +{ + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; +} + +h4 +{ + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; +} + +h5, .container-overview .subsection-title +{ + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 +{ + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +table +{ + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +td, th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +thead tr +{ + background-color: #ddd; + font-weight: bold; +} + +th { border-right: 1px solid #aaa; } +tr > th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/client/docs/styles/prettify-jsdoc.css b/client/docs/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/client/docs/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/client/docs/styles/prettify-tomorrow.css b/client/docs/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/client/docs/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs index be81d31..99ed830 100644 --- a/client/eslint.config.mjs +++ b/client/eslint.config.mjs @@ -1,11 +1,39 @@ import js from "@eslint/js"; import globals from "globals"; import pluginReact from "eslint-plugin-react"; -import { defineConfig } from "eslint/config"; +import babelParser from "@babel/eslint-parser"; - -export default defineConfig([ - { files: ["**/*.{js,mjs,cjs,jsx}"], plugins: { js }, extends: ["js/recommended"] }, - { files: ["**/*.{js,mjs,cjs,jsx}"], languageOptions: { globals: globals.browser } }, - pluginReact.configs.flat.recommended, -]); \ No newline at end of file +export default [ + { + files: ["**/*.{js,mjs,cjs,jsx}"], + ignores: ["docs/**"], + languageOptions: { + parser: babelParser, + parserOptions: { + requireConfigFile: false, + babelOptions: { + presets: ["@babel/preset-react"], + }, + ecmaVersion: 2021, + sourceType: "module", + ecmaFeatures: { jsx: true }, + }, + globals: { + ...globals.browser, + ...globals.node, + }, + }, + plugins: { + react: pluginReact, + }, + rules: { + ...js.configs.recommended.rules, + ...pluginReact.configs.recommended.rules, + }, + settings: { + react: { + version: "detect", + }, + }, + }, +]; diff --git a/client/jest.config.js b/client/jest.config.js new file mode 100644 index 0000000..f8a4371 --- /dev/null +++ b/client/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + preset: 'react-scripts', + testEnvironment: 'jsdom', + transformIgnorePatterns: [ + "node_modules/(?!(axios|react-router|@remix-run)/)" + ], + moduleNameMapper: { + '^axios$': '/node_modules/axios/dist/axios.js' + } +}; \ No newline at end of file diff --git a/client/jsdoc.json b/client/jsdoc.json new file mode 100644 index 0000000..170e9f2 --- /dev/null +++ b/client/jsdoc.json @@ -0,0 +1,11 @@ +{ + "source": { + "include": ["src/"], + "exclude": ["node_modules"] + }, + "opts": { + "destination": "./docs", + "recurse": true, + "template": "node_modules/jsdoc/templates/default" + } +} diff --git a/client/package-lock.json b/client/package-lock.json index c4d1384..2745cd7 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,18 +11,20 @@ "@monaco-editor/react": "^4.7.0", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^13.5.0", + "@testing-library/react": "^14.2.1", + "@testing-library/user-event": "^14.5.2", "axios": "^1.9.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router-dom": "^7.5.2", + "jsdoc": "^4.0.4", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", "react-syntax-highlighter": "^15.6.1", "socket.io-client": "^4.8.1", "web-vitals": "^2.1.4" }, "devDependencies": { + "@babel/eslint-parser": "^7.28.0", "@eslint/js": "^9.25.1", "@tailwindcss/postcss": "^4.1.5", "autoprefixer": "^10.4.15", @@ -118,10 +120,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.1.tgz", - "integrity": "sha512-q8rjOuadH0V6Zo4XLMkJ3RMQ9MSBqwaDByyYB0izsYdaIWGNLmEblbCOf1vyFHICcg16CD7Fsi51vcQnYxmt6Q==", - "license": "MIT", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.0.tgz", + "integrity": "sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -3026,6 +3027,18 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -3179,6 +3192,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3572,32 +3593,32 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.6.tgz", - "integrity": "sha512-ed6zQbgmKsjsVvodAS1q1Ld2BolEuxJOSyyNc+vhkjdmfNUDCmQnlXBfQkHrlzNmslxHsQU/bFmzcEbv4xXsLg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.7.tgz", + "integrity": "sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", - "lightningcss": "1.29.2", + "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", - "tailwindcss": "4.1.6" + "tailwindcss": "4.1.7" } }, "node_modules/@tailwindcss/node/node_modules/tailwindcss": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.6.tgz", - "integrity": "sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz", + "integrity": "sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==", "dev": true, "license": "MIT" }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.6.tgz", - "integrity": "sha512-0bpEBQiGx+227fW4G0fLQ8vuvyy5rsB1YIYNapTq3aRsJ9taF3f5cCaovDjN5pUGKKzcpMrZst/mhNaKAPOHOA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.7.tgz", + "integrity": "sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3609,24 +3630,24 @@ "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.6", - "@tailwindcss/oxide-darwin-arm64": "4.1.6", - "@tailwindcss/oxide-darwin-x64": "4.1.6", - "@tailwindcss/oxide-freebsd-x64": "4.1.6", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.6", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.6", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.6", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.6", - "@tailwindcss/oxide-linux-x64-musl": "4.1.6", - "@tailwindcss/oxide-wasm32-wasi": "4.1.6", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.6", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.6" + "@tailwindcss/oxide-android-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-arm64": "4.1.7", + "@tailwindcss/oxide-darwin-x64": "4.1.7", + "@tailwindcss/oxide-freebsd-x64": "4.1.7", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.7", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.7", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.7", + "@tailwindcss/oxide-linux-x64-musl": "4.1.7", + "@tailwindcss/oxide-wasm32-wasi": "4.1.7", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.7", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.7" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.6.tgz", - "integrity": "sha512-VHwwPiwXtdIvOvqT/0/FLH/pizTVu78FOnI9jQo64kSAikFSZT7K4pjyzoDpSMaveJTGyAKvDjuhxJxKfmvjiQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.7.tgz", + "integrity": "sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg==", "cpu": [ "arm64" ], @@ -3641,9 +3662,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.6.tgz", - "integrity": "sha512-weINOCcqv1HVBIGptNrk7c6lWgSFFiQMcCpKM4tnVi5x8OY2v1FrV76jwLukfT6pL1hyajc06tyVmZFYXoxvhQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.7.tgz", + "integrity": "sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg==", "cpu": [ "arm64" ], @@ -3658,9 +3679,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.6.tgz", - "integrity": "sha512-3FzekhHG0ww1zQjQ1lPoq0wPrAIVXAbUkWdWM8u5BnYFZgb9ja5ejBqyTgjpo5mfy0hFOoMnMuVDI+7CXhXZaQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.7.tgz", + "integrity": "sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw==", "cpu": [ "x64" ], @@ -3675,9 +3696,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.6.tgz", - "integrity": "sha512-4m5F5lpkBZhVQJq53oe5XgJ+aFYWdrgkMwViHjRsES3KEu2m1udR21B1I77RUqie0ZYNscFzY1v9aDssMBZ/1w==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.7.tgz", + "integrity": "sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw==", "cpu": [ "x64" ], @@ -3692,9 +3713,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.6.tgz", - "integrity": "sha512-qU0rHnA9P/ZoaDKouU1oGPxPWzDKtIfX7eOGi5jOWJKdxieUJdVV+CxWZOpDWlYTd4N3sFQvcnVLJWJ1cLP5TA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.7.tgz", + "integrity": "sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g==", "cpu": [ "arm" ], @@ -3709,9 +3730,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.6.tgz", - "integrity": "sha512-jXy3TSTrbfgyd3UxPQeXC3wm8DAgmigzar99Km9Sf6L2OFfn/k+u3VqmpgHQw5QNfCpPe43em6Q7V76Wx7ogIQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.7.tgz", + "integrity": "sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA==", "cpu": [ "arm64" ], @@ -3726,9 +3747,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.6.tgz", - "integrity": "sha512-8kjivE5xW0qAQ9HX9reVFmZj3t+VmljDLVRJpVBEoTR+3bKMnvC7iLcoSGNIUJGOZy1mLVq7x/gerVg0T+IsYw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.7.tgz", + "integrity": "sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==", "cpu": [ "arm64" ], @@ -3743,9 +3764,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.6.tgz", - "integrity": "sha512-A4spQhwnWVpjWDLXnOW9PSinO2PTKJQNRmL/aIl2U/O+RARls8doDfs6R41+DAXK0ccacvRyDpR46aVQJJCoCg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.7.tgz", + "integrity": "sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==", "cpu": [ "x64" ], @@ -3760,9 +3781,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.6.tgz", - "integrity": "sha512-YRee+6ZqdzgiQAHVSLfl3RYmqeeaWVCk796MhXhLQu2kJu2COHBkqlqsqKYx3p8Hmk5pGCQd2jTAoMWWFeyG2A==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.7.tgz", + "integrity": "sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==", "cpu": [ "x64" ], @@ -3777,9 +3798,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.6.tgz", - "integrity": "sha512-qAp4ooTYrBQ5pk5jgg54/U1rCJ/9FLYOkkQ/nTE+bVMseMfB6O7J8zb19YTpWuu4UdfRf5zzOrNKfl6T64MNrQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.7.tgz", + "integrity": "sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -3807,9 +3828,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.6.tgz", - "integrity": "sha512-nqpDWk0Xr8ELO/nfRUDjk1pc9wDJ3ObeDdNMHLaymc4PJBWj11gdPCWZFKSK2AVKjJQC7J2EfmSmf47GN7OuLg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.7.tgz", + "integrity": "sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw==", "cpu": [ "arm64" ], @@ -3824,9 +3845,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.6.tgz", - "integrity": "sha512-5k9xF33xkfKpo9wCvYcegQ21VwIBU1/qEbYlVukfEIyQbEA47uK8AAwS7NVjNE3vHzcmxMYwd0l6L4pPjjm1rQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.7.tgz", + "integrity": "sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ==", "cpu": [ "x64" ], @@ -3841,23 +3862,23 @@ } }, "node_modules/@tailwindcss/postcss": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.6.tgz", - "integrity": "sha512-ELq+gDMBuRXPJlpE3PEen+1MhnHAQQrh2zF0dI1NXOlEWfr2qWf2CQdr5jl9yANv8RErQaQ2l6nIFO9OSCVq/g==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.7.tgz", + "integrity": "sha512-88g3qmNZn7jDgrrcp3ZXEQfp9CVox7xjP1HN2TFKI03CltPVd/c61ydn5qJJL8FYunn0OqBaW5HNUga0kmPVvw==", "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.6", - "@tailwindcss/oxide": "4.1.6", + "@tailwindcss/node": "4.1.7", + "@tailwindcss/oxide": "4.1.7", "postcss": "^8.4.41", - "tailwindcss": "4.1.6" + "tailwindcss": "4.1.7" } }, "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.6.tgz", - "integrity": "sha512-j0cGLTreM6u4OWzBeLBpycK0WIh8w7kSwcUsQZoGLHZ7xDTdM69lN64AgoIEEwFi0tnhs4wSykUa5YWxAzgFYg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz", + "integrity": "sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==", "dev": true, "license": "MIT" }, @@ -3920,42 +3941,54 @@ "license": "MIT" }, "node_modules/@testing-library/react": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", - "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", - "license": "MIT", + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz", + "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==", "dependencies": { - "@babel/runtime": "^7.12.5" + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^9.0.0", + "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=18" + "node": ">=14" }, "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", - "license": "MIT", + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", "dependencies": { - "@babel/runtime": "^7.12.5" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=10", + "node": ">=14" + } + }, + "node_modules/@testing-library/react/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "engines": { + "node": ">=12", "npm": ">=6" }, "peerDependencies": { @@ -4201,6 +4234,28 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -4237,6 +4292,12 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", "license": "MIT" }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "peer": true + }, "node_modules/@types/q": { "version": "1.5.8", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", @@ -4255,6 +4316,24 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, + "node_modules/@types/react": { + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -5988,6 +6067,18 @@ "node": ">=4" } }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6423,15 +6514,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, - "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -6905,6 +6987,12 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "license": "MIT" }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "peer": true + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -7005,6 +7093,37 @@ "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "license": "MIT" }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -7391,9 +7510,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.154", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.154.tgz", - "integrity": "sha512-G4VCFAyKbp1QJ+sWdXYIRYsPGvlV5sDACfCmoMFog3rjm1syLhI41WXm/swZypwCIWIm4IFLWzHY14joWMQ5Fw==", + "version": "1.5.155", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.155.tgz", + "integrity": "sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==", "license": "ISC" }, "node_modules/emittery": { @@ -7621,6 +7740,25 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-iterator-helpers": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", @@ -9911,6 +10049,21 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -11545,6 +11698,71 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdoc/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsdoc/node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -11737,6 +11955,15 @@ "node": ">=0.10.0" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -11806,9 +12033,9 @@ } }, "node_modules/lightningcss": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", - "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -11822,22 +12049,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.29.2", - "lightningcss-darwin-x64": "1.29.2", - "lightningcss-freebsd-x64": "1.29.2", - "lightningcss-linux-arm-gnueabihf": "1.29.2", - "lightningcss-linux-arm64-gnu": "1.29.2", - "lightningcss-linux-arm64-musl": "1.29.2", - "lightningcss-linux-x64-gnu": "1.29.2", - "lightningcss-linux-x64-musl": "1.29.2", - "lightningcss-win32-arm64-msvc": "1.29.2", - "lightningcss-win32-x64-msvc": "1.29.2" + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", - "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", "cpu": [ "arm64" ], @@ -11856,9 +12083,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", - "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", "cpu": [ "x64" ], @@ -11877,9 +12104,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", - "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", "cpu": [ "x64" ], @@ -11898,9 +12125,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", - "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", "cpu": [ "arm" ], @@ -11919,9 +12146,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", - "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", "cpu": [ "arm64" ], @@ -11940,9 +12167,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", - "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", "cpu": [ "arm64" ], @@ -11961,9 +12188,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", - "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", "cpu": [ "x64" ], @@ -11982,9 +12209,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", - "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", "cpu": [ "x64" ], @@ -12003,9 +12230,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", - "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", "cpu": [ "arm64" ], @@ -12024,9 +12251,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", - "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", "cpu": [ "x64" ], @@ -12059,6 +12286,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -12219,6 +12455,57 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "license": "Unlicense", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -12234,6 +12521,12 @@ "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", "license": "CC0-1.0" }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -12636,6 +12929,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -13805,15 +14113,15 @@ } }, "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "node_modules/postcss-loader": { @@ -14763,6 +15071,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -14870,10 +15187,12 @@ } }, "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", - "license": "MIT", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } @@ -14940,15 +15259,15 @@ } }, "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", - "license": "MIT", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { - "scheduler": "^0.26.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.1.0" + "react": "^18.3.1" } }, "node_modules/react-error-overlay": { @@ -14973,41 +15292,33 @@ } }, "node_modules/react-router": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", - "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", - "license": "MIT", + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", + "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "@remix-run/router": "1.23.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.0.tgz", - "integrity": "sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==", - "license": "MIT", + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", + "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", "dependencies": { - "react-router": "7.6.0" + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-scripts": { @@ -15378,6 +15689,15 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "license": "MIT" }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -15753,10 +16073,12 @@ } }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/schema-utils": { "version": "4.3.2", @@ -15989,12 +16311,6 @@ "node": ">= 0.8.0" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -16511,6 +16827,18 @@ "node": ">= 0.8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -17300,13 +17628,13 @@ } }, "node_modules/terser": { - "version": "5.39.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.1.tgz", - "integrity": "sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==", + "version": "5.39.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.2.tgz", + "integrity": "sha512-yEPUmWve+VA78bI71BW70Dh0TuV4HHd+I5SHOAfS1+QBOmvmCiiffgjR8ryyEd3KIfvPGFqoADt8LdQ6XpXIvg==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -17687,6 +18015,12 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -18801,6 +19135,12 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "license": "MIT" }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "license": "Apache-2.0" + }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", diff --git a/client/package.json b/client/package.json index 281eccb..e0c107d 100644 --- a/client/package.json +++ b/client/package.json @@ -6,12 +6,13 @@ "@monaco-editor/react": "^4.7.0", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^13.5.0", + "@testing-library/react": "^14.2.1", + "@testing-library/user-event": "^14.5.2", "axios": "^1.9.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-router-dom": "^7.5.2", + "jsdoc": "^4.0.4", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", "react-syntax-highlighter": "^15.6.1", "socket.io-client": "^4.8.1", @@ -19,7 +20,7 @@ }, "scripts": { "start": "react-scripts start", - "build": "react-scripts build", + "build": "CI=false react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "lint": "eslint .", @@ -44,6 +45,7 @@ ] }, "devDependencies": { + "@babel/eslint-parser": "^7.28.0", "@eslint/js": "^9.25.1", "@tailwindcss/postcss": "^4.1.5", "autoprefixer": "^10.4.15", diff --git a/client/src/App.jsx b/client/src/App.jsx index f46224f..b9411fe 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,56 +1,82 @@ +/** + * @module App + * @description Main application component for the CoreTrace web interface. + * Provides a code editor with analysis capabilities and results display. + */ + import React, { useState, useEffect } from 'react'; import CodeEditorPane from './components/Editor/CodeEditorPane'; import ResultsPane from './components/Editor/ResultsPane'; -import Divider from './components/Editor/Divider'; import { analyzeCode as analyzeCodeAPI, getAvailableTools } from './services/api/api'; /** - * The main application component that renders the code editor and results pane. - * It manages the state for the code editor, analysis results, available tools, and user options. - * - * @component - * @returns {JSX.Element} The rendered App component. - * + * @component App + * @description The main application component that renders the code editor and results pane. + * Manages the state for the code editor, analysis results, available tools, and user options. + * + * @returns {JSX.Element} The rendered App component with code editor and results pane + * * @example * - * - * @state {string} code - The code entered by the user in the editor. - * @state {object|null} results - The results of the code analysis or null if no analysis has been performed. - * @state {boolean} loading - Indicates whether the code analysis is in progress. - * @state {number} dividerPosition - The percentage width of the left pane (code editor). - * @state {string} filename - The name of the file being analyzed. - * @state {object} options - The user-selected options for code analysis, including static/dynamic analysis and selected tools. - * @state {object} availableTools - The list of tools available for analysis. - * - * @effect Fetches the list of available tools when the component mounts and updates the state accordingly. - * - * @function handleOptionChange - Toggles a boolean option (e.g., static or dynamic analysis). - * @param {string} option - The name of the option to toggle. - * - * @function handleToolToggle - Toggles the inclusion of a specific tool in the analysis options. - * @param {string} tool - The name of the tool to toggle. - * - * @function handleAnalyzeCode - Initiates the code analysis process by calling an API and updates the results state. - * - * @function handleMouseDown - Handles the mouse down event for resizing the divider between the panes. - * @param {MouseEvent} e - The mouse down event. */ function App() { + /** + * @type {string} + * @description The code entered by the user in the editor + */ const [code, setCode] = useState('// Write your code here\n#include \n\nint main(void)\n{\n printf("Hello, World !\\n");\n return 0;\n}'); + + /** + * @type {Object|null} + * @description The results of the code analysis or null if no analysis has been performed + */ const [results, setResults] = useState(null); + + /** + * @type {boolean} + * @description Indicates whether the code analysis is in progress + */ const [loading, setLoading] = useState(false); - const [dividerPosition, setDividerPosition] = useState(50); // Percentage width of the left pane + + /** + * @type {number} + * @description The percentage width of the left pane (code editor) + */ + let dividerPosition = 50; + + /** + * @type {string} + * @description The name of the file being analyzed + */ const [filename, setFilename] = useState('main.cpp'); + + /** + * @type {Object} + * @description The user-selected options for code analysis + * @property {boolean} static - Enable static analysis + * @property {boolean} dynamic - Enable dynamic analysis + * @property {Array} tools - Selected tools for analysis + */ const [options, setOptions] = useState({ static: true, dynamic: false, tools: [], }); + /** + * @type {Object} + * @description The list of tools available for analysis + * @property {Array} tools - Array of available tool names + */ const [availableTools, setAvailableTools] = useState({ tools: [], }); + /** + * @effect + * @description Fetches the list of available tools when the component mounts + * and updates the state accordingly. Sets default options to include all tools. + */ useEffect(() => { const fetchTools = async () => { try { @@ -67,10 +93,20 @@ function App() { fetchTools(); }, []); + /** + * @function handleOptionChange + * @description Toggles a boolean option (e.g., static or dynamic analysis) + * @param {string} option - The name of the option to toggle + */ const handleOptionChange = (option) => { setOptions((prev) => ({ ...prev, [option]: !prev[option] })); }; + /** + * @function handleToolToggle + * @description Toggles the inclusion of a specific tool in the analysis options + * @param {string} tool - The name of the tool to toggle + */ const handleToolToggle = (tool) => { setOptions((prev) => ({ ...prev, @@ -80,6 +116,11 @@ function App() { })); }; + /** + * @function handleAnalyzeCode + * @description Initiates the code analysis process by calling the API + * and updates the results state with the analysis findings + */ const handleAnalyzeCode = async () => { try { setLoading(true); @@ -95,28 +136,6 @@ function App() { } }; - const handleMouseDown = (e) => { - e.preventDefault(); - const startX = e.clientX; - - const handleMouseMove = (moveEvent) => { - const deltaX = moveEvent.clientX - startX; - const newDividerPosition = Math.min( - Math.max(dividerPosition + (deltaX / window.innerWidth) * 100, 20), - 80 - ); - setDividerPosition(newDividerPosition); - }; - - const handleMouseUp = () => { - document.removeEventListener('mousemove', handleMouseMove); - document.removeEventListener('mouseup', handleMouseUp); - }; - - document.addEventListener('mousemove', handleMouseMove); - document.addEventListener('mouseup', handleMouseUp); - }; - return (
{ - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/client/src/components/Editor/CodeEditor.jsx b/client/src/components/Editor/CodeEditor.jsx index d1e0398..68e5e54 100644 --- a/client/src/components/Editor/CodeEditor.jsx +++ b/client/src/components/Editor/CodeEditor.jsx @@ -1,19 +1,25 @@ -import React, { useState } from 'react'; +/** + * @module CodeEditor + * @description Monaco Editor-based code editor component for C/C++ code editing. + */ + +import React from 'react'; +import PropTypes from 'prop-types'; import Editor from '@monaco-editor/react'; +/** + * @component CodeEditor + * @description Code editor component using Monaco Editor for C/C++ code. + * @param {Object} props - Component props + * @param {string} props.code - The code to display and edit + * @param {function} props.setCode - Setter for code value + * @returns {JSX.Element} Code editor panel + */ function CodeEditor({ code, setCode, - filename, - setFilename, - options, - handleOptionChange, - handleToolToggle, - analyzeCode, - loading, - results }) { - const [isResultsCollapsed, setIsResultsCollapsed] = useState(false); + // const [isResultsCollapsed, setIsResultsCollapsed] = useState(false); return (
@@ -45,7 +51,7 @@ function CodeEditor({

Results

- {!isResultsCollapsed && ( + {/* {!isResultsCollapsed && (
{loading ? (
@@ -61,10 +67,20 @@ function CodeEditor({
)}
- )} + )} */}
); } +CodeEditor.propTypes = { + code: PropTypes.string.isRequired, + setCode: PropTypes.func.isRequired, + loading: PropTypes.bool, + results: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object + ]) +}; + export default CodeEditor; \ No newline at end of file diff --git a/client/src/components/Editor/CodeEditorPane.jsx b/client/src/components/Editor/CodeEditorPane.jsx index 1dbb075..e234f2b 100644 --- a/client/src/components/Editor/CodeEditorPane.jsx +++ b/client/src/components/Editor/CodeEditorPane.jsx @@ -1,15 +1,39 @@ +/** + * @module CodeEditorPane + * @description Pane component for code editing, file open/save, and filename input. + */ + import React, { useRef } from 'react'; +import PropTypes from 'prop-types'; import Editor from '@monaco-editor/react'; +/** + * @component CodeEditorPane + * @description Pane for code editing, file open/save, and filename input. + * @param {Object} props - Component props + * @param {string} props.code - The code to display and edit + * @param {function} props.setCode - Setter for code value + * @param {number} props.dividerPosition - Width of the divider (percentage) + * @param {string} props.filename - Name of the file being edited + * @param {function} props.setFilename - Setter for filename + * @returns {JSX.Element} Code editor pane + */ function CodeEditorPane({ code, setCode, dividerPosition, filename, setFilename }) { const fileInputRef = useRef(null); - // Open file handler + /** + * @function handleOpenClick + * @description Triggers the file input dialog for opening a file + */ const handleOpenClick = () => { fileInputRef.current.click(); }; - // Read file and set code + /** + * @function handleFileChange + * @description Reads the selected file and sets the code content + * @param {Event} e - File input change event + */ const handleFileChange = (e) => { const file = e.target.files[0]; if (file && (file.name.endsWith('.c') || file.name.endsWith('.cpp'))) { @@ -24,7 +48,10 @@ function CodeEditorPane({ code, setCode, dividerPosition, filename, setFilename e.target.value = ''; }; - // Save file handler + /** + * @function handleSaveClick + * @description Saves the current code to a file with the specified filename + */ const handleSaveClick = () => { const blob = new Blob([code], { type: 'text/plain' }); const url = URL.createObjectURL(blob); @@ -92,4 +119,17 @@ function CodeEditorPane({ code, setCode, dividerPosition, filename, setFilename ); } +CodeEditorPane.propTypes = { + code: PropTypes.string.isRequired, + setCode: PropTypes.func.isRequired, + dividerPosition: PropTypes.number.isRequired, + setFilename: PropTypes.func.isRequired, + filename: PropTypes.string, + results: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.object + ]) +}; + + export default CodeEditorPane; \ No newline at end of file diff --git a/client/src/components/Editor/Divider.jsx b/client/src/components/Editor/Divider.jsx index 8a21a68..4cce0d4 100644 --- a/client/src/components/Editor/Divider.jsx +++ b/client/src/components/Editor/Divider.jsx @@ -1,5 +1,18 @@ +/** + * @module Divider + * @description Divider component for resizing panes in the editor layout. + */ + import React from 'react'; +import PropTypes from 'prop-types'; +/** + * @component Divider + * @description Vertical divider for resizing panes. Triggers a callback on mouse down. + * @param {Object} props - Component props + * @param {function} props.handleMouseDown - Callback for mouse down event + * @returns {JSX.Element} Divider element + */ function Divider({ handleMouseDown }) { return (
+ */ export default function CodeEditor() { return (
diff --git a/client/src/components/Editor/Results.jsx b/client/src/components/Editor/Results.jsx index c512ec9..6a8d614 100644 --- a/client/src/components/Editor/Results.jsx +++ b/client/src/components/Editor/Results.jsx @@ -1,8 +1,29 @@ +/** + * @module ResultsDisplay + * @description Displays analysis results, findings, and errors for selected tools. + */ + import React, { useEffect, useMemo, useState } from 'react'; import EditorToolbar from './Toolbar'; import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs'; +import PropTypes from 'prop-types'; +/** + * @component ResultsDisplay + * @description Displays findings and errors for selected analysis tools. + * @param {Object} props - Component props + * @param {Array|Object} props.results - Analysis results or error object + * @param {boolean} props.loading - Loading state + * @param {string} props.filename - Name of the analyzed file + * @param {Array} props.availableTools - List of available tools + * @param {function} props.setFilename - Setter for filename + * @param {Object} props.options - Analysis options + * @param {function} props.handleOptionChange - Handler for toggling options + * @param {function} props.handleToolToggle - Handler for toggling tools + * @param {function} props.analyzeCode - Handler to trigger analysis + * @returns {JSX.Element} Results display panel + */ function ResultsDisplay({ results, loading, @@ -14,18 +35,35 @@ function ResultsDisplay({ handleToolToggle, analyzeCode, }) { - // Set default selected option to "All" or first tool if available + /** + * @type {string} + * @description Currently selected tool for displaying findings + */ const [selectedTool, setSelectedTool] = useState("All"); - // Get tool names from results + /** + * @function toolNames + * @description Extracts tool names from results + * @returns {Array} List of tool names + */ const toolNames = useMemo(() => { if (!results || !Array.isArray(results)) return []; return results.map(r => r.tool); }, [results]); + /** + * @function displayOptions + * @description List of tool options for selection + * @returns {Array} List of display options + */ const displayOptions = useMemo(() => ["All", ...toolNames], [toolNames]); - // Get findings for the selected tool + /** + * @function getResultsForTool + * @description Gets findings for the selected tool + * @param {string} tool - Tool name or "All" + * @returns {Array} List of findings + */ const getResultsForTool = (tool) => { if (!results || !Array.isArray(results)) return []; if (tool === "All") { @@ -45,7 +83,11 @@ function ResultsDisplay({ } }, [toolNames, selectedTool]); - // Handle button click for an option + /** + * @function handleOptionClick + * @description Handles tool selection button click + * @param {string} option - Tool name or "All" + */ const handleOptionClick = (option) => { setSelectedTool(option); if (handleOptionChange) { @@ -162,4 +204,19 @@ function ResultsDisplay({ ); } +ResultsDisplay.propTypes = { + results: PropTypes.oneOfType([ + PropTypes.array, // parsed results array + PropTypes.object, // error object, etc. + ]), + loading: PropTypes.bool, + filename: PropTypes.string, + availableTools: PropTypes.array, + setFilename: PropTypes.func, + options: PropTypes.object, + handleOptionChange: PropTypes.func, + handleToolToggle: PropTypes.func, + analyzeCode: PropTypes.func, +}; + export default ResultsDisplay; \ No newline at end of file diff --git a/client/src/components/Editor/ResultsPane.jsx b/client/src/components/Editor/ResultsPane.jsx index b3634c2..55a861c 100644 --- a/client/src/components/Editor/ResultsPane.jsx +++ b/client/src/components/Editor/ResultsPane.jsx @@ -1,6 +1,28 @@ +/** + * @module ResultsPane + * @description Container for displaying the results panel and findings. + */ + import React from 'react'; import ResultsDisplay from './Results'; +import PropTypes from 'prop-types'; +/** + * @component ResultsPane + * @description Container for the results panel, including findings and errors. + * @param {Object} props - Component props + * @param {Array|Object} props.results - Analysis results or error object + * @param {boolean} props.loading - Loading state + * @param {string} props.filename - Name of the analyzed file + * @param {function} props.setFilename - Setter for filename + * @param {Object} props.options - Analysis options + * @param {Array} props.availableTools - List of available tools + * @param {function} props.handleOptionChange - Handler for toggling options + * @param {function} props.handleToolToggle - Handler for toggling tools + * @param {function} props.analyzeCode - Handler to trigger analysis + * @param {number} props.dividerPosition - Width of the divider (percentage) + * @returns {JSX.Element} Results pane container + */ function ResultsPane({ results, loading, @@ -36,4 +58,20 @@ function ResultsPane({ ); } +ResultsPane.propTypes = { + results: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object, + ]), + loading: PropTypes.bool, + filename: PropTypes.string, + setFilename: PropTypes.func, + options: PropTypes.object, + availableTools: PropTypes.array, + handleOptionChange: PropTypes.func, + handleToolToggle: PropTypes.func, + analyzeCode: PropTypes.func, + dividerPosition: PropTypes.number.isRequired, +}; + export default ResultsPane; \ No newline at end of file diff --git a/client/src/components/Editor/Toolbar.jsx b/client/src/components/Editor/Toolbar.jsx index 2f17e87..586c86a 100644 --- a/client/src/components/Editor/Toolbar.jsx +++ b/client/src/components/Editor/Toolbar.jsx @@ -1,5 +1,25 @@ +/** + * @module EditorToolbar + * @description Toolbar for code editor, providing filename input, analysis options, and tool selection. + */ + import React from 'react'; +import PropTypes from 'prop-types'; +/** + * @component EditorToolbar + * @description Toolbar for the code editor, including filename input, analysis options, and tool selection. + * @param {Object} props - Component props + * @param {string} props.filename - Name of the file being edited + * @param {function} props.setFilename - Setter for filename + * @param {Object} props.options - Analysis options (static, dynamic, tools) + * @param {Object} props.availableTools - Object with array of available tool names + * @param {function} props.handleOptionChange - Handler for toggling static/dynamic options + * @param {function} props.handleToolToggle - Handler for toggling tool selection + * @param {function} props.analyzeCode - Handler to trigger code analysis + * @param {boolean} props.loading - Loading state + * @returns {JSX.Element} Editor toolbar + */ function EditorToolbar({ filename, setFilename, @@ -89,4 +109,21 @@ function EditorToolbar({ ); } +EditorToolbar.propTypes = { + filename: PropTypes.string.isRequired, + setFilename: PropTypes.func.isRequired, + options: PropTypes.shape({ + static: PropTypes.bool, + dynamic: PropTypes.bool, + tools: PropTypes.arrayOf(PropTypes.string) + }).isRequired, + availableTools: PropTypes.shape({ + tools: PropTypes.arrayOf(PropTypes.string) + }), + handleOptionChange: PropTypes.func.isRequired, + handleToolToggle: PropTypes.func.isRequired, + analyzeCode: PropTypes.func.isRequired, + loading: PropTypes.bool +}; + export default EditorToolbar; \ No newline at end of file diff --git a/client/src/context/AnalysisContext.jsx b/client/src/context/AnalysisContext.jsx index b65b305..113d889 100644 --- a/client/src/context/AnalysisContext.jsx +++ b/client/src/context/AnalysisContext.jsx @@ -1,27 +1,96 @@ +/** + * @module AnalysisContext + * @description React context for managing code analysis state and operations. + * Provides centralized state management for code editor, analysis options, and results. + */ + import React, { createContext, useState, useContext } from 'react'; import { analyzeCode as analyzeCodeAPI } from '../services/api/api'; +import PropTypes from 'prop-types'; +/** + * @type {React.Context} + * @description React context for analysis-related state and functions + */ const AnalysisContext = createContext(); +/** + * @function useAnalysis + * @description Custom hook to access the analysis context + * @returns {Object} Analysis context value containing state and functions + * @throws {Error} When used outside of AnalysisProvider + * + * @example + * const { code, setCode, analyzeCode } = useAnalysis(); + */ export const useAnalysis = () => useContext(AnalysisContext); +/** + * @component AnalysisProvider + * @description Provider component that manages analysis state and provides context to children + * @param {Object} props - Component props + * @param {React.ReactNode} props.children - Child components to wrap with context + * @returns {JSX.Element} Provider component with analysis context + * + * @example + * + * + * + */ export const AnalysisProvider = ({ children }) => { + /** + * @type {string} + * @description The code content in the editor + */ const [code, setCode] = useState('// Write your C/C++ code here\n#include \n\nint main() {\n printf("Hello, CoreTrace!\\n");\n return 0;\n}'); + + /** + * @type {string} + * @description The filename for the code being analyzed + */ const [filename, setFilename] = useState('main.c'); + + /** + * @type {boolean} + * @description Loading state for analysis operations + */ const [loading, setLoading] = useState(false); + + /** + * @type {Object|null} + * @description Analysis results or null if no analysis has been performed + */ const [results, setResults] = useState(null); + + /** + * @type {Object} + * @description Analysis options and configuration + * @property {boolean} static - Enable static analysis + * @property {boolean} dynamic - Enable dynamic analysis + * @property {Array} tools - Selected tools for analysis + */ const [options, setOptions] = useState({ static: true, dynamic: false, tools: ['cppcheck', 'flawfinder'] }); + /** + * @function handleOptionChange + * @description Toggles boolean analysis options (static/dynamic) + * @param {string} option - The option to toggle ('static' or 'dynamic') + */ const handleOptionChange = (option) => { if (option === 'static' || option === 'dynamic') { setOptions({ ...options, [option]: !options[option] }); } }; + /** + * @function handleToolToggle + * @description Toggles the inclusion of a specific tool in analysis options + * @param {string} tool - The name of the tool to toggle + */ const handleToolToggle = (tool) => { const updatedTools = options.tools.includes(tool) ? options.tools.filter(t => t !== tool) @@ -30,6 +99,12 @@ export const AnalysisProvider = ({ children }) => { setOptions({ ...options, tools: updatedTools }); }; + /** + * @function analyzeCode + * @description Performs code analysis using the current code, filename, and options + * Updates loading state and results accordingly + * @async + */ const analyzeCode = async () => { try { setLoading(true); @@ -59,4 +134,8 @@ export const AnalysisProvider = ({ children }) => { {children} ); -}; \ No newline at end of file +}; + +AnalysisProvider.propTypes = { + children: PropTypes.node.isRequired, +}; diff --git a/client/src/services/api/api.jsx b/client/src/services/api/api.jsx index d4a5bd3..659700f 100644 --- a/client/src/services/api/api.jsx +++ b/client/src/services/api/api.jsx @@ -1,7 +1,24 @@ +/** + * @module ApiService + * @description API service for communicating with the CoreTrace backend server. + * Provides functions for code analysis and tool information retrieval. + */ + import axios from 'axios'; +/** + * @type {string} + * @description Base URL for the API server, configurable via environment variable + */ const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000'; +/** + * @type {Object} + * @description Axios instance configured for API communication + * @property {string} baseURL - Base URL for all API requests + * @property {Object} headers - Default headers for API requests + * @property {number} timeout - Request timeout in milliseconds + */ const api = axios.create({ baseURL: API_URL, headers: { @@ -11,15 +28,26 @@ const api = axios.create({ }); /** - * Analyzes the provided code using the specified options. - * - * @async * @function analyzeCode - * @param {string} filename - The name of the file containing the code to analyze. - * @param {string} code - The code to be analyzed. - * @param {Object} options - The options to customize the analysis process. - * @returns {Promise} The analysis result returned from the API. - * @throws {Error} Throws an error if the analysis fails, with the error message from the API or a default message. + * @description Analyzes the provided code using the specified options. + * Sends code and analysis options to the backend server for processing. + * + * @async + * @param {string} filename - The name of the file containing the code to analyze + * @param {string} code - The source code to be analyzed + * @param {Object} options - The options to customize the analysis process + * @param {boolean} [options.static] - Enable static analysis + * @param {boolean} [options.dynamic] - Enable dynamic analysis + * @param {Array} [options.tools] - Array of tools to use for analysis + * @returns {Promise} The analysis result with tool-specific findings + * @throws {Error} When the analysis fails, with error message from API or default message + * + * @example + * const result = await analyzeCode('main.c', '#include \nint main() { return 0; }', { + * static: true, + * dynamic: false, + * tools: ['flawfinder'] + * }); */ export const analyzeCode = async (filename, code, options) => { try { @@ -34,12 +62,19 @@ export const analyzeCode = async (filename, code, options) => { }; /** - * Fetches the list of available tools from the server. - * - * @async * @function getAvailableTools - * @returns {Promise} A promise that resolves to an array of tools. - * @throws {Error} Throws an error if the request fails, with a message from the server or a default message. + * @description Fetches the list of available analysis tools from the server. + * Retrieves information about tools that can be used for code analysis. + * + * @async + * @returns {Promise} Promise that resolves to an object containing available tools + * @returns {Object} tools - Object containing tool information + * @returns {Array} tools.tools - Array of available tool names + * @throws {Error} When the request fails, with error message from server or default message + * + * @example + * const tools = await getAvailableTools(); + * // Returns: { tools: ['flawfinder', 'cppcheck', 'clang-tidy'] } */ export const getAvailableTools = async () => { try { diff --git a/server/.eslintrc.json b/server/.eslintrc.json new file mode 100644 index 0000000..e016735 --- /dev/null +++ b/server/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "env": { + "node": true, + "es2021": true, + "jest": true + }, + "extends": [ + "eslint:recommended", + "airbnb-base" + ], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + "no-console": "off", + "import/no-extraneous-dependencies": ["error", {"devDependencies": true}] + } +} diff --git a/server/API_DOCUMENTATION.md b/server/API_DOCUMENTATION.md new file mode 100644 index 0000000..058ea45 --- /dev/null +++ b/server/API_DOCUMENTATION.md @@ -0,0 +1,335 @@ +# CoreTrace API Documentation + +## Overview + +The CoreTrace API provides endpoints for analyzing C/C++ code using various static and dynamic analysis tools. The API supports file upload, analysis configuration, and result retrieval. + +## Base URL + +``` +http://localhost:5000/api +``` + +## Authentication + +Currently, the API does not require authentication. All endpoints are publicly accessible. + +## Content-Type + +All requests should use `application/json` content type. + +## Endpoints + +### 1. Analyze Code + +**Endpoint:** `POST /api/analyze` + +**Description:** Analyzes uploaded C/C++ code files using configured analysis tools. + +**Request Body:** +```json +{ + "files": { + "filename.c": "#include \nint main() { return 0; }" + }, + "options": { + "static": true, + "dynamic": false, + "tools": ["flawfinder", "cppcheck"] + } +} +``` + +**Parameters:** +- `files` (Object): Key-value pairs where keys are filenames and values are file contents +- `options` (Object, optional): Analysis configuration + - `static` (boolean, optional): Enable static analysis (default: true) + - `dynamic` (boolean, optional): Enable dynamic analysis (default: false) + - `tools` (Array, optional): List of tools to use for analysis + +**Response:** +```json +{ + "tool": "flawfinder", + "results": [ + { + "message": "Buffer overflow vulnerability detected", + "locations": [ + { + "file": "main.c", + "startLine": 10, + "startColumn": 5, + "endColumn": 15, + "snippet": "strcpy(buffer, input);" + } + ] + } + ] +} +``` + +**Error Response:** +```json +{ + "error": "No files provided" +} +``` + +**Status Codes:** +- `200 OK`: Analysis completed successfully +- `400 Bad Request`: Invalid request (missing files, invalid options) +- `500 Internal Server Error`: Analysis failed + +### 2. Get Available Tools + +**Endpoint:** `GET /api/tools` + +**Description:** Retrieves a list of available analysis tools. + +**Request:** No parameters required + +**Response:** +```json +{ + "tools": ["flawfinder", "cppcheck", "clang-tidy"] +} +``` + +**Error Response:** +```json +{ + "error": "Failed to retrieve tools" +} +``` + +**Status Codes:** +- `200 OK`: Tools retrieved successfully +- `500 Internal Server Error`: Failed to retrieve tools + +### 3. Get Examples + +**Endpoint:** `GET /api/examples` + +**Description:** Retrieves a list of available example code snippets. + +**Request:** No parameters required + +**Response:** +```json +[ + { + "id": "buffer-overflow", + "name": "Buffer Overflow Example", + "description": "Demonstrates common buffer overflow vulnerabilities" + } +] +``` + +**Status Codes:** +- `200 OK`: Examples retrieved successfully +- `500 Internal Server Error`: Failed to retrieve examples + +### 4. Get Specific Example + +**Endpoint:** `GET /api/examples/:id` + +**Description:** Retrieves a specific example code snippet by ID. + +**Parameters:** +- `id` (string): The unique identifier of the example + +**Response:** +```json +{ + "id": "buffer-overflow", + "name": "Buffer Overflow Example", + "description": "Demonstrates common buffer overflow vulnerabilities", + "code": "#include \n#include \n\nint main() {\n char buffer[10];\n strcpy(buffer, \"This string is too long\");\n return 0;\n}" +} +``` + +**Error Response:** +```json +{ + "error": "Example not found" +} +``` + +**Status Codes:** +- `200 OK`: Example retrieved successfully +- `404 Not Found`: Example not found +- `500 Internal Server Error`: Failed to retrieve example + +## Data Types + +### Analysis Result + +```typescript +interface AnalysisResult { + tool: string; + results: Finding[]; +} + +interface Finding { + message: string; + locations: Location[]; +} + +interface Location { + file: string; + startLine?: number; + startColumn?: number; + endColumn?: number; + snippet?: string; +} +``` + +### Analysis Options + +```typescript +interface AnalysisOptions { + static?: boolean; + dynamic?: boolean; + tools?: string[]; +} +``` + +## Error Handling + +All endpoints return consistent error responses: + +```json +{ + "error": "Error message describing what went wrong" +} +``` + +Common error scenarios: +- Missing required parameters +- Invalid file formats +- File size limits exceeded +- Analysis tool failures +- Server configuration issues + +## Rate Limiting + +Currently, no rate limiting is implemented. Consider implementing rate limiting for production deployments. + +## File Size Limits + +- Maximum file size: 1MB per file +- Maximum number of files: 10 files per request +- Supported file extensions: `.c`, `.cpp`, `.h`, `.hpp` + +## Sandboxing + +All code analysis is performed in sandboxed environments using: +- Firejail for process isolation +- QEMU for virtualization (when available) +- Resource limits (CPU, memory, file descriptors) + +## Examples + +### JavaScript/Node.js + +```javascript +const axios = require('axios'); + +// Analyze code +const analyzeCode = async () => { + try { + const response = await axios.post('http://localhost:5000/api/analyze', { + files: { + 'main.c': '#include \nint main() { return 0; }' + }, + options: { + static: true, + tools: ['flawfinder'] + } + }); + console.log(response.data); + } catch (error) { + console.error('Analysis failed:', error.response?.data?.error); + } +}; + +// Get available tools +const getTools = async () => { + try { + const response = await axios.get('http://localhost:5000/api/tools'); + console.log(response.data.tools); + } catch (error) { + console.error('Failed to get tools:', error.response?.data?.error); + } +}; +``` + +### Python + +```python +import requests + +# Analyze code +def analyze_code(): + url = 'http://localhost:5000/api/analyze' + data = { + 'files': { + 'main.c': '#include \nint main() { return 0; }' + }, + 'options': { + 'static': True, + 'tools': ['flawfinder'] + } + } + + response = requests.post(url, json=data) + if response.status_code == 200: + print(response.json()) + else: + print(f"Error: {response.json().get('error')}") + +# Get available tools +def get_tools(): + url = 'http://localhost:5000/api/tools' + response = requests.get(url) + if response.status_code == 200: + print(response.json()['tools']) + else: + print(f"Error: {response.json().get('error')}") +``` + +### cURL + +```bash +# Analyze code +curl -X POST http://localhost:5000/api/analyze \ + -H "Content-Type: application/json" \ + -d '{ + "files": { + "main.c": "#include \nint main() { return 0; }" + }, + "options": { + "static": true, + "tools": ["flawfinder"] + } + }' + +# Get available tools +curl http://localhost:5000/api/tools +``` + +## Versioning + +Current API version: v1 + +API versioning is not yet implemented. Future versions may include versioning in the URL path (e.g., `/api/v1/analyze`). + +## Changelog + +### v1.0.0 +- Initial API implementation +- Code analysis endpoint +- Tools information endpoint +- Examples endpoints +- Basic error handling +- Sandboxed execution \ No newline at end of file diff --git a/server/app.js b/server/app.js index 21b02f9..d34ada3 100644 --- a/server/app.js +++ b/server/app.js @@ -1,25 +1,35 @@ +/** + * @module App + * @description Main Express application configuration and middleware setup. + * Configures CORS, JSON parsing, routes, and error handling for the CoreTrace API. + */ + const express = require('express'); const cors = require('cors'); const routes = require('./routes'); + /** - * Middleware for handling errors in the application. + * @module middlewares/errorHandler + * @description Middleware for handling errors in the application. * This middleware should be used to catch and process errors * that occur during the request-response cycle. - * - * @module middlewares/errorHandler */ const errorHandler = require('./middlewares/errorHandler'); +/** + * @type {express.Application} + * @description Express application instance with configured middleware and routes. + */ const app = express(); -// Middleware +// Middleware configuration app.use(cors()); app.use(express.json({ limit: '10mb' })); -// Routes +// Route mounting app.use('/api', routes); -// Error handling middleware +// Error handling middleware (must be last) app.use(errorHandler); module.exports = app; \ No newline at end of file diff --git a/server/config/index.js b/server/config/index.js index 80c2751..33f2657 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -1,15 +1,52 @@ +/** + * @module Config + * @description Application configuration module that centralizes all configuration settings. + * Provides environment-based configuration for server, sandbox, filesystem, jobs, and logging. + */ + const path = require('path'); const os = require('os'); +/** + * @type {Object} + * @description Main configuration object containing all application settings. + * Supports environment variable overrides for flexible deployment configurations. + */ module.exports = { - // Server configuration + /** + * @property {Object} server - Server configuration settings + * @property {number} server.port - HTTP server port, defaults to 5000 + * @property {string} server.host - Server hostname, defaults to 'localhost' + * @property {string} server.env - Environment mode, defaults to 'development' + */ server: { port: process.env.PORT || 5000, host: process.env.HOST || 'localhost', env: process.env.NODE_ENV || 'development' }, - // Sandbox configuration + /** + * @property {Object} sandbox - Sandbox execution configuration + * @property {Object} sandbox.qemu - QEMU virtualization settings + * @property {string} sandbox.qemu.memory - Memory limit in MB + * @property {string} sandbox.qemu.kernel - Kernel path for QEMU + * @property {number} sandbox.qemu.timeout - Execution timeout in milliseconds + * @property {string} sandbox.qemu.preferredMethod - Preferred sandbox method + * @property {string} sandbox.qemu.libRoot - Library root path + * @property {string|null} sandbox.qemu.customLibDir - Custom library directory + * @property {Object} sandbox.limits - Resource limits for sandboxed execution + * @property {number} sandbox.limits.maxFileSize - Maximum file size in bytes + * @property {number} sandbox.limits.maxFiles - Maximum number of files + * @property {number} sandbox.limits.maxProcesses - Maximum number of processes + * @property {number} sandbox.limits.maxOpenFiles - Maximum open files + * @property {number} sandbox.limits.cpuTime - CPU time limit in seconds + * @property {Object} sandbox.nsjail - NSJail sandbox settings + * @property {string} sandbox.nsjail.memory - Memory limit in MB + * @property {number} sandbox.nsjail.timeout - Execution timeout in milliseconds + * @property {string} sandbox.nsjail.preferredMethod - Preferred sandbox method + * @property {string} sandbox.nsjail.libRoot - Library root path + * @property {string|null} sandbox.nsjail.customLibDir - Custom library directory + */ sandbox: { // QEMU configuration qemu: { @@ -37,20 +74,33 @@ module.exports = { } }, - // File system configuration + /** + * @property {Object} filesystem - File system configuration settings + * @property {string} filesystem.tempDir - Temporary directory path + * @property {string} filesystem.workDir - Working directory path for job processing + * @property {Array} filesystem.allowedExtensions - Allowed file extensions for analysis + */ filesystem: { tempDir: path.join(os.tmpdir(), 'coretrace'), workDir: path.join(process.cwd(), 'temp'), allowedExtensions: ['.c', '.cpp', '.h', '.hpp'] }, - // Job management + /** + * @property {Object} jobs - Job management configuration + * @property {number} jobs.cleanupDelay - Delay before job cleanup in milliseconds + * @property {number} jobs.retentionPeriod - Job retention period in milliseconds + */ jobs: { cleanupDelay: 60000, // 1 minute retentionPeriod: 3600000 // 1 hour }, - // Logging configuration + /** + * @property {Object} logging - Logging configuration settings + * @property {string} logging.level - Log level (debug, info, warn, error) + * @property {string} logging.format - Log format (json, simple) + */ logging: { level: process.env.LOG_LEVEL || 'info', format: process.env.LOG_FORMAT || 'json' diff --git a/server/controllers/analyzeControllers.js b/server/controllers/analyzeControllers.js index 7989666..8ce2ba6 100644 --- a/server/controllers/analyzeControllers.js +++ b/server/controllers/analyzeControllers.js @@ -1,6 +1,22 @@ /** - * Module that imports the analyzeCode function from the analyzer service. - * This function is likely used to perform code analysis in the application. + * @module AnalyzeControllers + * @description Controller functions for code analysis operations. + * Handles request processing, validation, and response formatting for analysis endpoints. + */ + +/** + * @function analyze + * @description Controller function for handling code analysis requests. + * Validates input files and options, then delegates to the analyzer service for processing. + * + * @param {Object} req - Express request object + * @param {Object} req.body - Request body containing files and analysis options + * @param {Object} req.body.files - Object with filename-content pairs of files to analyze + * @param {Object} [req.body.options] - Analysis options and configuration + * @param {Object} res - Express response object + * @param {Function} next - Express next middleware function for error handling + * @returns {Object} JSON response with analysis results or error message + * @throws {Error} When analysis fails or validation errors occur */ const { analyzeCode } = require('../services/analyzer'); diff --git a/server/docs/controllers_analyzeControllers.js.html b/server/docs/controllers_analyzeControllers.js.html new file mode 100644 index 0000000..1510f41 --- /dev/null +++ b/server/docs/controllers_analyzeControllers.js.html @@ -0,0 +1,86 @@ + + + + + JSDoc: Source: controllers/analyzeControllers.js + + + + + + + + + + +
+ +

Source: controllers/analyzeControllers.js

+ + + + + + +
+
+
/**
+ * @module AnalyzeControllers
+ * @description Controller functions for code analysis operations.
+ * Handles request processing, validation, and response formatting for analysis endpoints.
+ */
+
+/**
+ * @function analyze
+ * @description Controller function for handling code analysis requests.
+ * Validates input files and options, then delegates to the analyzer service for processing.
+ * 
+ * @param {Object} req - Express request object
+ * @param {Object} req.body - Request body containing files and analysis options
+ * @param {Object} req.body.files - Object with filename-content pairs of files to analyze
+ * @param {Object} [req.body.options] - Analysis options and configuration
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function for error handling
+ * @returns {Object} JSON response with analysis results or error message
+ * @throws {Error} When analysis fails or validation errors occur
+ */
+const { analyzeCode } = require('../services/analyzer');
+
+exports.analyze = async (req, res, next) => {
+  try {
+    const { files, options } = req.body;
+
+    if (!files || Object.keys(files).length === 0) {
+      return res.status(400).json({ error: 'No files provided' });
+    }
+
+    const result = await analyzeCode(files, options || {});
+    res.json(result);
+  } catch (error) {
+    next(error);
+  }
+};
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/fonts/OpenSans-Bold-webfont.eot b/server/docs/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/server/docs/fonts/OpenSans-Bold-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-Bold-webfont.svg b/server/docs/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/server/docs/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-Bold-webfont.woff b/server/docs/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/server/docs/fonts/OpenSans-Bold-webfont.woff differ diff --git a/server/docs/fonts/OpenSans-BoldItalic-webfont.eot b/server/docs/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/server/docs/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-BoldItalic-webfont.svg b/server/docs/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/server/docs/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-BoldItalic-webfont.woff b/server/docs/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/server/docs/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/server/docs/fonts/OpenSans-Italic-webfont.eot b/server/docs/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/server/docs/fonts/OpenSans-Italic-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-Italic-webfont.svg b/server/docs/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/server/docs/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-Italic-webfont.woff b/server/docs/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/server/docs/fonts/OpenSans-Italic-webfont.woff differ diff --git a/server/docs/fonts/OpenSans-Light-webfont.eot b/server/docs/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/server/docs/fonts/OpenSans-Light-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-Light-webfont.svg b/server/docs/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/server/docs/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-Light-webfont.woff b/server/docs/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/server/docs/fonts/OpenSans-Light-webfont.woff differ diff --git a/server/docs/fonts/OpenSans-LightItalic-webfont.eot b/server/docs/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/server/docs/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-LightItalic-webfont.svg b/server/docs/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/server/docs/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-LightItalic-webfont.woff b/server/docs/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/server/docs/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/server/docs/fonts/OpenSans-Regular-webfont.eot b/server/docs/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/server/docs/fonts/OpenSans-Regular-webfont.eot differ diff --git a/server/docs/fonts/OpenSans-Regular-webfont.svg b/server/docs/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/server/docs/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/docs/fonts/OpenSans-Regular-webfont.woff b/server/docs/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/server/docs/fonts/OpenSans-Regular-webfont.woff differ diff --git a/server/docs/global.html b/server/docs/global.html new file mode 100644 index 0000000..16ea043 --- /dev/null +++ b/server/docs/global.html @@ -0,0 +1,629 @@ + + + + + JSDoc: Global + + + + + + + + + + +
+ +

Global

+ + + + + + +
+ +
+ +

+ + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

errorHandler(err, req, res, next) → {void}

+ + + + + + +
+ Middleware function to handle errors in the application. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
err + + +Error + + + + The error object containing details about the error.
req + + +Object + + + + The Express request object.
res + + +Object + + + + The Express response object.
next + + +function + + + + The next middleware function in the stack. + +Logs the error stack trace for debugging purposes and sends an appropriate +JSON response to the client. In non-production environments, the error message +and stack trace are included in the response for easier debugging.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

getExampleCode(id) → {Object|null}

+ + + + + + +
+ Get a specific example by ID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +string + + + + Example ID
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Example object or null if not found +
+ + + +
+
+ Type +
+
+ +Object +| + +null + + +
+
+ + + + + + + + + + + + + +

getExampleList() → {Array}

+ + + + + + +
+ Get a list of all available example code snippets +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of example metadata (without code content) +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/index.html b/server/docs/index.html new file mode 100644 index 0000000..c56f80f --- /dev/null +++ b/server/docs/index.html @@ -0,0 +1,65 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/middlewares_errorHandler.js.html b/server/docs/middlewares_errorHandler.js.html new file mode 100644 index 0000000..ebb6984 --- /dev/null +++ b/server/docs/middlewares_errorHandler.js.html @@ -0,0 +1,86 @@ + + + + + JSDoc: Source: middlewares/errorHandler.js + + + + + + + + + + +
+ +

Source: middlewares/errorHandler.js

+ + + + + + +
+
+
/**
+ * Middleware function to handle errors in the application.
+ *
+ * @param {Error} err - The error object containing details about the error.
+ * @param {Object} req - The Express request object.
+ * @param {Object} res - The Express response object.
+ * @param {Function} next - The next middleware function in the stack.
+ *
+ * Logs the error stack trace for debugging purposes and sends an appropriate
+ * JSON response to the client. In non-production environments, the error message
+ * and stack trace are included in the response for easier debugging.
+ *
+ * @returns {void}
+ */
+const errorHandler = (err, req, res, next) => {
+  console.error(err.stack); // Log the error stack trace for debugging
+
+  // Determine the HTTP status code
+  const statusCode = err.status || 500;
+
+  // Build the error response
+  const response = {
+    error: 'An unexpected error occurred',
+  };
+
+  // Include the error message in non-production environments
+  if (process.env.NODE_ENV !== 'production') {
+    response.message = err.message;
+    response.stack = err.stack;
+  }
+
+  // Send the error response
+  res.status(statusCode).json(response);
+};
+
+module.exports = errorHandler;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/module-AnalyzeControllers.html b/server/docs/module-AnalyzeControllers.html new file mode 100644 index 0000000..6c9b089 --- /dev/null +++ b/server/docs/module-AnalyzeControllers.html @@ -0,0 +1,546 @@ + + + + + JSDoc: Module: AnalyzeControllers + + + + + + + + + + +
+ +

Module: AnalyzeControllers

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Controller functions for code analysis operations. +Handles request processing, validation, and response formatting for analysis endpoints.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) analyze(req, res, next) → {Object}

+ + + + + + +
+ Controller function for handling code analysis requests. +Validates input files and options, then delegates to the analyzer service for processing. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
req + + +Object + + + + Express request object +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
body + + +Object + + + + Request body containing files and analysis options +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
files + + +Object + + + + + + + + + + Object with filename-content pairs of files to analyze
options + + +Object + + + + + + <optional>
+ + + + + +
Analysis options and configuration
+ +
+ +
res + + +Object + + + + Express response object
next + + +function + + + + Express next middleware function for error handling
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When analysis fails or validation errors occur +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ JSON response with analysis results or error message +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-AnalyzeRoutes.html b/server/docs/module-AnalyzeRoutes.html new file mode 100644 index 0000000..3ae4339 --- /dev/null +++ b/server/docs/module-AnalyzeRoutes.html @@ -0,0 +1,242 @@ + + + + + JSDoc: Module: AnalyzeRoutes + + + + + + + + + + +
+ +

Module: AnalyzeRoutes

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Express routes for code analysis functionality. +Handles file upload, validation, and analysis requests using the analyzer service.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) router :express.Router

+ + + + +
+ Router instance for analysis-related endpoints. +
+ + + +
Type:
+
    +
  • + +express.Router + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-Analyzer-Analyzer.html b/server/docs/module-Analyzer-Analyzer.html new file mode 100644 index 0000000..8b4f80f --- /dev/null +++ b/server/docs/module-Analyzer-Analyzer.html @@ -0,0 +1,304 @@ + + + + + JSDoc: Class: Analyzer + + + + + + + + + + +
+ +

Class: Analyzer

+ + + + + + +
+ +
+ +

+ Analyzer~Analyzer()

+ + +
+ +
+
+ + + + + + +

new Analyzer()

+ + + + + + +
+ Main analyzer class that orchestrates code analysis using ctrace and flawfinder. +Handles file management, executable path resolution, and result processing. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

+ Analyzer~Analyzer()

+ + +
+ +
+
+ + + + + + +

new Analyzer()

+ + + + + + +
+ Initializes the analyzer with executable paths for ctrace and test binaries. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-Analyzer.html b/server/docs/module-Analyzer.html new file mode 100644 index 0000000..f4285b1 --- /dev/null +++ b/server/docs/module-Analyzer.html @@ -0,0 +1,1398 @@ + + + + + JSDoc: Module: Analyzer + + + + + + + + + + +
+ +

Module: Analyzer

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Core analysis service that handles code analysis using ctrace and flawfinder tools. +Manages file processing, sandbox execution, and result parsing for security analysis.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +

Classes

+ +
+
Analyzer
+
+ +
Analyzer
+
+
+ + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) analyzeCode(files, options) → {Promise.<Object>}

+ + + + + + +
+ Performs comprehensive code analysis on uploaded files using ctrace and flawfinder. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
files + + +Object + + + + Object containing filename-content pairs of files to analyze
options + + +Object + + + + Analysis options including static/dynamic flags +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
static + + +boolean + + + + + + <optional>
+ + + + + +
Enable static analysis
dynamic + + +boolean + + + + + + <optional>
+ + + + + +
Enable dynamic analysis
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When file validation fails or analysis execution errors occur +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Parsed analysis results with tool-specific findings +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) buildArguments(filePaths, options, workDir) → {Array.<string>}

+ + + + + + +
+ Builds command line arguments for the analysis executable based on options and file paths. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
filePaths + + +Array.<string> + + + + Array of file paths to analyze
options + + +Object + + + + Analysis options including static/dynamic flags
workDir + + +string + + + + Working directory path
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of command line arguments +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +

(inner) cleanAnsiCodes(text) → {string}

+ + + + + + +
+ Removes ANSI escape codes from text output for cleaner logging. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +string + + + + Text that may contain ANSI escape codes
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Cleaned text without ANSI codes +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

(inner) getExecutablePath() → {string}

+ + + + + + +
+ Determines the appropriate executable path, falling back to test executable if ctrace is not available. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Path to the executable to use for analysis +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

(inner) runAnalysis(execPath, args, jobId, workDir) → {Promise.<Object>}

+ + + + + + +
+ Executes the analysis in a sandboxed environment and processes the results. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
execPath + + +string + + + + Path to the executable to run
args + + +Array.<string> + + + + Command line arguments for the executable
jobId + + +string + + + + Unique job identifier
workDir + + +string + + + + Working directory path
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Parsed analysis results with tool-specific findings +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) saveFilesToWorkDir(workDir, files) → {Array.<string>}

+ + + + + + +
+ Saves uploaded files to the working directory and sets up flawfinder environment. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
workDir + + +string + + + + Working directory path where files should be saved
files + + +Object + + + + Object containing filename-content pairs
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When flawfinder.py is not found or file operations fail +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Array of saved file paths +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-ExamplesRoutes.html b/server/docs/module-ExamplesRoutes.html new file mode 100644 index 0000000..f05f471 --- /dev/null +++ b/server/docs/module-ExamplesRoutes.html @@ -0,0 +1,242 @@ + + + + + JSDoc: Module: ExamplesRoutes + + + + + + + + + + +
+ +

Module: ExamplesRoutes

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Express routes for example code functionality. +Provides access to predefined code examples for testing and demonstration purposes.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) router :express.Router

+ + + + +
+ Router instance for example-related endpoints. +
+ + + +
Type:
+
    +
  • + +express.Router + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:01 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-JobManager-JobManager.html b/server/docs/module-JobManager-JobManager.html new file mode 100644 index 0000000..a40a730 --- /dev/null +++ b/server/docs/module-JobManager-JobManager.html @@ -0,0 +1,304 @@ + + + + + JSDoc: Class: JobManager + + + + + + + + + + +
+ +

Class: JobManager

+ + + + + + +
+ +
+ +

+ JobManager~JobManager()

+ + +
+ +
+
+ + + + + + +

new JobManager()

+ + + + + + +
+ Handles the complete lifecycle of analysis jobs including creation, tracking, and cleanup. +Maintains job state in memory and manages file system operations for job directories. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

+ JobManager~JobManager()

+ + +
+ +
+
+ + + + + + +

new JobManager()

+ + + + + + +
+ Initializes the job manager with job storage and ensures work directory exists. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-JobManager.html b/server/docs/module-JobManager.html new file mode 100644 index 0000000..d4d954a --- /dev/null +++ b/server/docs/module-JobManager.html @@ -0,0 +1,1395 @@ + + + + + JSDoc: Module: JobManager + + + + + + + + + + +
+ +

Module: JobManager

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Manages analysis jobs including creation, status tracking, validation, and cleanup. +Provides job lifecycle management and file validation for the analysis system.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +

Classes

+ +
+
JobManager
+
+ +
JobManager
+
+
+ + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) cleanupJob(jobId)

+ + + + + + +
+ Performs cleanup operations for a job including file removal and memory cleanup. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
jobId + + +string + + + + Unique job identifier to cleanup
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) createJob(files, optionsopt) → {Object}

+ + + + + + +
+ Creates a new analysis job with unique ID and work directory. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
files + + +Object + + + + + + + + + + + + Object containing filename-content pairs of files to analyze
options + + +Object + + + + + + <optional>
+ + + + + +
+ + {} + + Analysis options and configuration
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Job object with id, status, startTime, files, options, and workDir +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(inner) getJob(jobId) → {Object|null}

+ + + + + + +
+ Retrieves a job by its unique identifier. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
jobId + + +string + + + + Unique job identifier
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Job object if found, null otherwise +
+ + + +
+
+ Type +
+
+ +Object +| + +null + + +
+
+ + + + + + + + + + + + + +

(inner) initializeStorage()

+ + + + + + +
+ Ensures the job storage directory exists for file operations. +Creates the work directory if it doesn't exist. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) scheduleCleanup(jobId)

+ + + + + + +
+ Schedules cleanup of a job after a configurable delay. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
jobId + + +string + + + + Unique job identifier to schedule cleanup for
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(inner) updateJobStatus(jobId, status, resultopt, erroropt) → {Object}

+ + + + + + +
+ Updates the status of an existing job and optionally stores results or errors. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
jobId + + +string + + + + + + + + + + + + Unique job identifier
status + + +string + + + + + + + + + + + + New status for the job ('created', 'running', 'completed', 'failed')
result + + +Object + + + + + + <optional>
+ + + + + +
+ + null + + Analysis results to store with the job
error + + +string + + + + + + <optional>
+ + + + + +
+ + null + + Error message if job failed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When job with specified ID is not found +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Updated job object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(inner) validateFiles(files) → {Array.<string>}

+ + + + + + +
+ Validates uploaded files for security, size, and format requirements. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
files + + +Object + + + + Object containing filename-content pairs to validate
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of validation error messages, empty if validation passes +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-Logger.html b/server/docs/module-Logger.html new file mode 100644 index 0000000..7267fd2 --- /dev/null +++ b/server/docs/module-Logger.html @@ -0,0 +1,431 @@ + + + + + JSDoc: Module: Logger + + + + + + + + + + +
+ +

Module: Logger

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Centralized logging service using Winston for structured logging across the application. +Provides console and file-based logging with request tracking capabilities.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) logger :winston.Logger

+ + + + +
+ Winston logger instance configured with console and file transports. +Supports different log levels and formats for development and production environments. +
+ + + +
Type:
+
    +
  • + +winston.Logger + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(inner) requestLogger(req, res, next)

+ + + + + + +
+ Express middleware for logging incoming HTTP requests with request ID tracking. +Adds request ID to the request object and logs request details for debugging and monitoring. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
req + + +Object + + + + Express request object
res + + +Object + + + + Express response object
next + + +function + + + + Express next middleware function
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-Routes.html b/server/docs/module-Routes.html new file mode 100644 index 0000000..4d5b91c --- /dev/null +++ b/server/docs/module-Routes.html @@ -0,0 +1,242 @@ + + + + + JSDoc: Module: Routes + + + + + + + + + + +
+ +

Module: Routes

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Main router configuration that mounts all application routes. +Centralizes route organization and provides a single entry point for all API endpoints.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) router :express.Router

+ + + + +
+ Express router instance that mounts all application routes. +
+ + + +
Type:
+
    +
  • + +express.Router + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-Sandbox.html b/server/docs/module-Sandbox.html new file mode 100644 index 0000000..59e2f03 --- /dev/null +++ b/server/docs/module-Sandbox.html @@ -0,0 +1,2396 @@ + + + + + JSDoc: Module: Sandbox + + + + + + + + + + +
+ +

Module: Sandbox

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Sandbox execution service providing multiple isolation methods for secure code analysis. +Supports QEMU virtualization, Firejail, Bubblewrap, and fallback sandboxing with resource limits.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) libRoot :string

+ + + + +
+ Library root path for QEMU user-mode emulation +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(inner, constant) qemuBinary :string

+ + + + +
+ QEMU binary path, configurable via environment variable +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(inner) cleanupSandbox(workDir) → {Promise.<void>}

+ + + + + + +
+ Safely cleans up the sandbox directory after analysis completion. +Validates the directory path to prevent accidental deletion of system directories. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
workDir + + +string + + + + Path to the sandbox directory to cleanup
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

(inner) createSandbox(jobId) → {Promise.<string>}

+ + + + + + +
+ Creates a sandboxed environment for running code analysis with proper permissions. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
jobId + + +string + + + + Unique identifier for the analysis job
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When sandbox creation fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Path to the created sandbox directory +
+ + + +
+
+ Type +
+
+ +Promise.<string> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxExecutable(executablePath, args, timeoutMs) → {Promise.<Object>}

+ + + + + + +
+ Runs an executable with basic resource limits using ulimit. +Provides minimal sandboxing with CPU time, file descriptor, and process limits. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithBestMethod(executablePath, args, timeoutMs, preferredSandbox, workDir) → {Promise.<Object>}

+ + + + + + +
+ Executes an executable using the best available sandbox method with fallback options. +Tries preferred sandbox first, then falls back to other methods if available. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
preferredSandbox + + +string + + + + Preferred sandbox method ('qemu', 'bubblewrap', 'firejail')
workDir + + +string + + + + Working directory for the sandbox
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When all sandbox methods fail +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithBubblewrap(executablePath, args, timeoutMs) → {Promise.<Object>}

+ + + + + + +
+ Runs an executable in a Bubblewrap sandbox with comprehensive security restrictions. +Provides namespace isolation, read-only mounts, and network restrictions. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When Bubblewrap is not installed or execution fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithFirejail(executablePath, args, timeoutMs) → {Promise.<Object>}

+ + + + + + +
+ Runs an executable in a Firejail sandbox with comprehensive security restrictions. +Provides filesystem isolation, capability dropping, and resource limits. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When Firejail is not installed or execution fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithFirejailOnly(executablePath, args, timeoutMs, workDir) → {Promise.<Object>}

+ + + + + + +
+ Runs an executable in a Firejail sandbox with resource and network restrictions. +Applies ulimit for memory (500MB) and uses firejail for network and filesystem isolation. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
workDir + + +string + + + + Working directory for the sandbox
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When Firejail is not installed or execution fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithQemu(executablePath, args, timeoutMs) → {Promise.<Object>}

+ + + + + + +
+ Runs an executable in a QEMU system-mode virtual machine for maximum isolation. +Creates a minimal VM environment with custom kernel and initrd. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When QEMU is not installed or VM creation fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) sandboxWithQemuUser(executablePath, args, timeoutMs, libRoot, customLibDir) → {Promise.<Object>}

+ + + + + + +
+ Alternative QEMU sandboxing approach using user-mode emulation. +Now applies ulimit (memory/process) and firejail (network/filesystem) restrictions. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executablePath + + +string + + + + Path to the executable to run
args + + +Array + + + + Command line arguments for the executable
timeoutMs + + +number + + + + Execution timeout in milliseconds
libRoot + + +string + + + + Library root path for QEMU user-mode
customLibDir + + +string +| + +null + + + + Custom library directory path
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When QEMU user-mode or Firejail is not installed +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Execution result with code, stdout, stderr, and success status +
+ + + +
+
+ Type +
+
+ +Promise.<Object> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-SarifParser.html b/server/docs/module-SarifParser.html new file mode 100644 index 0000000..8434b02 --- /dev/null +++ b/server/docs/module-SarifParser.html @@ -0,0 +1,648 @@ + + + + + JSDoc: Module: SarifParser + + + + + + + + + + +
+ +

Module: SarifParser

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
SARIF (Static Analysis Results Interchange Format) parser for processing analysis tool outputs. +Extracts and parses JSON blocks from mixed log output to provide structured analysis results.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) extractSarifBlocks(output) → {Array.<string>}

+ + + + + + +
+ Extracts SARIF JSON blocks from mixed output text using regex pattern matching. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
output + + +string + + + + Mixed output text that may contain SARIF JSON blocks
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of extracted SARIF JSON strings, empty array if none found +
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + + + + +

(inner) parseSarifResults(sarifJson) → {Array.<Object>}

+ + + + + + +
+ Parses a single SARIF JSON string and extracts structured results with tool information. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sarifJson + + +string + + + + SARIF JSON string to parse
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of parsed results with tool, message, and location information +
+ + + +
+
+ Type +
+
+ +Array.<Object> + + +
+
+ + + + + + + + + + + + + +

(inner) parseToolOutputs(outputText) → {Array.<Object>}

+ + + + + + +
+ Main function to parse mixed tool outputs and extract structured analysis results. +Processes multiple JSON blocks from analysis tool output and organizes results by tool. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
outputText + + +string + + + + Mixed output text from analysis tools containing JSON blocks
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of tool results with tool name and findings +
+ + + +
+
+ Type +
+
+ +Array.<Object> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-ToolsRoutes.html b/server/docs/module-ToolsRoutes.html new file mode 100644 index 0000000..1a3d5ec --- /dev/null +++ b/server/docs/module-ToolsRoutes.html @@ -0,0 +1,242 @@ + + + + + JSDoc: Module: ToolsRoutes + + + + + + + + + + +
+ +

Module: ToolsRoutes

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Express routes for analysis tools functionality. +Provides information about available analysis tools and their capabilities.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(inner, constant) router :express.Router

+ + + + +
+ Router instance for tools-related endpoints. +
+ + + +
Type:
+
    +
  • + +express.Router + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/module-ToolsService.html b/server/docs/module-ToolsService.html new file mode 100644 index 0000000..482906d --- /dev/null +++ b/server/docs/module-ToolsService.html @@ -0,0 +1,316 @@ + + + + + JSDoc: Module: ToolsService + + + + + + + + + + +
+ +

Module: ToolsService

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Service for retrieving information about available analysis tools from ctrace. +Provides functionality to query and parse available tools for code analysis.
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(inner) getAvailableTools() → {Promise.<Array.<string>>}

+ + + + + + +
+ Retrieves available analysis tools by executing `ctrace --help` and parsing the output. +Extracts tool information from the help output and returns a structured list of available tools. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ When ctrace execution fails or tool parsing fails +
+
+
+
+
+
+ Type +
+
+ +Error + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+ Array of available tool names +
+ + + +
+
+ Type +
+
+ +Promise.<Array.<string>> + + +
+
+ + + + + + +
Example
+ +
const tools = await getAvailableTools();
+// Returns: ['flawfinder', 'cppcheck', 'clang-tidy']
+ + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + \ No newline at end of file diff --git a/server/docs/routes_analyze.js.html b/server/docs/routes_analyze.js.html new file mode 100644 index 0000000..c52e6f4 --- /dev/null +++ b/server/docs/routes_analyze.js.html @@ -0,0 +1,125 @@ + + + + + JSDoc: Source: routes/analyze.js + + + + + + + + + + +
+ +

Source: routes/analyze.js

+ + + + + + +
+
+
/**
+ * @module AnalyzeRoutes
+ * @description Express routes for code analysis functionality.
+ * Handles file upload, validation, and analysis requests using the analyzer service.
+ */
+
+const express = require('express');
+const analyzer = require('../services/analyzer');
+
+/**
+ * @type {express.Router}
+ * @description Router instance for analysis-related endpoints.
+ */
+const router = express.Router();
+
+/**
+ * @route POST /api/analyze
+ * @description Submit code files for security analysis using CoreTrace and flawfinder tools.
+ * Accepts C/C++ source files and analysis options, returns structured analysis results.
+ * 
+ * @param {Object} req - Express request object
+ * @param {Object} req.body - Request body containing files and analysis options
+ * @param {Object} req.body.files - Object with filename-content pairs of C/C++ files to analyze
+ * @param {Object} [req.body.options] - Analysis options including static/dynamic flags
+ * @param {boolean} [req.body.options.static] - Enable static analysis
+ * @param {boolean} [req.body.options.dynamic] - Enable dynamic analysis
+ * @param {Object} res - Express response object
+ * @returns {Object} JSON response with analysis results or error message
+ * 
+ * @example
+ * POST /api/analyze
+ * {
+ *   "files": {
+ *     "main.c": "#include <stdio.h>\nint main() { return 0; }"
+ *   },
+ *   "options": {
+ *     "static": true,
+ *     "dynamic": false
+ *   }
+ * }
+ */
+router.post('/', async (req, res) => {
+    try {
+        const { files, options } = req.body;
+
+        // Validation
+        if (!files || Object.keys(files).length === 0) {
+            return res.status(400).json({ error: 'No files provided' });
+        }
+
+        // Validate file sizes and content
+        for (const [filename, content] of Object.entries(files)) {
+            if (typeof content !== 'string') {
+                return res.status(400).json({ error: 'File content must be a string' });
+            }
+
+            if (content.length > 1000000) { // 1MB limit per file
+                return res.status(400).json({ error: 'File size exceeds the limit (1MB)' });
+            }
+
+            if (!filename.match(/\.(c|cpp|h|hpp)$/i)) {
+                return res.status(400).json({ error: 'Only C/C++ files are allowed' });
+            }
+        }
+
+        // Call service function to handle the analysis
+        const result = await analyzer.analyzeCode(files, options || {});
+        res.json(result);
+    } catch (error) {
+        console.error('Error analyzing code:', error);
+        res.status(500).json({ error: 'An error occurred during analysis' });
+    }
+});
+
+module.exports = router;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/routes_examples.js.html b/server/docs/routes_examples.js.html new file mode 100644 index 0000000..b25e76b --- /dev/null +++ b/server/docs/routes_examples.js.html @@ -0,0 +1,130 @@ + + + + + JSDoc: Source: routes/examples.js + + + + + + + + + + +
+ +

Source: routes/examples.js

+ + + + + + +
+
+
/**
+ * @module ExamplesRoutes
+ * @description Express routes for example code functionality.
+ * Provides access to predefined code examples for testing and demonstration purposes.
+ */
+
+const express = require('express');
+const { getExampleList, getExampleCode } = require('../services/examples');
+
+/**
+ * @type {express.Router}
+ * @description Router instance for example-related endpoints.
+ */
+const router = express.Router();
+
+/**
+ * @route GET /api/examples
+ * @description Retrieve a list of all available example code snippets.
+ * Returns metadata about available examples including IDs, names, and descriptions.
+ * 
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @returns {Object} JSON response with array of example metadata
+ * 
+ * @example
+ * GET /api/examples
+ * Response: [
+ *   {
+ *     "id": "buffer-overflow",
+ *     "name": "Buffer Overflow Example",
+ *     "description": "Demonstrates common buffer overflow vulnerabilities"
+ *   }
+ * ]
+ */
+router.get('/', (req, res) => {
+    try {
+        const examples = getExampleList();
+        res.json(examples);
+    } catch (error) {
+        console.error('Error retrieving examples:', error);
+        res.status(500).json({ error: 'Failed to retrieve examples' });
+    }
+});
+
+/**
+ * @route GET /api/examples/:id
+ * @description Retrieve a specific example code snippet by its unique identifier.
+ * Returns the complete code content and metadata for the requested example.
+ * 
+ * @param {Object} req - Express request object
+ * @param {string} req.params.id - Unique identifier of the example to retrieve
+ * @param {Object} res - Express response object
+ * @returns {Object} JSON response with example code and metadata, or 404 if not found
+ * 
+ * @example
+ * GET /api/examples/buffer-overflow
+ * Response: {
+ *   "id": "buffer-overflow",
+ *   "name": "Buffer Overflow Example",
+ *   "description": "Demonstrates common buffer overflow vulnerabilities",
+ *   "code": "#include <stdio.h>\n#include <string.h>\n..."
+ * }
+ */
+router.get('/:id', (req, res) => {
+    try {
+        const { id } = req.params;
+        const example = getExampleCode(id);
+
+        if (!example) {
+            return res.status(404).json({ error: 'Example not found' });
+        }
+
+        res.json(example);
+    } catch (error) {
+        console.error('Error retrieving example:', error);
+        res.status(500).json({ error: 'Failed to retrieve example' });
+    }
+});
+
+module.exports = router;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:01 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/routes_index.js.html b/server/docs/routes_index.js.html new file mode 100644 index 0000000..b27d020 --- /dev/null +++ b/server/docs/routes_index.js.html @@ -0,0 +1,73 @@ + + + + + JSDoc: Source: routes/index.js + + + + + + + + + + +
+ +

Source: routes/index.js

+ + + + + + +
+
+
/**
+ * @module Routes
+ * @description Main router configuration that mounts all application routes.
+ * Centralizes route organization and provides a single entry point for all API endpoints.
+ */
+
+const express = require('express');
+const analyzeRoutes = require('./analyze');
+const examplesRoutes = require('./examples');
+const toolsRoutes = require('./tools');
+
+/**
+ * @type {express.Router}
+ * @description Express router instance that mounts all application routes.
+ */
+const router = express.Router();
+
+// Mount route modules
+router.use('/analyze', analyzeRoutes);
+router.use('/examples', examplesRoutes);
+router.use('/tools', toolsRoutes);
+
+module.exports = router;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/routes_tools.js.html b/server/docs/routes_tools.js.html new file mode 100644 index 0000000..114bce2 --- /dev/null +++ b/server/docs/routes_tools.js.html @@ -0,0 +1,98 @@ + + + + + JSDoc: Source: routes/tools.js + + + + + + + + + + +
+ +

Source: routes/tools.js

+ + + + + + +
+
+
/**
+ * @module ToolsRoutes
+ * @description Express routes for analysis tools functionality.
+ * Provides information about available analysis tools and their capabilities.
+ */
+
+const express = require('express');
+const { getAvailableTools } = require('../services/toolsService');
+
+/**
+ * @type {express.Router}
+ * @description Router instance for tools-related endpoints.
+ */
+const router = express.Router();
+
+/**
+ * @route GET /api/tools
+ * @description Retrieve information about available analysis tools from ctrace.
+ * Returns a list of tools that can be used for code analysis, including their
+ * names, descriptions, and capabilities.
+ * 
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @returns {Object} JSON response with array of available tools
+ * 
+ * @example
+ * GET /api/tools
+ * Response: {
+ *   "tools": [
+ *     {
+ *       "name": "flawfinder",
+ *       "description": "Static analysis tool for finding security vulnerabilities",
+ *       "version": "2.0.19"
+ *     }
+ *   ]
+ * }
+ */
+router.get('/', async (req, res) => {
+  try {
+    const tools = await getAvailableTools();
+    res.json({ tools });
+  } catch (error) {
+    console.error('Error retrieving tools:', error);
+    res.status(500).json({ error: 'Failed to retrieve tools' });
+  }
+});
+
+module.exports = router;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/scripts/linenumber.js b/server/docs/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/server/docs/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/server/docs/scripts/prettify/Apache-License-2.0.txt b/server/docs/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/server/docs/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/server/docs/scripts/prettify/lang-css.js b/server/docs/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/server/docs/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/server/docs/scripts/prettify/prettify.js b/server/docs/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/server/docs/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p + + + + JSDoc: Source: services/analyzer.js + + + + + + + + + + +
+ +

Source: services/analyzer.js

+ + + + + + +
+
+
/**
+ * @module Analyzer
+ * @description Core analysis service that handles code analysis using ctrace and flawfinder tools.
+ * Manages file processing, sandbox execution, and result parsing for security analysis.
+ */
+
+// services/analyzer.js
+const fs = require('fs');
+const path = require('path');
+const { sandboxWithBestMethod } = require('./sandbox');
+const config = require('../config');
+const logger = require('./logger');
+const jobManager = require('./jobManager');
+const { parseToolOutputs } = require('./sarifParser');
+
+// In-memory store for analysis jobs (would use a database in production)
+const analysisJobs = new Map();
+
+/**
+ * @class Analyzer
+ * @description Main analyzer class that orchestrates code analysis using ctrace and flawfinder.
+ * Handles file management, executable path resolution, and result processing.
+ */
+class Analyzer {
+    /**
+     * @constructor
+     * @description Initializes the analyzer with executable paths for ctrace and test binaries.
+     */
+    constructor() {
+        this.ctraceExecutable = path.join(__dirname, '../../server/bin/ctrace');
+        this.testExecutable = path.join(__dirname, '../../server/bin/test');
+    }
+
+    /**
+     * @method analyzeCode
+     * @description Performs comprehensive code analysis on uploaded files using ctrace and flawfinder.
+     * @param {Object} files - Object containing filename-content pairs of files to analyze
+     * @param {Object} options - Analysis options including static/dynamic flags
+     * @param {boolean} [options.static] - Enable static analysis
+     * @param {boolean} [options.dynamic] - Enable dynamic analysis
+     * @returns {Promise<Object>} Parsed analysis results with tool-specific findings
+     * @throws {Error} When file validation fails or analysis execution errors occur
+     */
+    async analyzeCode(files, options) {
+        logger.info('Starting analysis', { files: Object.keys(files), options });
+
+        // Validate files
+        const validationErrors = jobManager.validateFiles(files);
+        if (validationErrors.length > 0) {
+            throw new Error(`Validation failed: ${validationErrors.join(', ')}`);
+        }
+
+        // Create job
+        const job = jobManager.createJob(files, options);
+
+        try {
+            // Save files to work directory
+            const filePaths = this.saveFilesToWorkDir(job.workDir, files);
+            logger.info('Files saved', { jobId: job.id, filePaths });
+
+            // Get executable path
+            const execPath = this.getExecutablePath();
+            logger.info('Using executable', { jobId: job.id, execPath });
+
+            // Build arguments
+            const args = this.buildArguments(filePaths, options, job.workDir);
+            logger.info('Built arguments', { jobId: job.id, args });
+
+            // Run analysis in sandbox
+            const result = await this.runAnalysis(execPath, args, job.id, job.workDir);
+
+            // Update job status
+            jobManager.updateJobStatus(job.id, 'completed', result);
+
+            return result;
+        } catch (error) {
+            logger.error('Analysis failed', { jobId: job.id, error: error.message });
+            jobManager.updateJobStatus(job.id, 'failed', null, error.message);
+            throw error;
+        }
+    }
+
+    /**
+     * @method getExecutablePath
+     * @description Determines the appropriate executable path, falling back to test executable if ctrace is not available.
+     * @returns {string} Path to the executable to use for analysis
+     */
+    getExecutablePath() {
+        return fs.existsSync(this.ctraceExecutable) ? this.ctraceExecutable : this.testExecutable;
+    }
+
+    /**
+     * @method saveFilesToWorkDir
+     * @description Saves uploaded files to the working directory and sets up flawfinder environment.
+     * @param {string} workDir - Working directory path where files should be saved
+     * @param {Object} files - Object containing filename-content pairs
+     * @returns {Array<string>} Array of saved file paths
+     * @throws {Error} When flawfinder.py is not found or file operations fail
+     */
+    saveFilesToWorkDir(workDir, files) {
+        const filePaths = [];
+
+        // Save the uploaded files first
+        for (const [filename, content] of Object.entries(files)) {
+            const filePath = path.join(workDir, filename);
+            fs.writeFileSync(filePath, content);
+            filePaths.push(filename);
+        }
+
+        // Create the flawfinder directory structure that ctrace expects
+        const flawfinderTargetDir = path.join(workDir, 'flawfinder', 'src', 'flawfinder-build');
+        fs.mkdirSync(flawfinderTargetDir, { recursive: true });
+        console.log('flawfinderTargetDir', flawfinderTargetDir);
+        const flawfinderSource = path.join(__dirname, '../bin/flawfinder.py');
+        const flawfinderDest = path.join(flawfinderTargetDir, 'flawfinder.py');
+
+        if (fs.existsSync(flawfinderSource)) {
+            fs.copyFileSync(flawfinderSource, flawfinderDest);
+            fs.chmodSync(flawfinderDest, 0o755);
+            console.log("Flawfinder.py copied to", flawfinderDest);
+        } else {
+            throw new Error(`flawfinder.py not found at ${flawfinderSource}`);
+        }
+        return filePaths;
+    }
+
+    /**
+     * @method buildArguments
+     * @description Builds command line arguments for the analysis executable based on options and file paths.
+     * @param {Array<string>} filePaths - Array of file paths to analyze
+     * @param {Object} options - Analysis options including static/dynamic flags
+     * @param {string} workDir - Working directory path
+     * @returns {Array<string>} Array of command line arguments
+     */
+    buildArguments(filePaths, options, workDir) {
+        const args = [];
+        const execPath = this.getExecutablePath();
+
+        if (execPath === this.ctraceExecutable) {
+            args.push(`--input=${filePaths.join(',')}`);
+            if (options.static) args.push('--static');
+            if (options.dynamic) args.push('--dyn');
+            // if (options.tools?.length > 0) {
+            //     args.push(`--invoke=${options.tools.join(',')}`);
+            // }
+            // const reportPath = path.join(workDir, 'report.txt');
+            // args.push(`--report-file=${reportPath}`);
+            args.push("--sarif-format");
+        }
+
+        return args;
+    }
+
+    /**
+     * @method runAnalysis
+     * @description Executes the analysis in a sandboxed environment and processes the results.
+     * @param {string} execPath - Path to the executable to run
+     * @param {Array<string>} args - Command line arguments for the executable
+     * @param {string} jobId - Unique job identifier
+     * @param {string} workDir - Working directory path
+     * @returns {Promise<Object>} Parsed analysis results with tool-specific findings
+     */
+    async runAnalysis(execPath, args, jobId, workDir) {
+        logger.info('Running analysis in sandbox', { jobId, execPath, args });
+
+        const result = await sandboxWithBestMethod(
+            execPath,
+            args,
+            config.sandbox.qemu.timeout,
+            'firejail',
+            workDir
+        );
+
+        // Clean output
+        result.stdout = this.cleanAnsiCodes(result.stdout);
+        result.stderr = this.cleanAnsiCodes(result.stderr);
+
+        // Add job ID and test mode flag
+        result.jobId = jobId;
+        if (execPath === this.testExecutable) {
+            result.testMode = true;
+            result.message = "Using test executable - ctrace not found";
+        }
+
+        const parsed = parseToolOutputs(result.stdout);
+        console.log(JSON.stringify(parsed, null, 2));
+        console.log(parsed);
+        return parsed;
+    }
+
+    /**
+     * @method cleanAnsiCodes
+     * @description Removes ANSI escape codes from text output for cleaner logging.
+     * @param {string} text - Text that may contain ANSI escape codes
+     * @returns {string} Cleaned text without ANSI codes
+     */
+    cleanAnsiCodes(text) {
+        if (!text) return '';
+        return text.replace(/\u001b\[\d+m|\[\d+m/g, '');
+    }
+}
+
+// Export singleton instance
+module.exports = new Analyzer();
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_examples.js.html b/server/docs/services_examples.js.html new file mode 100644 index 0000000..2d13c2c --- /dev/null +++ b/server/docs/services_examples.js.html @@ -0,0 +1,140 @@ + + + + + JSDoc: Source: services/examples.js + + + + + + + + + + +
+ +

Source: services/examples.js

+ + + + + + +
+
+
const exampleSnippets = {
+    'hello-world': {
+        id: 'hello-world',
+        title: 'Hello World',
+        description: 'A simple Hello World program in C',
+        language: 'c',
+        files: {
+            'main.c': `#include <stdio.h>
+  
+  int main() {
+      printf("Hello, World!\\n");
+      return 0;
+  }`
+        }
+    },
+    'buffer-overflow': {
+        id: 'buffer-overflow',
+        title: 'Buffer Overflow Example',
+        description: 'An example demonstrating a potential buffer overflow vulnerability',
+        language: 'c',
+        files: {
+            'vulnerable.c': `#include <stdio.h>
+  #include <string.h>
+  
+  void insecure_function(char *input) {
+      char buffer[10];
+      strcpy(buffer, input); // No bounds checking
+      printf("Buffer content: %s\\n", buffer);
+  }
+  
+  int main(int argc, char *argv[]) {
+      if (argc > 1) {
+          insecure_function(argv[1]);
+      } else {
+          printf("Please provide an argument\\n");
+      }
+      return 0;
+  }`
+        }
+    },
+    'memory-leak': {
+        id: 'memory-leak',
+        title: 'Memory Leak Example',
+        description: 'An example demonstrating a memory leak',
+        language: 'cpp',
+        files: {
+            'leak.cpp': `#include <iostream>
+  
+  void leak_memory() {
+      int* arr = new int[100];
+      // Missing delete[] arr;
+  }
+  
+  int main() {
+      for (int i = 0; i < 1000; i++) {
+          leak_memory();
+      }
+      std::cout << "Program finished\\n";
+      return 0;
+  }`
+        }
+    }
+};
+
+/**
+ * Get a list of all available example code snippets
+ * @returns {Array} List of example metadata (without code content)
+ */
+function getExampleList() {
+    return Object.values(exampleSnippets).map(({ id, title, description, language }) => ({
+        id,
+        title,
+        description,
+        language
+    }));
+}
+
+/**
+ * Get a specific example by ID
+ * @param {string} id - Example ID
+ * @returns {Object|null} Example object or null if not found
+ */
+function getExampleCode(id) {
+    return exampleSnippets[id] || null;
+}
+
+module.exports = {
+    getExampleList,
+    getExampleCode
+};
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_jobManager.js.html b/server/docs/services_jobManager.js.html new file mode 100644 index 0000000..a6ae0e6 --- /dev/null +++ b/server/docs/services_jobManager.js.html @@ -0,0 +1,244 @@ + + + + + JSDoc: Source: services/jobManager.js + + + + + + + + + + +
+ +

Source: services/jobManager.js

+ + + + + + +
+
+
/**
+ * @module JobManager
+ * @description Manages analysis jobs including creation, status tracking, validation, and cleanup.
+ * Provides job lifecycle management and file validation for the analysis system.
+ */
+
+const { v4: uuidv4 } = require('uuid');
+const path = require('path');
+const fs = require('fs');
+const config = require('../config');
+const logger = require('./logger');
+
+/**
+ * @class JobManager
+ * @description Handles the complete lifecycle of analysis jobs including creation, tracking, and cleanup.
+ * Maintains job state in memory and manages file system operations for job directories.
+ */
+class JobManager {
+    /**
+     * @constructor
+     * @description Initializes the job manager with job storage and ensures work directory exists.
+     */
+    constructor() {
+        this.jobs = new Map();
+        this.initializeStorage();
+    }
+
+    /**
+     * @method initializeStorage
+     * @description Ensures the job storage directory exists for file operations.
+     * Creates the work directory if it doesn't exist.
+     */
+    initializeStorage() {
+        // Ensure job storage directory exists
+        if (!fs.existsSync(config.filesystem.workDir)) {
+            fs.mkdirSync(config.filesystem.workDir, { recursive: true });
+        }
+    }
+
+    /**
+     * @method createJob
+     * @description Creates a new analysis job with unique ID and work directory.
+     * @param {Object} files - Object containing filename-content pairs of files to analyze
+     * @param {Object} [options={}] - Analysis options and configuration
+     * @returns {Object} Job object with id, status, startTime, files, options, and workDir
+     */
+    createJob(files, options = {}) {
+        console.log('createJob');
+        const jobId = uuidv4();
+        const workDir = path.join(config.filesystem.workDir, jobId);
+        console.log('workDir', workDir);
+
+        // Create job directory
+        fs.mkdirSync(workDir, { recursive: true });
+
+        // Initialize job record
+        const job = {
+            id: jobId,
+            status: 'created',
+            startTime: new Date(),
+            files: Object.keys(files),
+            options,
+            workDir
+        };
+
+        this.jobs.set(jobId, job);
+        logger.info('Job created', { jobId, status: job.status });
+
+        return job;
+    }
+
+    /**
+     * @method updateJobStatus
+     * @description Updates the status of an existing job and optionally stores results or errors.
+     * @param {string} jobId - Unique job identifier
+     * @param {string} status - New status for the job ('created', 'running', 'completed', 'failed')
+     * @param {Object} [result=null] - Analysis results to store with the job
+     * @param {string} [error=null] - Error message if job failed
+     * @returns {Object} Updated job object
+     * @throws {Error} When job with specified ID is not found
+     */
+    updateJobStatus(jobId, status, result = null, error = null) {
+        const job = this.jobs.get(jobId);
+        if (!job) {
+            throw new Error(`Job ${jobId} not found`);
+        }
+
+        job.status = status;
+        job.endTime = new Date();
+        if (result) job.result = result;
+        if (error) job.error = error;
+
+        this.jobs.set(jobId, job);
+        logger.info('Job status updated', { jobId, status });
+
+        // Schedule cleanup if job is completed or failed
+        if (status === 'completed' || status === 'failed') {
+            //this.scheduleCleanup(jobId);
+        }
+
+        return job;
+    }
+
+    /**
+     * @method getJob
+     * @description Retrieves a job by its unique identifier.
+     * @param {string} jobId - Unique job identifier
+     * @returns {Object|null} Job object if found, null otherwise
+     */
+    getJob(jobId) {
+        return this.jobs.get(jobId);
+    }
+
+    /**
+     * @method scheduleCleanup
+     * @description Schedules cleanup of a job after a configurable delay.
+     * @param {string} jobId - Unique job identifier to schedule cleanup for
+     */
+    scheduleCleanup(jobId) {
+        const job = this.jobs.get(jobId);
+        if (!job) return;
+
+        // Schedule cleanup after delay
+        setTimeout(() => {
+            this.cleanupJob(jobId);
+        }, config.jobs.cleanupDelay);
+    }
+
+    /**
+     * @method cleanupJob
+     * @description Performs cleanup operations for a job including file removal and memory cleanup.
+     * @param {string} jobId - Unique job identifier to cleanup
+     */
+    cleanupJob(jobId) {
+        const job = this.jobs.get(jobId);
+        if (!job) return;
+
+        try {
+            // Remove job directory
+            if (fs.existsSync(job.workDir)) {
+                fs.rmSync(job.workDir, { recursive: true, force: true });
+            }
+
+            // Remove job from memory after retention period
+            setTimeout(() => {
+                this.jobs.delete(jobId);
+            }, config.jobs.retentionPeriod);
+
+            logger.info('Job cleaned up', { jobId });
+        } catch (error) {
+            logger.error('Error cleaning up job', { jobId, error: error.message });
+        }
+    }
+
+    /**
+     * @method validateFiles
+     * @description Validates uploaded files for security, size, and format requirements.
+     * @param {Object} files - Object containing filename-content pairs to validate
+     * @returns {Array<string>} Array of validation error messages, empty if validation passes
+     */
+    validateFiles(files) {
+        const errors = [];
+
+        // Check if files are provided
+        if (!files || Object.keys(files).length === 0) {
+            errors.push('No files provided');
+            return errors;
+        }
+
+        // Validate each file
+        for (const [filename, content] of Object.entries(files)) {
+            // Check file extension
+            const ext = path.extname(filename).toLowerCase();
+            if (!config.filesystem.allowedExtensions.includes(ext)) {
+                errors.push(`Invalid file extension for ${filename}`);
+            }
+
+            // Check content type
+            if (typeof content !== 'string') {
+                errors.push(`Invalid content type for ${filename}`);
+            }
+
+            // Check file size
+            if (content.length > config.sandbox.limits.maxFileSize) {
+                errors.push(`File ${filename} exceeds size limit`);
+            }
+        }
+
+        return errors;
+    }
+}
+
+// Export singleton instance
+module.exports = new JobManager(); 
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_logger.js.html b/server/docs/services_logger.js.html new file mode 100644 index 0000000..48673c0 --- /dev/null +++ b/server/docs/services_logger.js.html @@ -0,0 +1,107 @@ + + + + + JSDoc: Source: services/logger.js + + + + + + + + + + +
+ +

Source: services/logger.js

+ + + + + + +
+
+
/**
+ * @module Logger
+ * @description Centralized logging service using Winston for structured logging across the application.
+ * Provides console and file-based logging with request tracking capabilities.
+ */
+
+const winston = require('winston');
+const config = require('../config');
+
+/**
+ * @type {winston.Logger}
+ * @description Winston logger instance configured with console and file transports.
+ * Supports different log levels and formats for development and production environments.
+ */
+const logger = winston.createLogger({
+    level: config.logging.level,
+    format: winston.format.combine(
+        winston.format.timestamp(),
+        winston.format.json()
+    ),
+    transports: [
+        new winston.transports.Console({
+            format: winston.format.combine(
+                winston.format.colorize(),
+                winston.format.simple()
+            )
+        }),
+        new winston.transports.File({ 
+            filename: 'error.log', 
+            level: 'error' 
+        }),
+        new winston.transports.File({ 
+            filename: 'combined.log' 
+        })
+    ]
+});
+
+/**
+ * @function requestLogger
+ * @description Express middleware for logging incoming HTTP requests with request ID tracking.
+ * Adds request ID to the request object and logs request details for debugging and monitoring.
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object  
+ * @param {Function} next - Express next middleware function
+ */
+logger.requestLogger = (req, res, next) => {
+    req.requestId = req.headers['x-request-id'] || Math.random().toString(36).substring(7);
+    logger.info('Incoming request', {
+        requestId: req.requestId,
+        method: req.method,
+        path: req.path,
+        ip: req.ip
+    });
+    next();
+};
+
+module.exports = logger; 
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_sandbox.js.html b/server/docs/services_sandbox.js.html new file mode 100644 index 0000000..633e305 --- /dev/null +++ b/server/docs/services_sandbox.js.html @@ -0,0 +1,778 @@ + + + + + JSDoc: Source: services/sandbox.js + + + + + + + + + + +
+ +

Source: services/sandbox.js

+ + + + + + +
+
+
/**
+ * @module Sandbox
+ * @description Sandbox execution service providing multiple isolation methods for secure code analysis.
+ * Supports QEMU virtualization, Firejail, Bubblewrap, and fallback sandboxing with resource limits.
+ */
+
+const fs = require('fs');
+const path = require('path');
+const os = require('os');
+const { spawn, exec } = require('child_process');
+const crypto = require('crypto');
+const config = require('../config');
+require('dotenv').config();
+
+/**
+ * @type {string}
+ * @description QEMU binary path, configurable via environment variable
+ */
+const qemuBinary = process.env.QEMU_BINARY || 'qemu-x86_64';
+
+/**
+ * @type {string}
+ * @description Library root path for QEMU user-mode emulation
+ */
+const libRoot = process.env.QEMU_LIB_ROOT || '/usr/x86_64-linux-gnu';
+
+/**
+ * @function createSandbox
+ * @description Creates a sandboxed environment for running code analysis with proper permissions.
+ * @param {string} jobId - Unique identifier for the analysis job
+ * @returns {Promise<string>} Path to the created sandbox directory
+ * @throws {Error} When sandbox creation fails
+ */
+async function createSandbox(jobId) {
+    // Create a temporary working directory
+    const workDir = path.join(os.tmpdir(), `coretrace-${jobId}`);
+
+    try {
+        // Create directory
+        console.log(`Creating sandbox at: ${workDir}`);
+        fs.mkdirSync(workDir, { recursive: true });
+
+        // Set permissions (more restrictive on Unix-like systems)
+        if (process.platform !== 'win32') {
+            console.log(`Setting permissions for sandbox: ${workDir}`);
+            fs.chmodSync(workDir, 0o750); // rwxr-x---
+        }
+
+        return workDir;
+    } catch (error) {
+        console.error('Error creating sandbox:', error);
+        throw new Error('Failed to create sandbox environment');
+    }
+}
+
+/**
+ * @function cleanupSandbox
+ * @description Safely cleans up the sandbox directory after analysis completion.
+ * Validates the directory path to prevent accidental deletion of system directories.
+ * @param {string} workDir - Path to the sandbox directory to cleanup
+ * @returns {Promise<void>}
+ */
+async function cleanupSandbox(workDir) {
+    try {
+        // Ensure the path is actually a temporary directory we created
+        if (!workDir.includes('coretrace-') || !workDir.startsWith(os.tmpdir())) {
+            throw new Error('Invalid sandbox directory');
+        }
+
+        // Remove the directory and all its contents
+        console.log(`Cleaning up sandbox at: ${workDir}`);
+        fs.rmSync(workDir, { recursive: true, force: true });
+    } catch (error) {
+        console.error('Error cleaning up sandbox:', error);
+    }
+}
+
+/**
+ * @function sandboxWithBubblewrap
+ * @description Runs an executable in a Bubblewrap sandbox with comprehensive security restrictions.
+ * Provides namespace isolation, read-only mounts, and network restrictions.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When Bubblewrap is not installed or execution fails
+ */
+function sandboxWithBubblewrap(executablePath, args = [], timeoutMs = 10000) {
+    return new Promise((resolve, reject) => {
+        // Ensure the executable exists
+        if (!fs.existsSync(executablePath)) {
+            return reject(new Error(`Executable not found: ${executablePath}`));
+        }
+
+        const execDir = path.dirname(executablePath);
+        const execName = path.basename(executablePath);
+
+        // Build bwrap command with security restrictions
+        const bwrapArgs = [
+            // Mount system directories read-only
+            '--ro-bind', '/usr', '/usr',
+            '--ro-bind', '/lib', '/lib',
+            '--ro-bind', '/lib64', '/lib64',
+            '--ro-bind', '/bin', '/bin',
+            // Provide /proc but mask sensitive things
+            '--proc', '/proc',
+            // Provide minimal /dev
+            '--dev', '/dev',
+            // Provide a temporary directory
+            '--tmpfs', '/tmp',
+            // Unshare namespaces for better isolation
+            '--unshare-all',
+            // Create a new process session
+            '--new-session',
+            // Mount the executable directory with read-only access
+            '--ro-bind', execDir, execDir,
+            // Change to the executable directory
+            '--chdir', execDir,
+            // Deny network access
+            '--unshare-net',
+            // Execute the binary with arguments
+            executablePath,
+            ...args
+        ];
+
+        console.log(`Running with bwrap: ${executablePath} ${args.join(' ')}`);
+
+        const process = spawn('bwrap', bwrapArgs, {
+            stdio: 'pipe',
+            timeout: timeoutMs
+        });
+
+        let stdout = '';
+        let stderr = '';
+
+        process.stdout.on('data', (data) => {
+            stdout += data.toString();
+        });
+
+        process.stderr.on('data', (data) => {
+            stderr += data.toString();
+        });
+
+        process.on('close', (code) => {
+            resolve({
+                code,
+                stdout,
+                stderr,
+                success: code === 0
+            });
+        });
+
+        process.on('error', (err) => {
+            // Handle command not found error
+            if (err.code === 'ENOENT') {
+                reject(new Error('Bubblewrap (bwrap) is not installed. Please install it first.'));
+            } else {
+                reject(err);
+            }
+        });
+
+        // Handle timeout
+        setTimeout(() => {
+            if (!process.killed) {
+                process.kill('SIGKILL');
+                reject(new Error('Process execution timed out'));
+            }
+        }, timeoutMs);
+    });
+}
+
+/**
+ * @function sandboxWithFirejail
+ * @description Runs an executable in a Firejail sandbox with comprehensive security restrictions.
+ * Provides filesystem isolation, capability dropping, and resource limits.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When Firejail is not installed or execution fails
+ */
+function sandboxWithFirejail(executablePath, args = [], timeoutMs = 10000) {
+    return new Promise((resolve, reject) => {
+        // Ensure the executable exists
+        if (!fs.existsSync(executablePath)) {
+            return reject(new Error(`Executable not found: ${executablePath}`));
+        }
+
+        const execDir = path.dirname(executablePath);
+
+        // Build firejail command with security restrictions
+        const firejailArgs = [
+            '--noprofile',                // Don't use any profiles
+            '--quiet',                    // Less verbose output
+            '--private=' + execDir,       // Use private sandbox with the executable directory
+            '--private-tmp',              // Use private /tmp directory
+            '--private-dev',              // Use private /dev directory
+            '--caps.drop=all',            // Drop all capabilities
+            '--nonewprivs',               // No new privileges
+            '--noroot',                   // No fake root user
+            '--seccomp',                  // Enable seccomp filtering
+            '--net=none',                 // No network access
+            '--rlimit-as=' + (500 * 1024 * 1024), // Memory limit (500MB)
+            '--rlimit-cpu=30',            // CPU time limit (30 seconds)
+            '--rlimit-fsize=10485760',    // File size limit (10MB)
+            '--rlimit-nofile=50',         // Open files limit
+            '--rlimit-nproc=20',          // Process limit
+            executablePath,               // The executable
+            ...args                       // Arguments to the executable
+        ];
+
+        console.log(`Running with firejail: ${executablePath} ${args.join(' ')}`);
+
+        const process = spawn('firejail', firejailArgs, {
+            stdio: 'pipe',
+            timeout: timeoutMs
+        });
+
+        let stdout = '';
+        let stderr = '';
+
+        process.stdout.on('data', (data) => {
+            stdout += data.toString();
+        });
+
+        process.stderr.on('data', (data) => {
+            stderr += data.toString();
+        });
+
+        process.on('close', (code) => {
+            resolve({
+                code,
+                stdout,
+                stderr,
+                success: code === 0
+            });
+        });
+
+        process.on('error', (err) => {
+            // Handle command not found error
+            if (err.code === 'ENOENT') {
+                reject(new Error('Firejail is not installed. Please install it first.'));
+            } else {
+                reject(err);
+            }
+        });
+
+        // Handle timeout
+        setTimeout(() => {
+            if (!process.killed) {
+                process.kill('SIGKILL');
+                reject(new Error('Process execution timed out'));
+            }
+        }, timeoutMs);
+    });
+}
+
+/**
+ * @function sandboxWithBestMethod
+ * @description Executes an executable using the best available sandbox method with fallback options.
+ * Tries preferred sandbox first, then falls back to other methods if available.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @param {string} preferredSandbox - Preferred sandbox method ('qemu', 'bubblewrap', 'firejail')
+ * @param {string} workDir - Working directory for the sandbox
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When all sandbox methods fail
+ */
+async function sandboxWithBestMethod(executablePath, args = [], timeoutMs = 10000, preferredSandbox = 'qemu', workDir) {
+    console.log("sandboxWithBestMethod", executablePath, args, timeoutMs, preferredSandbox);
+    try {
+        // Try the preferred sandbox first
+        if (preferredSandbox === 'qemu') {
+            try {
+                console.log("Trying QEMU user-mode");
+                return await sandboxWithQemuUser(executablePath, args, timeoutMs, config.sandbox.qemu.libRoot, config.sandbox.qemu.customLibDir);
+            } catch (qemuError) {
+                console.log("QEMU failed, falling back to bubblewrap:", qemuError.message);
+            }
+        }
+
+        // Fallback to other sandbox methods
+        if (preferredSandbox === 'bubblewrap') {
+            try {
+                console.log("Trying Bubblewrap");
+                return await sandboxWithBubblewrap(executablePath, args, timeoutMs);
+            } catch (bwrapError) {
+                console.log("Bubblewrap failed, falling back to firejail:", bwrapError.message);
+            }
+        }
+
+        if (preferredSandbox === 'firejail') {
+            try {
+                console.log("Trying Firejail");
+                return await sandboxWithFirejailOnly(executablePath, args, timeoutMs, workDir);
+            } catch (firejailError) {
+                console.log("Firejail failed, falling back to basic sandbox:", firejailError.message);
+            }
+        }
+
+        // Last resort: basic sandbox with resource limits
+        console.log("Trying basic sandbox");
+        return await sandboxExecutable(executablePath, args, timeoutMs);
+    } catch (error) {
+        console.error("All sandbox methods failed:", error.message);
+        throw error;
+    }
+}
+
+/**
+ * @function sandboxExecutable
+ * @description Runs an executable with basic resource limits using ulimit.
+ * Provides minimal sandboxing with CPU time, file descriptor, and process limits.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ */
+function sandboxExecutable(executablePath, args = [], timeoutMs = 10000) {
+    return new Promise((resolve, reject) => {
+        // Set resource limits using ulimit on Linux
+        const resourceLimits = [
+            'ulimit -t 5',     // CPU time (5 seconds)
+            'ulimit -n 32',    // Max open files
+            // set permission limits
+            'ulimit -u 32'    // Max user processes
+        ].join('; ');
+
+        // Run command with resource limits
+        const cmd = `${resourceLimits}; ${executablePath} ${args.join(' ')}`;
+        const process = spawn('bash', ['-c', cmd], {
+            cwd: path.dirname(executablePath),
+            stdio: 'pipe',
+            timeout: timeoutMs,
+        });
+
+        let stdout = '';
+        let stderr = '';
+
+        process.stdout.on('data', (data) => {
+            stdout += data.toString();
+        });
+
+        process.stderr.on('data', (data) => {
+            stderr += data.toString();
+        });
+
+        process.on('close', (code) => {
+            resolve({
+                code,
+                stdout,
+                stderr,
+                success: code === 0
+            });
+        });
+
+        process.on('error', (err) => {
+            reject(err);
+        });
+
+        // Handle timeout
+        setTimeout(() => {
+            if (!process.killed) {
+                process.kill('SIGKILL');
+                reject(new Error('Process execution timed out'));
+            }
+        }, timeoutMs);
+    });
+}
+
+/**
+ * @function sandboxWithQemu
+ * @description Runs an executable in a QEMU system-mode virtual machine for maximum isolation.
+ * Creates a minimal VM environment with custom kernel and initrd.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When QEMU is not installed or VM creation fails
+ */
+function sandboxWithQemu(executablePath, args = [], timeoutMs = 10000) {
+    return new Promise((resolve, reject) => {
+        // Ensure the executable exists
+        if (!fs.existsSync(executablePath)) {
+            return reject(new Error(`Executable not found: ${executablePath}`));
+        }
+
+        // Create a temporary directory for the VM's filesystem
+        const vmId = crypto.randomBytes(8).toString('hex');
+        const vmDir = path.join(os.tmpdir(), `qemu-sandbox-${vmId}`);
+        fs.mkdirSync(vmDir, { recursive: true });
+
+        // Create a minimal filesystem structure for the VM
+        const vmBinDir = path.join(vmDir, 'bin');
+        fs.mkdirSync(vmBinDir, { recursive: true });
+
+        // Copy the executable to the VM directory
+        const execName = path.basename(executablePath);
+        const vmExecPath = path.join(vmBinDir, execName);
+        fs.copyFileSync(executablePath, vmExecPath);
+        fs.chmodSync(vmExecPath, 0o755); // Make it executable
+
+        // Create a script to run the executable with arguments
+        const scriptContent = `#!/bin/sh
+cd /bin
+./${execName} ${args.join(' ')}
+exit $?
+`;
+        const scriptPath = path.join(vmDir, 'run.sh');
+        fs.writeFileSync(scriptPath, scriptContent);
+        fs.chmodSync(scriptPath, 0o755);
+
+        // Create a minimal initrd
+        const initrdPath = path.join(vmDir, 'initrd.img');
+        const initrdContent = `#!/bin/sh
+mount -t proc none /proc
+mount -t sysfs none /sys
+mount -t devtmpfs none /dev
+exec /bin/sh
+`;
+        fs.writeFileSync(initrdPath, initrdContent);
+        fs.chmodSync(initrdPath, 0o755);
+
+        // QEMU parameters with correct kernel path
+        const qemuArgs = [
+            '-nographic',               // No GUI
+            '-m', '64',                 // 64MB RAM
+            '-no-reboot',               // Don't reboot on crash
+            '-kernel', '/boot/vmlinuz-linux-lts', // Use the LTS kernel
+            '-initrd', initrdPath,      // Use our minimal initrd
+            '-append', 'console=ttyS0 panic=1 rootfstype=9p root=/dev/root rw init=/run.sh',
+            '-virtfs', `local,id=root,path=${vmDir},security_model=none,mount_tag=/dev/root`,
+            '-net', 'none'             // No network
+        ];
+
+        console.log(`Running with QEMU: ${executablePath} ${args.join(' ')}`);
+
+        const process = spawn('qemu-system-x86_64', qemuArgs, {
+            stdio: 'pipe',
+            timeout: timeoutMs
+        });
+
+        let stdout = '';
+        let stderr = '';
+
+        process.stdout.on('data', (data) => {
+            stdout += data.toString();
+        });
+
+        process.stderr.on('data', (data) => {
+            stderr += data.toString();
+        });
+
+        process.on('close', (code) => {
+            // Clean up temporary VM directory
+            try {
+                fs.rmSync(vmDir, { recursive: true, force: true });
+            } catch (error) {
+                console.error(`Failed to clean up VM directory ${vmDir}:`, error);
+            }
+
+            resolve({
+                code,
+                stdout,
+                stderr,
+                success: code === 0
+            });
+        });
+
+        process.on('error', (err) => {
+            // Clean up on error
+            try {
+                fs.rmSync(vmDir, { recursive: true, force: true });
+            } catch (cleanupError) {
+                console.error(`Failed to clean up VM directory ${vmDir}:`, cleanupError);
+            }
+
+            // Handle command not found error
+            if (err.code === 'ENOENT') {
+                reject(new Error('QEMU is not installed. Please install qemu-system-x86_64 first.'));
+            } else {
+                reject(err);
+            }
+        });
+
+        // Handle timeout
+        setTimeout(() => {
+            if (!process.killed) {
+                process.kill('SIGKILL');
+                reject(new Error('Process execution timed out'));
+            }
+        }, timeoutMs);
+    });
+}
+
+/**
+ * @function sandboxWithFirejailOnly
+ * @description Runs an executable in a Firejail sandbox with resource and network restrictions.
+ * Applies ulimit for memory (500MB) and uses firejail for network and filesystem isolation.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @param {string} workDir - Working directory for the sandbox
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When Firejail is not installed or execution fails
+ */
+function sandboxWithFirejailOnly(
+    executablePath,
+    args = [],
+    timeoutMs = 10000,
+    workDir = null
+) {
+    const path = require('path');
+    const fs = require('fs');
+    const { spawn } = require('child_process');
+
+    return new Promise((resolve, reject) => {
+        if (!fs.existsSync(executablePath)) {
+            return reject(new Error(`Executable not found: ${executablePath}`));
+        }
+        console.log('fnuersjingvjfkdesnfdsiknbfsdjkl:wnbk workDir', workDir);
+        const sandboxDir = workDir || path.join(os.tmpdir(), `firejail-sandbox-${crypto.randomBytes(8).toString('hex')}`);
+        console.log('fnuersjingvjfkdesnfdsiknbfsdjkl:wnbk sandoxDir', sandboxDir);
+        if (!workDir) {
+            console.log('creating sandboxDir', sandboxDir);
+            fs.mkdirSync(sandboxDir, { recursive: true });
+        }
+        // fs.mkdirSync(sandboxDir, { recursive: true });
+        const binaryName = path.basename(executablePath);
+        const sandboxBinaryPath = path.join(sandboxDir, binaryName);
+        fs.copyFileSync(executablePath, sandboxBinaryPath);
+        fs.chmodSync(sandboxBinaryPath, 0o755); // Ensure it's executable
+        // Compose the shell command with ulimit and firejail restrictions
+        // --net=none disables network, --private uses a private /tmp and home
+        // ulimit -v: max virtual memory (KB)
+        console.log('./' + path.basename(executablePath));
+        console.log('args', args);
+        const shellCmd = [
+            // 'ulimit -v 100000;',         // 100MB memory limit
+            'exec',
+            'firejail',
+            '--quiet',
+            '--noprofile',
+            '--net=none',
+            '--private=' + sandboxDir,
+            '--private-tmp',
+            // '--private-dev',
+            '--blacklist=/var',
+            '--blacklist=/etc/shadow',
+            '--blacklist=/etc/passwd',
+            '--blacklist=/tmp',
+            './' + path.basename(executablePath),
+            ...args
+        ].join(' ');
+
+        console.log(`Running with firejail (ulimit + firejail): ${shellCmd}`);
+        try {
+
+            const child = spawn('bash', ['-c', shellCmd], {
+                cwd: path.dirname(executablePath),
+                stdio: 'pipe',
+                timeout: timeoutMs
+            });
+
+            let stdout = '';
+            let stderr = '';
+
+            child.stdout.on('data', (data) => {
+                stdout += data.toString();
+            });
+
+            child.stderr.on('data', (data) => {
+                stderr += data.toString();
+            });
+
+            child.on('close', (code) => {
+                resolve({
+                    code,
+                    stdout,
+                    stderr,
+                    success: code === 0
+                });
+                // Clean up temporary sandbox directory
+                try {
+                    fs.rmSync(sandboxDir, { recursive: true, force: true });
+                } catch (error) {
+                    console.error(`Failed to clean up sandbox directory ${sandboxDir}:`, error);
+                }
+            });
+
+            child.on('error', (err) => {
+                if (err.code === 'ENOENT') {
+                    reject(new Error('firejail is not installed. Please install firejail.'));
+                } else {
+                    reject(err);
+                }
+                // Clean up temporary sandbox directory
+                try {
+                    fs.rmSync(sandboxDir, { recursive: true, force: true });
+                } catch (error) {
+                    console.error(`Failed to clean up sandbox directory ${sandboxDir}:`, error);
+                }
+            });
+
+            setTimeout(() => {
+                if (!child.killed) {
+                    child.kill('SIGKILL');
+                    reject(new Error('child execution timed out'));
+                }
+            }, timeoutMs);
+        } catch (error) {
+            console.error('error ', error);
+        }
+    });
+}
+
+/**
+ * @function sandboxWithQemuUser
+ * @description Alternative QEMU sandboxing approach using user-mode emulation.
+ * Now applies ulimit (memory/process) and firejail (network/filesystem) restrictions.
+ * @param {string} executablePath - Path to the executable to run
+ * @param {Array} args - Command line arguments for the executable
+ * @param {number} timeoutMs - Execution timeout in milliseconds
+ * @param {string} libRoot - Library root path for QEMU user-mode
+ * @param {string|null} customLibDir - Custom library directory path
+ * @returns {Promise<Object>} Execution result with code, stdout, stderr, and success status
+ * @throws {Error} When QEMU user-mode or Firejail is not installed
+ */
+function sandboxWithQemuUser(
+    executablePath,
+    args = [],
+    timeoutMs = 10000,
+    libRoot = '/usr/x86_64-linux-gnu',
+    customLibDir = null
+) {
+    const path = require('path');
+    const fs = require('fs');
+    const { spawn } = require('child_process');
+
+    return new Promise((resolve, reject) => {
+        if (!fs.existsSync(executablePath)) {
+            return reject(new Error(`Executable not found: ${executablePath}`));
+        }
+
+        const qemuBinary = 'qemu-x86_64';
+
+        // Compose the shell command with ulimit and firejail restrictions
+        // --net=none disables network, --private uses a private /tmp and home
+        // ulimit -v: max virtual memory (KB), ulimit -u: max user processes
+        const shellCmd = [
+            'ulimit -v 500000;',         // 500MB memory limit
+            //            'ulimit -u 128;',             // Max 32 processes
+            'exec',
+            'firejail',
+            '--quiet',
+            '--noprofile',
+            '--net=none',
+            '--private',
+            qemuBinary,
+            '-L', libRoot,
+            executablePath,
+            ...args
+        ].join(' ');
+
+        // Set up environment
+        const env = { ...process.env };
+        if (customLibDir) {
+            env.LD_LIBRARY_PATH = customLibDir;
+        }
+
+        console.log(`Running with QEMU user-mode (ulimit + firejail): ${shellCmd}`);
+
+        const child = spawn('bash', ['-c', shellCmd], {
+            cwd: path.dirname(executablePath),
+            stdio: 'pipe',
+            timeout: timeoutMs,
+            env
+        });
+
+        let stdout = '';
+        let stderr = '';
+
+        child.stdout.on('data', (data) => {
+            stdout += data.toString();
+        });
+
+        child.stderr.on('data', (data) => {
+            stderr += data.toString();
+        });
+
+        child.on('close', (code) => {
+            resolve({
+                code,
+                stdout,
+                stderr,
+                success: code === 0
+            });
+        });
+
+        child.on('error', (err) => {
+            if (err.code === 'ENOENT') {
+                reject(new Error('QEMU user-mode emulation or firejail is not installed. Please install qemu-user and firejail.'));
+            } else {
+                reject(err);
+            }
+        });
+
+        setTimeout(() => {
+            if (!child.killed) {
+                child.kill('SIGKILL');
+                reject(new Error('child execution timed out'));
+            }
+        }, timeoutMs);
+    });
+}
+
+module.exports = {
+    createSandbox,
+    cleanupSandbox,
+    sandboxWithBubblewrap,
+    sandboxWithFirejail,
+    sandboxWithBestMethod,
+    sandboxExecutable,
+    sandboxWithQemu,
+    sandboxWithFirejailOnly
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_sarifParser.js.html b/server/docs/services_sarifParser.js.html new file mode 100644 index 0000000..9813c8d --- /dev/null +++ b/server/docs/services_sarifParser.js.html @@ -0,0 +1,162 @@ + + + + + JSDoc: Source: services/sarifParser.js + + + + + + + + + + +
+ +

Source: services/sarifParser.js

+ + + + + + +
+
+
/**
+ * @module SarifParser
+ * @description SARIF (Static Analysis Results Interchange Format) parser for processing analysis tool outputs.
+ * Extracts and parses JSON blocks from mixed log output to provide structured analysis results.
+ */
+
+/**
+ * @function extractSarifBlocks
+ * @description Extracts SARIF JSON blocks from mixed output text using regex pattern matching.
+ * @param {string} output - Mixed output text that may contain SARIF JSON blocks
+ * @returns {Array<string>} Array of extracted SARIF JSON strings, empty array if none found
+ */
+function extractSarifBlocks(output) {
+    // This regex finds top-level JSON objects (not perfect, but works for SARIF blocks)
+    const regex = /{[\s\S]*?"runs":\s*\[[\s\S]*?\][\s\S]*?}/g;
+    return output.match(regex) || [];
+}
+
+/**
+ * @function parseSarifResults
+ * @description Parses a single SARIF JSON string and extracts structured results with tool information.
+ * @param {string} sarifJson - SARIF JSON string to parse
+ * @returns {Array<Object>} Array of parsed results with tool, message, and location information
+ */
+function parseSarifResults(sarifJson) {
+    const results = [];
+    const sarif = JSON.parse(sarifJson);
+    if (!sarif.runs) return results;
+    for (const run of sarif.runs) {
+        const tool = run.tool?.driver?.name || "unknown";
+        for (const result of run.results || []) {
+            const message = result.message?.text || "";
+            const locations = (result.locations || []).map(loc => {
+                const phys = loc.physicalLocation || {};
+                const region = phys.region || {};
+                return {
+                    file: phys.artifactLocation?.uri,
+                    startLine: region.startLine,
+                    startColumn: region.startColumn,
+                    endColumn: region.endColumn,
+                    snippet: region.snippet?.text
+                };
+            });
+            results.push({
+                tool,
+                message,
+                locations
+            });
+        }
+    }
+    return results;
+}
+
+/**
+ * @function parseToolOutputs
+ * @description Main function to parse mixed tool outputs and extract structured analysis results.
+ * Processes multiple JSON blocks from analysis tool output and organizes results by tool.
+ * @param {string} outputText - Mixed output text from analysis tools containing JSON blocks
+ * @returns {Array<Object>} Array of tool results with tool name and findings
+ */
+function parseToolOutputs(outputText) {
+    const toolResults = [];
+
+    // Match all JSON blocks (assuming each JSON starts with { and ends with })
+    const jsonBlocks = [...outputText.matchAll(/\{[\s\S]*?\n\}/g)];
+
+    for (const match of jsonBlocks) {
+        try {
+            const json = JSON.parse(match[0]);
+            if (!json.runs || !Array.isArray(json.runs)) continue;
+
+            for (const run of json.runs) {
+                const toolName = run.tool?.driver?.name || 'Unknown Tool';
+                const results = [];
+
+                for (const result of run.results || []) {
+                    const message = result.message?.text || '';
+                    const locations = result.locations?.map(loc => {
+                        const phys = loc.physicalLocation || {};
+                        const region = phys.region || {};
+                        return {
+                            file: phys.artifactLocation?.uri || '',
+                            startLine: region.startLine || null,
+                            startColumn: region.startColumn || null,
+                            endColumn: region.endColumn || null,
+                            snippet: region.snippet?.text || ''
+                        };
+                    }) || [];
+
+                    results.push({ message, locations });
+                }
+
+                toolResults.push({
+                    tool: toolName,
+                    results
+                });
+            }
+        } catch (e) {
+            // Invalid JSON block, skip
+            continue;
+        }
+    }
+
+    return toolResults;
+}
+
+module.exports = {
+    extractSarifBlocks,
+    parseSarifResults,
+    parseToolOutputs
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/services_toolsService.js.html b/server/docs/services_toolsService.js.html new file mode 100644 index 0000000..afd2e4a --- /dev/null +++ b/server/docs/services_toolsService.js.html @@ -0,0 +1,93 @@ + + + + + JSDoc: Source: services/toolsService.js + + + + + + + + + + +
+ +

Source: services/toolsService.js

+ + + + + + +
+
+
/**
+ * @module ToolsService
+ * @description Service for retrieving information about available analysis tools from ctrace.
+ * Provides functionality to query and parse available tools for code analysis.
+ */
+
+const { exec } = require('child_process');
+const path = require('path');
+
+/**
+ * @function getAvailableTools
+ * @description Retrieves available analysis tools by executing `ctrace --help` and parsing the output.
+ * Extracts tool information from the help output and returns a structured list of available tools.
+ * @returns {Promise<Array<string>>} Array of available tool names
+ * @throws {Error} When ctrace execution fails or tool parsing fails
+ * 
+ * @example
+ * const tools = await getAvailableTools();
+ * // Returns: ['flawfinder', 'cppcheck', 'clang-tidy']
+ */
+async function getAvailableTools() {
+  const ctracePath = path.join(__dirname, '../../server/bin/ctrace');
+
+  return new Promise((resolve, reject) => {
+    exec(`${ctracePath} --help`, (error, stdout, stderr) => {
+      if (error) {
+        console.error('Error executing ctrace:', stderr);
+        return reject(error);
+      }
+
+      // Parse the output to extract tools
+      const toolsMatch = stdout.match(/Available tools: (.+)/);
+      if (toolsMatch && toolsMatch[1]) {
+        const tools = toolsMatch[1].split(',').map(tool => tool.trim());
+        return resolve(tools);
+      }
+
+      reject(new Error('Failed to parse available tools from ctrace output'));
+    });
+  });
+}
+
+module.exports = { getAvailableTools };
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Wed Jul 09 2025 08:50:31 GMT+0400 (Réunion Time) +
+ + + + + diff --git a/server/docs/styles/jsdoc-default.css b/server/docs/styles/jsdoc-default.css new file mode 100644 index 0000000..7d1729d --- /dev/null +++ b/server/docs/styles/jsdoc-default.css @@ -0,0 +1,358 @@ +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html +{ + overflow: auto; + background-color: #fff; + font-size: 14px; +} + +body +{ + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +a, a:visited, a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header +{ + display: block; + padding: 0px 4px; +} + +tt, code, kbd, samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +#main { + float: left; + width: 70%; +} + +article dl { + margin-bottom: 40px; +} + +article img { + max-width: 100%; +} + +section +{ + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav +{ + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav ul a, nav ul a:visited, nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4D4E53; +} + +nav h3 { + margin-top: 12px; +} + +nav li { + margin-top: 6px; +} + +footer { + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; +} + +h1, h2, h3, h4 { + font-weight: 200; + margin: 0; +} + +h1 +{ + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; +} + +h2, h3.subsection-title +{ + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h3 +{ + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; +} + +h4 +{ + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; +} + +h5, .container-overview .subsection-title +{ + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 +{ + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +table +{ + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +td, th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +thead tr +{ + background-color: #ddd; + font-weight: bold; +} + +th { border-right: 1px solid #aaa; } +tr > th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/server/docs/styles/prettify-jsdoc.css b/server/docs/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/server/docs/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/server/docs/styles/prettify-tomorrow.css b/server/docs/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/server/docs/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/server/jsdoc.json b/server/jsdoc.json new file mode 100644 index 0000000..7778f7a --- /dev/null +++ b/server/jsdoc.json @@ -0,0 +1,19 @@ +{ + "source": { + "include": [ + "services/", + "routes/", + "controllers/", + "middlewares/" + ], + "exclude": [ + "node_modules", + "temp" + ] + }, + "opts": { + "destination": "./docs", + "recurse": true, + "template": "node_modules/jsdoc/templates/default" + } +} \ No newline at end of file diff --git a/server/middlewares/errorHandler.js b/server/middlewares/errorHandler.js index e2feaf5..a8efb0a 100644 --- a/server/middlewares/errorHandler.js +++ b/server/middlewares/errorHandler.js @@ -2,9 +2,9 @@ * Middleware function to handle errors in the application. * * @param {Error} err - The error object containing details about the error. - * @param {import('express').Request} req - The Express request object. - * @param {import('express').Response} res - The Express response object. - * @param {import('express').NextFunction} next - The next middleware function in the stack. + * @param {Object} req - The Express request object. + * @param {Object} res - The Express response object. + * @param {Function} next - The next middleware function in the stack. * * Logs the error stack trace for debugging purposes and sends an appropriate * JSON response to the client. In non-production environments, the error message diff --git a/server/package-lock.json b/server/package-lock.json index 69482e8..81d7a3e 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -15,9 +15,64 @@ "winston": "^3.17.0" }, "devDependencies": { + "jsdoc": "^4.0.4", + "eslint": "^8.57.1", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.31.0", + "jest": "^29.7.0", "nodemon": "^3.0.1" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "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": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", + "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", @@ -36,6 +91,44 @@ "kuler": "^2.0.0" } }, + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", @@ -54,6 +147,101 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -68,6 +256,37 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -99,6 +318,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -147,6 +373,56 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -156,6 +432,25 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -185,6 +480,110 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -257,6 +656,13 @@ "dev": true, "license": "MIT" }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true, + "license": "MIT" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -278,6 +684,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", @@ -306,35 +719,194 @@ "node": ">= 0.10" } }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">= 0.8" + "node": ">= 8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dotenv": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { "version": "16.5.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", @@ -379,6 +951,95 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.10", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz", + "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -409,386 +1070,1506 @@ "node": ">= 0.4" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "hasown": "^2.0.2" }, "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.4" } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, "engines": { - "node": ">= 0.8" + "node": ">=6" } }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" }, "engines": { - "node": ">= 0.4" + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, "engines": { - "node": ">= 0.4" + "node": ">=4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" + "ms": "^2.1.1" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">= 0.8" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "ISC" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "license": "MIT" }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "binary-extensions": "^2.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/eslint/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10.13.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/logform": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", - "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" + "estraverse": "^5.1.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=0.10" } }, - "node_modules/logform/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz", + "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/hpp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hpp/-/hpp-0.2.3.tgz", + "integrity": "sha512-4zDZypjQcxK/8pfFNR7jaON7zEUpXZxz4viyFmqjb3kWNWAHsLEUmWXcdn25c5l76ISvnD6hbOGO97cXUI3Ryw==", + "license": "ISC", + "dependencies": { + "lodash": "^4.17.12", + "type-is": "^1.6.12" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz", + "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "license": "Unlicense", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", @@ -796,310 +2577,948 @@ "node": ">= 0.4" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/merge-descriptors": { + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "p-limit": "^2.2.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8.0" } }, - "node_modules/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=6.0" + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": ">= 0.10" } }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true, "license": "MIT" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, "engines": { - "node": ">= 0.4" + "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8" } }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "fn.name": "1.x.x" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">= 0.8" + "node": ">=8.10.0" } }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, "engines": { - "node": ">=8.6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, "engines": { - "node": ">= 0.8" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "glob": "^7.1.3" }, - "engines": { - "node": ">= 6" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" }, "engines": { - "node": ">=8.10.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/safe-buffer": { @@ -1137,9 +3556,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -1203,12 +3622,84 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -1327,6 +3818,19 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1398,6 +3902,110 @@ "node": ">= 0.6" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -1405,6 +4013,20 @@ "dev": true, "license": "MIT" }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1441,6 +4063,21 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1483,6 +4120,13 @@ "engines": { "node": ">= 12.0.0" } + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true, + "license": "Apache-2.0" } } } diff --git a/server/package.json b/server/package.json index 7177e48..0f12c25 100644 --- a/server/package.json +++ b/server/package.json @@ -5,7 +5,12 @@ "main": "server.js", "scripts": { "start": "node server.js", - "dev": "nodemon server.js" + "dev": "nodemon server.js", + "docs": "jsdoc -c jsdoc.json", + "build": "echo 'No build step required for server'", + "test": "jest", + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "dependencies": { "cors": "^2.8.5", @@ -15,6 +20,11 @@ "winston": "^3.17.0" }, "devDependencies": { + "jsdoc": "^4.0.4", + "eslint": "^8.57.1", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.31.0", + "jest": "^29.7.0", "nodemon": "^3.0.1" } -} +} \ No newline at end of file diff --git a/server/routes/analyze.js b/server/routes/analyze.js index aafc91a..a08ac32 100644 --- a/server/routes/analyze.js +++ b/server/routes/analyze.js @@ -1,15 +1,43 @@ +/** + * @module AnalyzeRoutes + * @description Express routes for code analysis functionality. + * Handles file upload, validation, and analysis requests using the analyzer service. + */ + const express = require('express'); const analyzer = require('../services/analyzer'); +/** + * @type {express.Router} + * @description Router instance for analysis-related endpoints. + */ const router = express.Router(); /** * @route POST /api/analyze - * @description Submit code for analysis with CoreTrace + * @description Submit code files for security analysis using CoreTrace and flawfinder tools. + * Accepts C/C++ source files and analysis options, returns structured analysis results. + * * @param {Object} req - Express request object - * @param {Object} req.body - Request body containing files and options + * @param {Object} req.body - Request body containing files and analysis options + * @param {Object} req.body.files - Object with filename-content pairs of C/C++ files to analyze + * @param {Object} [req.body.options] - Analysis options including static/dynamic flags + * @param {boolean} [req.body.options.static] - Enable static analysis + * @param {boolean} [req.body.options.dynamic] - Enable dynamic analysis * @param {Object} res - Express response object - * @returns {void} + * @returns {Object} JSON response with analysis results or error message + * + * @example + * POST /api/analyze + * { + * "files": { + * "main.c": "#include \nint main() { return 0; }" + * }, + * "options": { + * "static": true, + * "dynamic": false + * } + * } */ router.post('/', async (req, res) => { try { diff --git a/server/routes/index.js b/server/routes/index.js index 60a27a4..3fa3233 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -1,10 +1,21 @@ +/** + * @module Routes + * @description Main router configuration that mounts all application routes. + * Centralizes route organization and provides a single entry point for all API endpoints. + */ + const express = require('express'); const analyzeRoutes = require('./analyze'); const examplesRoutes = require('./examples'); const toolsRoutes = require('./tools'); +/** + * @type {express.Router} + * @description Express router instance that mounts all application routes. + */ const router = express.Router(); +// Mount route modules router.use('/analyze', analyzeRoutes); router.use('/examples', examplesRoutes); router.use('/tools', toolsRoutes); diff --git a/server/routes/tools.js b/server/routes/tools.js index b677160..b6cdf59 100644 --- a/server/routes/tools.js +++ b/server/routes/tools.js @@ -1,11 +1,39 @@ +/** + * @module ToolsRoutes + * @description Express routes for analysis tools functionality. + * Provides information about available analysis tools and their capabilities. + */ + const express = require('express'); const { getAvailableTools } = require('../services/toolsService'); +/** + * @type {express.Router} + * @description Router instance for tools-related endpoints. + */ const router = express.Router(); /** * @route GET /api/tools - * @description Retrieve available tools from ctrace + * @description Retrieve information about available analysis tools from ctrace. + * Returns a list of tools that can be used for code analysis, including their + * names, descriptions, and capabilities. + * + * @param {Object} req - Express request object + * @param {Object} res - Express response object + * @returns {Object} JSON response with array of available tools + * + * @example + * GET /api/tools + * Response: { + * "tools": [ + * { + * "name": "flawfinder", + * "description": "Static analysis tool for finding security vulnerabilities", + * "version": "2.0.19" + * } + * ] + * } */ router.get('/', async (req, res) => { try { diff --git a/server/server.js b/server/server.js index ce42f9f..f83c12b 100644 --- a/server/server.js +++ b/server/server.js @@ -1,79 +1,22 @@ -// const express = require('express'); -// const cors = require('cors'); -// const path = require('path'); -// const routes = require('./routes'); -// const { exec } = require('child_process'); -// const fs = require('fs'); -// const os = require('os'); -// const { v4: uuidv4 } = require('uuid'); - -// const app = express(); -// const PORT = process.env.PORT || 5000; - -// // Middleware -// app.use(cors()); -// app.use(express.json({ limit: '10mb' })); -// app.use(express.static(path.join(__dirname, '../client/build'))); -// app.use('/api', routes); - -// app.get('/health', (req, res) => { -// res.status(200).json({ status: 'ok' }); -// }); - -// // Endpoint to analyze code -// app.post('/api/analyze', async (req, res) => { -// try { -// const { files, options } = req.body; - -// if (!files || Object.keys(files).length === 0) { -// return res.status(400).json({ error: 'No files provided' }); -// } - -// // Validate file sizes and content -// for (const [filename, content] of Object.entries(files)) { -// if (typeof content !== 'string') { -// return res.status(400).json({ error: 'File content must be a string' }); -// } - -// if (content.length > 1000000) { // 1MB limit per file -// return res.status(400).json({ error: 'File size exceeds the limit (1MB)' }); -// } - -// if (!filename.match(/\.(c|cpp|h|hpp)$/i)) { -// return res.status(400).json({ error: 'Only C/C++ files are allowed' }); -// } -// } - -// const result = await runCoreTrace(files, options || {}); -// res.json(result); -// } catch (error) { -// console.error('Error analyzing code:', error); -// res.status(500).json({ error: 'An error occurred during analysis' }); -// } -// }); - -// // Catch-all handler for client-side routing -// app.get('*', (req, res) => { -// res.sendFile(path.join(__dirname, '../client/build', 'index.html')); -// }); - -// app.use((err, req, res, next) => { -// console.error(err.stack); -// res.status(500).json({ -// error: 'An unexpected error occurred', -// message: process.env.NODE_ENV === 'production' ? undefined : err.message -// }); -// }); - -// app.listen(PORT, () => { -// console.log(`Server running on port ${PORT}`); -// }); - -// module.exports = app; +/** + * @module Server + * @description HTTP server entry point for the CoreTrace web application. + * Starts the Express application on the configured port and handles server lifecycle. + */ const app = require('./app'); + +/** + * @type {number} + * @description Port number for the HTTP server, defaults to 5000 if not specified in environment. + */ const PORT = process.env.PORT || 5000; +/** + * @function startServer + * @description Starts the HTTP server and logs the port number. + * The server will listen for incoming HTTP requests on the specified port. + */ app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); \ No newline at end of file diff --git a/server/services/analyzer.js b/server/services/analyzer.js index b64d8e4..b0a9561 100644 --- a/server/services/analyzer.js +++ b/server/services/analyzer.js @@ -1,3 +1,9 @@ +/** + * @module Analyzer + * @description Core analysis service that handles code analysis using ctrace and flawfinder tools. + * Manages file processing, sandbox execution, and result parsing for security analysis. + */ + // services/analyzer.js const fs = require('fs'); const path = require('path'); @@ -10,12 +16,31 @@ const { parseToolOutputs } = require('./sarifParser'); // In-memory store for analysis jobs (would use a database in production) const analysisJobs = new Map(); +/** + * @class Analyzer + * @description Main analyzer class that orchestrates code analysis using ctrace and flawfinder. + * Handles file management, executable path resolution, and result processing. + */ class Analyzer { + /** + * @constructor + * @description Initializes the analyzer with executable paths for ctrace and test binaries. + */ constructor() { this.ctraceExecutable = path.join(__dirname, '../../server/bin/ctrace'); this.testExecutable = path.join(__dirname, '../../server/bin/test'); } + /** + * @method analyzeCode + * @description Performs comprehensive code analysis on uploaded files using ctrace and flawfinder. + * @param {Object} files - Object containing filename-content pairs of files to analyze + * @param {Object} options - Analysis options including static/dynamic flags + * @param {boolean} [options.static] - Enable static analysis + * @param {boolean} [options.dynamic] - Enable dynamic analysis + * @returns {Promise} Parsed analysis results with tool-specific findings + * @throws {Error} When file validation fails or analysis execution errors occur + */ async analyzeCode(files, options) { logger.info('Starting analysis', { files: Object.keys(files), options }); @@ -55,10 +80,23 @@ class Analyzer { } } + /** + * @method getExecutablePath + * @description Determines the appropriate executable path, falling back to test executable if ctrace is not available. + * @returns {string} Path to the executable to use for analysis + */ getExecutablePath() { return fs.existsSync(this.ctraceExecutable) ? this.ctraceExecutable : this.testExecutable; } + /** + * @method saveFilesToWorkDir + * @description Saves uploaded files to the working directory and sets up flawfinder environment. + * @param {string} workDir - Working directory path where files should be saved + * @param {Object} files - Object containing filename-content pairs + * @returns {Array} Array of saved file paths + * @throws {Error} When flawfinder.py is not found or file operations fail + */ saveFilesToWorkDir(workDir, files) { const filePaths = []; @@ -86,6 +124,14 @@ class Analyzer { return filePaths; } + /** + * @method buildArguments + * @description Builds command line arguments for the analysis executable based on options and file paths. + * @param {Array} filePaths - Array of file paths to analyze + * @param {Object} options - Analysis options including static/dynamic flags + * @param {string} workDir - Working directory path + * @returns {Array} Array of command line arguments + */ buildArguments(filePaths, options, workDir) { const args = []; const execPath = this.getExecutablePath(); @@ -105,6 +151,15 @@ class Analyzer { return args; } + /** + * @method runAnalysis + * @description Executes the analysis in a sandboxed environment and processes the results. + * @param {string} execPath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {string} jobId - Unique job identifier + * @param {string} workDir - Working directory path + * @returns {Promise} Parsed analysis results with tool-specific findings + */ async runAnalysis(execPath, args, jobId, workDir) { logger.info('Running analysis in sandbox', { jobId, execPath, args }); @@ -133,6 +188,12 @@ class Analyzer { return parsed; } + /** + * @method cleanAnsiCodes + * @description Removes ANSI escape codes from text output for cleaner logging. + * @param {string} text - Text that may contain ANSI escape codes + * @returns {string} Cleaned text without ANSI codes + */ cleanAnsiCodes(text) { if (!text) return ''; return text.replace(/\u001b\[\d+m|\[\d+m/g, ''); diff --git a/server/services/jobManager.js b/server/services/jobManager.js index ea5a16f..63c7505 100644 --- a/server/services/jobManager.js +++ b/server/services/jobManager.js @@ -1,15 +1,35 @@ +/** + * @module JobManager + * @description Manages analysis jobs including creation, status tracking, validation, and cleanup. + * Provides job lifecycle management and file validation for the analysis system. + */ + const { v4: uuidv4 } = require('uuid'); const path = require('path'); const fs = require('fs'); const config = require('../config'); const logger = require('./logger'); +/** + * @class JobManager + * @description Handles the complete lifecycle of analysis jobs including creation, tracking, and cleanup. + * Maintains job state in memory and manages file system operations for job directories. + */ class JobManager { + /** + * @constructor + * @description Initializes the job manager with job storage and ensures work directory exists. + */ constructor() { this.jobs = new Map(); this.initializeStorage(); } + /** + * @method initializeStorage + * @description Ensures the job storage directory exists for file operations. + * Creates the work directory if it doesn't exist. + */ initializeStorage() { // Ensure job storage directory exists if (!fs.existsSync(config.filesystem.workDir)) { @@ -17,6 +37,13 @@ class JobManager { } } + /** + * @method createJob + * @description Creates a new analysis job with unique ID and work directory. + * @param {Object} files - Object containing filename-content pairs of files to analyze + * @param {Object} [options={}] - Analysis options and configuration + * @returns {Object} Job object with id, status, startTime, files, options, and workDir + */ createJob(files, options = {}) { console.log('createJob'); const jobId = uuidv4(); @@ -42,6 +69,16 @@ class JobManager { return job; } + /** + * @method updateJobStatus + * @description Updates the status of an existing job and optionally stores results or errors. + * @param {string} jobId - Unique job identifier + * @param {string} status - New status for the job ('created', 'running', 'completed', 'failed') + * @param {Object} [result=null] - Analysis results to store with the job + * @param {string} [error=null] - Error message if job failed + * @returns {Object} Updated job object + * @throws {Error} When job with specified ID is not found + */ updateJobStatus(jobId, status, result = null, error = null) { const job = this.jobs.get(jobId); if (!job) { @@ -64,10 +101,21 @@ class JobManager { return job; } + /** + * @method getJob + * @description Retrieves a job by its unique identifier. + * @param {string} jobId - Unique job identifier + * @returns {Object|null} Job object if found, null otherwise + */ getJob(jobId) { return this.jobs.get(jobId); } + /** + * @method scheduleCleanup + * @description Schedules cleanup of a job after a configurable delay. + * @param {string} jobId - Unique job identifier to schedule cleanup for + */ scheduleCleanup(jobId) { const job = this.jobs.get(jobId); if (!job) return; @@ -78,6 +126,11 @@ class JobManager { }, config.jobs.cleanupDelay); } + /** + * @method cleanupJob + * @description Performs cleanup operations for a job including file removal and memory cleanup. + * @param {string} jobId - Unique job identifier to cleanup + */ cleanupJob(jobId) { const job = this.jobs.get(jobId); if (!job) return; @@ -99,6 +152,12 @@ class JobManager { } } + /** + * @method validateFiles + * @description Validates uploaded files for security, size, and format requirements. + * @param {Object} files - Object containing filename-content pairs to validate + * @returns {Array} Array of validation error messages, empty if validation passes + */ validateFiles(files) { const errors = []; diff --git a/server/services/logger.js b/server/services/logger.js index 961dde1..48b8ab0 100644 --- a/server/services/logger.js +++ b/server/services/logger.js @@ -1,6 +1,17 @@ +/** + * @module Logger + * @description Centralized logging service using Winston for structured logging across the application. + * Provides console and file-based logging with request tracking capabilities. + */ + const winston = require('winston'); const config = require('../config'); +/** + * @type {winston.Logger} + * @description Winston logger instance configured with console and file transports. + * Supports different log levels and formats for development and production environments. + */ const logger = winston.createLogger({ level: config.logging.level, format: winston.format.combine( @@ -24,7 +35,14 @@ const logger = winston.createLogger({ ] }); -// Add request ID to logs +/** + * @function requestLogger + * @description Express middleware for logging incoming HTTP requests with request ID tracking. + * Adds request ID to the request object and logs request details for debugging and monitoring. + * @param {Object} req - Express request object + * @param {Object} res - Express response object + * @param {Function} next - Express next middleware function + */ logger.requestLogger = (req, res, next) => { req.requestId = req.headers['x-request-id'] || Math.random().toString(36).substring(7); logger.info('Incoming request', { diff --git a/server/services/sandbox.js b/server/services/sandbox.js index 9eba055..12e34cc 100644 --- a/server/services/sandbox.js +++ b/server/services/sandbox.js @@ -1,3 +1,9 @@ +/** + * @module Sandbox + * @description Sandbox execution service providing multiple isolation methods for secure code analysis. + * Supports QEMU virtualization, Firejail, Bubblewrap, and fallback sandboxing with resource limits. + */ + const fs = require('fs'); const path = require('path'); const os = require('os'); @@ -5,13 +11,25 @@ const { spawn, exec } = require('child_process'); const crypto = require('crypto'); const config = require('../config'); require('dotenv').config(); + +/** + * @type {string} + * @description QEMU binary path, configurable via environment variable + */ const qemuBinary = process.env.QEMU_BINARY || 'qemu-x86_64'; + +/** + * @type {string} + * @description Library root path for QEMU user-mode emulation + */ const libRoot = process.env.QEMU_LIB_ROOT || '/usr/x86_64-linux-gnu'; /** - * Create a sandboxed environment for running code analysis - * @param {string} jobId - ID of the analysis job - * @returns {Promise} Path to the sandbox directory + * @function createSandbox + * @description Creates a sandboxed environment for running code analysis with proper permissions. + * @param {string} jobId - Unique identifier for the analysis job + * @returns {Promise} Path to the created sandbox directory + * @throws {Error} When sandbox creation fails */ async function createSandbox(jobId) { // Create a temporary working directory @@ -36,8 +54,10 @@ async function createSandbox(jobId) { } /** - * Clean up the sandbox after analysis is complete - * @param {string} workDir - Path to the sandbox directory + * @function cleanupSandbox + * @description Safely cleans up the sandbox directory after analysis completion. + * Validates the directory path to prevent accidental deletion of system directories. + * @param {string} workDir - Path to the sandbox directory to cleanup * @returns {Promise} */ async function cleanupSandbox(workDir) { @@ -56,11 +76,14 @@ async function cleanupSandbox(workDir) { } /** - * Run an executable in a Bubblewrap sandbox - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution + * @function sandboxWithBubblewrap + * @description Runs an executable in a Bubblewrap sandbox with comprehensive security restrictions. + * Provides namespace isolation, read-only mounts, and network restrictions. + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When Bubblewrap is not installed or execution fails */ function sandboxWithBubblewrap(executablePath, args = [], timeoutMs = 10000) { return new Promise((resolve, reject) => { @@ -147,11 +170,14 @@ function sandboxWithBubblewrap(executablePath, args = [], timeoutMs = 10000) { } /** - * Run an executable in a Firejail sandbox - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution + * @function sandboxWithFirejail + * @description Runs an executable in a Firejail sandbox with comprehensive security restrictions. + * Provides filesystem isolation, capability dropping, and resource limits. + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When Firejail is not installed or execution fails */ function sandboxWithFirejail(executablePath, args = [], timeoutMs = 10000) { return new Promise((resolve, reject) => { @@ -230,12 +256,16 @@ function sandboxWithFirejail(executablePath, args = [], timeoutMs = 10000) { } /** - * Run an executable in the best available sandbox - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @param {string} preferredSandbox - 'bubblewrap', 'firejail', or 'fallback' - * @returns {Promise} Result of the execution + * @function sandboxWithBestMethod + * @description Executes an executable using the best available sandbox method with fallback options. + * Tries preferred sandbox first, then falls back to other methods if available. + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @param {string} preferredSandbox - Preferred sandbox method ('qemu', 'bubblewrap', 'firejail') + * @param {string} workDir - Working directory for the sandbox + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When all sandbox methods fail */ async function sandboxWithBestMethod(executablePath, args = [], timeoutMs = 10000, preferredSandbox = 'qemu', workDir) { console.log("sandboxWithBestMethod", executablePath, args, timeoutMs, preferredSandbox); @@ -279,12 +309,14 @@ async function sandboxWithBestMethod(executablePath, args = [], timeoutMs = 1000 } /** - * sandboxExecutable - Run an executable in a sandboxed environment - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution - * */ + * @function sandboxExecutable + * @description Runs an executable with basic resource limits using ulimit. + * Provides minimal sandboxing with CPU time, file descriptor, and process limits. + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @returns {Promise} Execution result with code, stdout, stderr, and success status + */ function sandboxExecutable(executablePath, args = [], timeoutMs = 10000) { return new Promise((resolve, reject) => { // Set resource limits using ulimit on Linux @@ -338,11 +370,14 @@ function sandboxExecutable(executablePath, args = [], timeoutMs = 10000) { } /** - * Run an executable in a QEMU-based sandbox - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution + * @function sandboxWithQemu + * @description Runs an executable in a QEMU system-mode virtual machine for maximum isolation. + * Creates a minimal VM environment with custom kernel and initrd. + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When QEMU is not installed or VM creation fails */ function sandboxWithQemu(executablePath, args = [], timeoutMs = 10000) { return new Promise((resolve, reject) => { @@ -460,12 +495,15 @@ exec /bin/sh } /** - * Run an executable in a Firejail sandbox with resource and network restrictions. + * @function sandboxWithFirejailOnly + * @description Runs an executable in a Firejail sandbox with resource and network restrictions. * Applies ulimit for memory (500MB) and uses firejail for network and filesystem isolation. - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @param {string} workDir - Working directory for the sandbox + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When Firejail is not installed or execution fails */ function sandboxWithFirejailOnly( executablePath, @@ -578,12 +616,16 @@ function sandboxWithFirejailOnly( } /** - * Alternative QEMU sandboxing approach using user-mode emulation + * @function sandboxWithQemuUser + * @description Alternative QEMU sandboxing approach using user-mode emulation. * Now applies ulimit (memory/process) and firejail (network/filesystem) restrictions. - * @param {string} executablePath - Path to the executable - * @param {Array} args - Arguments to pass to the executable - * @param {number} timeoutMs - Timeout in milliseconds - * @returns {Promise} Result of the execution + * @param {string} executablePath - Path to the executable to run + * @param {Array} args - Command line arguments for the executable + * @param {number} timeoutMs - Execution timeout in milliseconds + * @param {string} libRoot - Library root path for QEMU user-mode + * @param {string|null} customLibDir - Custom library directory path + * @returns {Promise} Execution result with code, stdout, stderr, and success status + * @throws {Error} When QEMU user-mode or Firejail is not installed */ function sandboxWithQemuUser( executablePath, diff --git a/server/services/sarifParser.js b/server/services/sarifParser.js index bb1ca67..e979bdc 100644 --- a/server/services/sarifParser.js +++ b/server/services/sarifParser.js @@ -1,10 +1,27 @@ +/** + * @module SarifParser + * @description SARIF (Static Analysis Results Interchange Format) parser for processing analysis tool outputs. + * Extracts and parses JSON blocks from mixed log output to provide structured analysis results. + */ +/** + * @function extractSarifBlocks + * @description Extracts SARIF JSON blocks from mixed output text using regex pattern matching. + * @param {string} output - Mixed output text that may contain SARIF JSON blocks + * @returns {Array} Array of extracted SARIF JSON strings, empty array if none found + */ function extractSarifBlocks(output) { // This regex finds top-level JSON objects (not perfect, but works for SARIF blocks) const regex = /{[\s\S]*?"runs":\s*\[[\s\S]*?\][\s\S]*?}/g; return output.match(regex) || []; } +/** + * @function parseSarifResults + * @description Parses a single SARIF JSON string and extracts structured results with tool information. + * @param {string} sarifJson - SARIF JSON string to parse + * @returns {Array} Array of parsed results with tool, message, and location information + */ function parseSarifResults(sarifJson) { const results = []; const sarif = JSON.parse(sarifJson); @@ -34,6 +51,13 @@ function parseSarifResults(sarifJson) { return results; } +/** + * @function parseToolOutputs + * @description Main function to parse mixed tool outputs and extract structured analysis results. + * Processes multiple JSON blocks from analysis tool output and organizes results by tool. + * @param {string} outputText - Mixed output text from analysis tools containing JSON blocks + * @returns {Array} Array of tool results with tool name and findings + */ function parseToolOutputs(outputText) { const toolResults = []; @@ -80,7 +104,6 @@ function parseToolOutputs(outputText) { return toolResults; } - module.exports = { extractSarifBlocks, parseSarifResults, diff --git a/server/services/toolsService.js b/server/services/toolsService.js index 285c75b..ddba910 100644 --- a/server/services/toolsService.js +++ b/server/services/toolsService.js @@ -1,9 +1,22 @@ +/** + * @module ToolsService + * @description Service for retrieving information about available analysis tools from ctrace. + * Provides functionality to query and parse available tools for code analysis. + */ + const { exec } = require('child_process'); const path = require('path'); /** - * Get available tools by executing `ctrace --help` - * @returns {Promise} JSON object with static, dynamic, and tools + * @function getAvailableTools + * @description Retrieves available analysis tools by executing `ctrace --help` and parsing the output. + * Extracts tool information from the help output and returns a structured list of available tools. + * @returns {Promise>} Array of available tool names + * @throws {Error} When ctrace execution fails or tool parsing fails + * + * @example + * const tools = await getAvailableTools(); + * // Returns: ['flawfinder', 'cppcheck', 'clang-tidy'] */ async function getAvailableTools() { const ctracePath = path.join(__dirname, '../../server/bin/ctrace');