diff --git a/.github/workflows/Security-hardening.yml b/.github/workflows/Security-hardening.yml index a929a2f..aef83db 100644 --- a/.github/workflows/Security-hardening.yml +++ b/.github/workflows/Security-hardening.yml @@ -2,9 +2,11 @@ name: Security Hardening on: pull_request: - branches: [ "develop" ] + branches: ['develop'] push: - branches: [ "copilot/*" ] branches-ignore: docs + branches: ['copilot/*'] + branches-ignore: + - docs schedule: # Run security checks daily at 2 AM UTC - cron: '0 2 * * *' @@ -13,26 +15,26 @@ jobs: security-audit: name: Security Audit and Dependency Scan runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - + - name: Install dependencies run: npm ci - + - name: Run npm audit run: | echo "Running npm audit..." npm audit --audit-level=high continue-on-error: false - + - name: Check for banned imports in /api run: | echo "Checking for banned database imports in /api directory..." @@ -49,7 +51,7 @@ jobs: exit 1 fi echo "✓ No banned imports found in /api directory" - + - name: Check for committed secrets run: | echo "Checking for accidentally committed secrets..." @@ -66,7 +68,7 @@ jobs: exit 1 fi echo "✓ No obvious secrets found in repository" - + - name: Check SECURITY.md exists run: | if [ ! -f "SECURITY.md" ]; then @@ -74,7 +76,7 @@ jobs: exit 1 fi echo "✓ SECURITY.md exists" - + - name: Check agents.md exists run: | if [ ! -f "agents.md" ]; then @@ -82,7 +84,7 @@ jobs: exit 1 fi echo "✓ agents.md exists" - + - name: Verify TypeScript compilation run: | echo "Checking TypeScript compilation..." @@ -92,20 +94,20 @@ jobs: api-security: name: API Security Checks runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - + - name: Install dependencies run: npm ci - + - name: Check API routes for content-type enforcement run: | echo "Checking API routes for proper content-type handling..." @@ -114,7 +116,7 @@ jobs: echo "WARNING: HTML content detected in API routes - API should return JSON only" fi echo "✓ API content-type check complete" - + - name: Check for SQL injection vulnerabilities run: | echo "Checking for potential SQL injection patterns..." @@ -126,11 +128,11 @@ jobs: pii-detection: name: PII and Sensitive Data Detection runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Check for PII in test files run: | echo "Checking for real PII in test files..." @@ -139,7 +141,7 @@ jobs: echo "WARNING: Real SSN patterns found in tests - use synthetic data only" fi echo "✓ PII detection check complete" - + - name: Check for hardcoded credentials run: | echo "Checking for hardcoded credentials..." @@ -151,11 +153,11 @@ jobs: dependency-pinning: name: Verify Dependency Pinning runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Check for unpinned dependencies run: | echo "Checking package.json for unpinned dependencies..." @@ -168,11 +170,11 @@ jobs: rate-limit-check: name: Verify Rate Limiting runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Check for rate limiting implementation run: | echo "Checking for rate limiting in API routes..." @@ -188,7 +190,7 @@ jobs: runs-on: ubuntu-latest needs: [security-audit, api-security, pii-detection, dependency-pinning, rate-limit-check] if: always() - + steps: - name: Summary run: | diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index eb1da63..00e96b2 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -10,7 +10,7 @@ name: 'Dependency review' on: pull_request: - branches: [ "develop" ] + branches: ['develop'] # If using a dependency submission action in this workflow this permission will need to be set to: # diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 460bc37..45758ae 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,13 +5,15 @@ name: Node.js CI on: push: - branches: [ "develop" ] + branches: ['develop'] pull_request: - branches: [ "develop" ] + branches: ['develop'] + +permissions: + contents: read jobs: build: - runs-on: ubuntu-latest strategy: @@ -20,12 +22,12 @@ jobs: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run build --if-present - - run: npm test + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run build --if-present + - run: npm test diff --git a/README.md b/README.md index 5e9c78d..b636156 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ [![CodeQL](https://github.com/pinkycollie/deaf-first-platform/actions/workflows/github-code-scanning/codeql/badge.svg?branch=main)](https://github.com/pinkycollie/deaf-first-platform/actions/workflows/github-code-scanning/codeql) [![Coverage](https://codecov.io/gh/pinkycollie/deaf-first-platform/branch/main/graph/badge.svg)](https://codecov.io/gh/pinkycollie/deaf-first-platform) [![Copilot code review](https://github.com/pinkycollie/DEAF-FIRST-PLATFORM/actions/workflows/copilot-pull-request-reviewer/copilot-pull-request-reviewer/badge.svg)](https://github.com/pinkycollie/DEAF-FIRST-PLATFORM/actions/workflows/copilot-pull-request-reviewer/copilot-pull-request-reviewer) + # MBTQ Deaf-First Platform A comprehensive platform built with deaf-first principles, providing accessible financial services, AI-powered assistance, and decentralized governance. - + ## 📚 MBTQ Components This repository contains OpenAPI specifications for all five core services of the MBTQ.dev: ### 1. **DeafAUTH - Identity Cortex** + Secure authentication system designed with deaf-first principles. - **Location**: `Services/deafauth/` @@ -18,13 +20,16 @@ Secure authentication system designed with deaf-first principles. - **OpenAPI Spec**: [openapi.yaml](Services/deafauth/openapi/openapi.yaml) ### 2. **PinkSync - Accessibility Engine** + Real-time accessibility features and synchronization. + - **Location**: `Services/pinksync/` - **Base URL**: `https://api.mbtq.dev/sync` (sync.mbtq.dev) - **Documentation**: [PinkSync README](Services/pinksync/README.md) - **OpenAPI Spec**: [openapi.yaml](Services/pinksync/openapi/openapi.yaml) ### 3. **Fibonrose - Trust & Blockchain** + Decentralized trust and verification layer. - **Location**: `Services/fibonrose/` @@ -33,13 +38,16 @@ Decentralized trust and verification layer. - **OpenAPI Spec**: [openapi.yaml](Services/fibonrose/openapi/openapi.yaml) ### 4. **360Magicians - AI Agents** + Intelligent automation and assistance agents. + - **Location**: `Services/magicians/` - **Base URL**: `https://api.mbtq.dev/magicians` magicians.mbtq.dev - **Documentation**: [360Magicians README](Services/magicians/README.md) - **OpenAPI Spec**: [openapi.yaml](Services/magicians/openapi/openapi.yaml) ### 5. **MBTQ DAO - Governance** + Decentralized governance and community management. - **Location**: `Services/dao/` @@ -59,7 +67,7 @@ Decentralized governance and community management. ✔ **Interactive HTML documentation** ✔ **Fetch API examples for browsers** ✔ **Architecture documentation** -✔ Production-ready specifications +✔ Production-ready specifications ## 📖 Documentation @@ -89,6 +97,7 @@ Authorization: Bearer ### Getting Started with Authentication 1. Register a new user: + ```bash curl -X POST https://api.mbtq.dev/auth/register \ -H "Content-Type: application/json" \ @@ -96,6 +105,7 @@ curl -X POST https://api.mbtq.dev/auth/register \ ``` 2. Login to get tokens: + ```bash curl -X POST https://api.mbtq.dev/auth/login \ -H "Content-Type: application/json" \ @@ -103,6 +113,7 @@ curl -X POST https://api.mbtq.dev/auth/login \ ``` 3. Use the access token for API calls: + ```bash curl -X GET https://api.mbtq.dev/sync/status \ -H "Authorization: Bearer " @@ -255,11 +266,11 @@ Generated SDKs will be in the `sdks/` directory. See [SDK.md](SDK.md) for detail ```javascript const deafAuthMiddleware = async (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; - + if (!token) { return res.status(401).json({ error: 'No token provided' }); } - + try { const decoded = await verifyDeafAuthToken(token); req.user = decoded; @@ -277,12 +288,12 @@ module.exports = deafAuthMiddleware; ```javascript const pinkSyncMiddleware = async (req, res, next) => { const userId = req.user?.id; - + if (userId) { const preferences = await getPinkSyncPreferences(userId); req.accessibilityPrefs = preferences; } - + next(); }; @@ -381,6 +392,7 @@ See LICENSE file for details. ## 🌟 Acknowledgments Built with deaf-first principles and a commitment to accessibility for all. + # DEAF-FIRST Platform [![CI/CD Pipeline](https://github.com/pinkycollie/DEAF-FIRST-PLATFORM/actions/workflows/ci.yml/badge.svg)](https://github.com/pinkycollie/DEAF-FIRST-PLATFORM/actions/workflows/ci.yml) @@ -442,23 +454,27 @@ The platform features a modern, cutting-edge showcase interface that demonstrate ## Quick Start 1. Clone the repository: + ```bash git clone https://github.com/pinkycollie/Deaf-First-Platform.git cd Deaf-First-Platform ``` 2. Install dependencies: + ```bash npm install ``` 3. Set up environment variables: + ```bash cp .env.example .env # Edit .env with your configuration ``` 4. Run all services in development mode: + ```bash npm run dev ``` @@ -466,11 +482,13 @@ npm run dev ## Development Scripts ### Run all services + ```bash npm run dev ``` ### Run individual services + ```bash npm run dev:frontend # Frontend only npm run dev:backend # Backend only @@ -481,17 +499,20 @@ npm run dev:a11y # Accessibility nodes only ``` ### Build + ```bash npm run build # Build all workspaces ``` ### Testing + ```bash npm run test # Run all tests npm run test:e2e # Run end-to-end tests ``` ### Code Quality + ```bash npm run lint # Lint all workspaces npm run format # Format code with Prettier @@ -499,6 +520,7 @@ npm run type-check # TypeScript type checking ``` ### Database + ```bash npm run db:setup # Setup databases npm run db:migrate # Run migrations @@ -506,6 +528,7 @@ npm run db:seed # Seed databases ``` ### Docker + ```bash npm run docker:up # Start all services with Docker npm run docker:down # Stop Docker services @@ -525,6 +548,7 @@ npm run dev:backend ``` **Features:** + - Register and manage webhooks via REST API - Receive webhooks from external services (Xano, Stripe, etc.) - HMAC-SHA256 signature verification @@ -533,6 +557,7 @@ npm run dev:backend - Test endpoints for development **Documentation:** + - [Quick Start Guide](./QUICKSTART-WEBHOOKS.md) - Get started in minutes - [API Reference](./WEBHOOK-API.md) - Complete API documentation - [Migration Guide](./WEBHOOK-MIGRATION-GUIDE.md) - Migrate from Xano @@ -560,42 +585,49 @@ To run MCP servers individually: Each workspace is independently versioned and can be developed, tested, and deployed separately. ### Frontend (@deaf-first/frontend) + - React 18 with TypeScript - Vite for fast development - Accessible UI components - Sign language support ### Backend (@deaf-first/backend) + - Express.js REST API - PostgreSQL database - JWT authentication - RESTful endpoints ### DeafAUTH (@mbtq/deafauth) + - Specialized authentication service - Accessible authentication flows - MCP server for auth operations - User preference management ### PinkSync (@mbtq/pinksync) + - Real-time WebSocket synchronization - Redis-based pub/sub - MCP server for sync operations - Event-driven architecture ### FibonRose (@mbtq/fibonrose) + - Mathematical optimization algorithms - Fibonacci-based scheduling - MCP server for optimization queries - Performance analytics ### Accessibility Nodes (@mbtq/accessibility-nodes) + - Modular accessibility features - Sign language interpretation - Visual accessibility enhancements - MCP server for accessibility APIs ### AI Services (@mbtq/ai) + - AI-powered workflows - Natural language processing - Sign language generation @@ -673,6 +705,6 @@ MIT License - see LICENSE file for details - Accessibility - SaaS ecosystem - modules workflows -- http platform management +- http platform management - Real-time synchronization - Sign language support diff --git a/ai/dist/index.d.ts b/ai/dist/index.d.ts new file mode 100644 index 0000000..0a3811f --- /dev/null +++ b/ai/dist/index.d.ts @@ -0,0 +1,3 @@ +declare const app: any; +export default app; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/ai/dist/index.d.ts.map b/ai/dist/index.d.ts.map new file mode 100644 index 0000000..56fada7 --- /dev/null +++ b/ai/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,GAAG,KAAY,CAAC;AAuFtB,eAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/ai/dist/index.js b/ai/dist/index.js new file mode 100644 index 0000000..842ac62 --- /dev/null +++ b/ai/dist/index.js @@ -0,0 +1,81 @@ +import express from 'express'; +import cors from 'cors'; +import dotenv from 'dotenv'; +dotenv.config(); +const app = express(); +const PORT = process.env.AI_PORT || $, { PORT }; +// Note: This is a mock implementation for development. +// In production, integrate with actual AI services like OpenAI API. +// Middleware +app.use(cors()); +app.use(express.json()); +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'healthy', + service: 'AI Services', + version: '2.0.0', + timestamp: new Date().toISOString() + }); +}); +// AI processing endpoints +app.post('/api/process/text', (req, res) => { + const { text, operation } = req.body; + let result = ''; + switch (operation) { + case 'summarize': + result = text.substring(0, 100) + '...'; + break; + case 'translate': + result = `[Translated] ${text}`; + break; + case 'simplify': + result = text.aslGloss(); + break; + default: + result = text; + } + res.json({ + success: true, + operation, + originalText: text, + result, + confidence: 0.95, + }); +}); +app.post('/api/generate', (req, res) => { + const { prompt, type } = req.body; + res.json({ + success: true, + prompt, + contentType: type, + generated: `Generated ${type} content based on: ${prompt}`, + url: type !== 'text' ? `https://example.com/generated/${type}/${Date.now()}` : null, + }); +}); +app.post('/api/analyze/accessibility', (req, res) => { + const { content, contentType = 'text' } = req.body; + res.json({ + success: true, + contentType, + analysis: { + score: 85, + issues: [ + { type: 'contrast', severity: 'medium', description: 'Low contrast ratio' }, + { type: 'alt-text', severity: 'high', description: 'Missing alt text' }, + ], + recommendations: [ + 'Add sign language interpretation', + 'Improve contrast ratio', + 'Add descriptive alt text', + ], + }, + }); +}); +// Start server +app.listen(PORT, () => { + console.log(`AI Services running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); +}); +export default app; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/ai/dist/index.js.map b/ai/dist/index.js.map new file mode 100644 index 0000000..f8fff06 --- /dev/null +++ b/ai/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/ai/dist/mcp-server.d.ts b/ai/dist/mcp-server.d.ts new file mode 100644 index 0000000..6f78524 --- /dev/null +++ b/ai/dist/mcp-server.d.ts @@ -0,0 +1,3 @@ +#!/usr/bin/env node +export {}; +//# sourceMappingURL=mcp-server.d.ts.map \ No newline at end of file diff --git a/ai/dist/mcp-server.d.ts.map b/ai/dist/mcp-server.d.ts.map new file mode 100644 index 0000000..06de3e9 --- /dev/null +++ b/ai/dist/mcp-server.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/ai/dist/mcp-server.js b/ai/dist/mcp-server.js new file mode 100644 index 0000000..edb5b10 --- /dev/null +++ b/ai/dist/mcp-server.js @@ -0,0 +1,177 @@ +#!/usr/bin/env node +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; +// Tool schemas +const ProcessTextSchema = z.object({ + text: z.string(), + operation: z.enum(['summarize', 'translate', 'simplify']), +}); +const GenerateContentSchema = z.object({ + prompt: z.string(), + type: z.enum(['text', 'image', 'video']), +}); +const AnalyzeAccessibilitySchema = z.object({ + content: z.string(), + contentType: z.string().optional(), +}); +// Define available tools +const tools = [ + { + name: 'process_text', + description: 'Process text using AI (summarize, translate, or simplify)', + inputSchema: { + type: 'object', + properties: { + text: { type: 'string', description: 'Text to process' }, + operation: { + type: 'string', + enum: ['summarize', 'translate', 'simplify'], + description: 'AI operation to perform' + }, + }, + required: ['text', 'operation'], + }, + }, + { + name: 'generate_content', + description: 'Generate accessible content using AI', + inputSchema: { + type: 'object', + properties: { + prompt: { type: 'string', description: 'Generation prompt' }, + type: { + type: 'string', + enum: ['text', 'image', 'video'], + description: 'Content type to generate' + }, + }, + required: ['prompt', 'type'], + }, + }, + { + name: 'analyze_accessibility', + description: 'Analyze content for accessibility issues using AI', + inputSchema: { + type: 'object', + properties: { + content: { type: 'string', description: 'Content to analyze' }, + contentType: { type: 'string', description: 'Type of content' }, + }, + required: ['content'], + }, + }, +]; +// Create server instance +const server = new Server({ + name: 'ai-mcp-server', + version: '2.0.0', +}, { + capabilities: { + tools: {}, + }, +}); +// List available tools +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { tools }; +}); +// Handle tool calls +server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + try { + switch (name) { + case 'process_text': { + const { text, operation } = ProcessTextSchema.parse(args); + let result = ''; + switch (operation) { + case 'summarize': + result = text.substring(0, 100) + '...'; + break; + case 'translate': + result = `[Translated] ${text}`; + break; + case 'simplify': + result = text.toLowerCase(); + break; + } + return { + content: [ + { + type: 'text', + text: JSON.stringify({ + success: true, + operation, + originalText: text, + result, + confidence: 0.95, + }), + }, + ], + }; + } + case 'generate_content': { + const { prompt, type } = GenerateContentSchema.parse(args); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ + success: true, + prompt, + contentType: type, + generated: `Generated ${type} content based on: ${prompt}`, + url: type !== 'text' ? `https://example.com/generated/${type}/${Date.now()}` : null, + }), + }, + ], + }; + } + case 'analyze_accessibility': { + const { content, contentType = 'text' } = AnalyzeAccessibilitySchema.parse(args); + return { + content: [ + { + type: 'text', + text: JSON.stringify({ + success: true, + contentType, + analysis: { + score: 85, + issues: [ + { type: 'contrast', severity: 'medium', description: 'Low contrast ratio' }, + { type: 'alt-text', severity: 'high', description: 'Missing alt text' }, + ], + recommendations: [ + 'Add sign language interpretation', + 'Improve contrast ratio', + 'Add descriptive alt text', + ], + }, + }), + }, + ], + }; + } + default: + throw new Error(`Unknown tool: ${name}`); + } + } + catch (error) { + if (error instanceof z.ZodError) { + throw new Error(`Invalid arguments: ${error.message}`); + } + throw error; + } +}); +// Start server +async function main() { + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error('AI MCP Server running on stdio'); +} +main().catch((error) => { + console.error('Server error:', error); + process.exit(1); +}); +//# sourceMappingURL=mcp-server.js.map \ No newline at end of file diff --git a/ai/dist/mcp-server.js.map b/ai/dist/mcp-server.js.map new file mode 100644 index 0000000..25bc4e3 --- /dev/null +++ b/ai/dist/mcp-server.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/ai/src/index.ts b/ai/src/index.ts index aa9652d..3ee41c1 100644 --- a/ai/src/index.ts +++ b/ai/src/index.ts @@ -16,11 +16,11 @@ app.use(express.json()); // Health check endpoint app.get('/health', (req, res) => { - res.json({ + res.json({ status: 'healthy', service: 'AI Services', version: '2.0.0', - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), }); }); @@ -29,7 +29,9 @@ app.post('/api/process/text', (req, res) => { const { text, operation } = req.body; if (typeof text !== 'string') { - return res.status(400).json({ success: false, error: 'Invalid request', message: '`text` must be a string' }); + return res + .status(400) + .json({ success: false, error: 'Invalid request', message: '`text` must be a string' }); } let result = ''; @@ -55,22 +57,9 @@ app.post('/api/process/text', (req, res) => { confidence: 0.95, }); }); - default: - result = text; - } - - res.json({ - success: true, - operation, - originalText: text, - result, - confidence: 0.95, - }); -}); - app.post('/api/generate', (req, res) => { const { prompt, type } = req.body; - + res.json({ success: true, prompt, @@ -82,7 +71,7 @@ app.post('/api/generate', (req, res) => { app.post('/api/analyze/accessibility', (req, res) => { const { content, contentType = 'text' } = req.body; - + res.json({ success: true, contentType, diff --git a/backend/dist/db/setup.d.ts b/backend/dist/db/setup.d.ts new file mode 100644 index 0000000..de2a803 --- /dev/null +++ b/backend/dist/db/setup.d.ts @@ -0,0 +1,3 @@ +#!/usr/bin/env node +export {}; +//# sourceMappingURL=setup.d.ts.map \ No newline at end of file diff --git a/backend/dist/db/setup.d.ts.map b/backend/dist/db/setup.d.ts.map new file mode 100644 index 0000000..a16fd6f --- /dev/null +++ b/backend/dist/db/setup.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/db/setup.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/backend/dist/db/setup.js b/backend/dist/db/setup.js new file mode 100644 index 0000000..4f919f4 --- /dev/null +++ b/backend/dist/db/setup.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node +import dotenv from 'dotenv'; +dotenv.config(); +async function setupDatabase() { + console.log('Setting up Backend database...'); + // Mock database setup + console.log('Database URL:', process.env.DATABASE_URL || 'Not configured'); + console.log('Creating tables...'); + console.log('- modules'); + console.log('- workflows'); + console.log('- configurations'); + console.log('Backend database setup complete!'); +} +setupDatabase().catch((error) => { + console.error('Database setup failed:', error); + process.exit(1); +}); +//# sourceMappingURL=setup.js.map \ No newline at end of file diff --git a/backend/dist/db/setup.js.map b/backend/dist/db/setup.js.map new file mode 100644 index 0000000..aa2f659 --- /dev/null +++ b/backend/dist/db/setup.js.map @@ -0,0 +1 @@ +{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/db/setup.ts"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,KAAK,UAAU,aAAa;IAC1B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAE9C,sBAAsB;IACtB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gBAAgB,CAAC,CAAC;IAE3E,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAClD,CAAC;AAED,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/backend/dist/index.d.ts b/backend/dist/index.d.ts new file mode 100644 index 0000000..0a3811f --- /dev/null +++ b/backend/dist/index.d.ts @@ -0,0 +1,3 @@ +declare const app: any; +export default app; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/backend/dist/index.d.ts.map b/backend/dist/index.d.ts.map new file mode 100644 index 0000000..06c5fcc --- /dev/null +++ b/backend/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,GAAG,KAAY,CAAC;AA6CtB,eAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/backend/dist/index.js b/backend/dist/index.js new file mode 100644 index 0000000..46204cb --- /dev/null +++ b/backend/dist/index.js @@ -0,0 +1,48 @@ +import express from 'express'; +import cors from 'cors'; +import helmet from 'helmet'; +import dotenv from 'dotenv'; +import webhookRoutes from './routes/webhook.routes'; +import incomingWebhookRoutes from './routes/incoming-webhook.routes'; +dotenv.config(); +const app = express(); +const PORT = process.env.BACKEND_PORT || 3000; +// Middleware +app.use(helmet()); +app.use(cors()); +app.use(express.json()); +// Health check endpoint +app.get('/health', (req, res) => { + res.json({ + status: 'healthy', + service: 'Backend API', + version: '2.0.0', + timestamp: new Date().toISOString() + }); +}); +// API endpoints +app.get('/api/status', (req, res) => { + res.json({ + success: true, + services: { + backend: 'running', + deafauth: 'running', + pinksync: 'running', + fibonrose: 'running', + accessibility: 'running', + ai: 'running', + } + }); +}); +// Webhook routes +app.use('/api/webhooks', webhookRoutes); +app.use('/api/incoming-webhooks', incomingWebhookRoutes); +// Start server +app.listen(PORT, () => { + console.log(`Backend API running on port ${PORT}`); + console.log(`Health check: http://localhost:${PORT}/health`); + console.log(`Webhook API: http://localhost:${PORT}/api/webhooks`); + console.log(`Incoming Webhooks: http://localhost:${PORT}/api/incoming-webhooks`); +}); +export default app; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/backend/dist/index.js.map b/backend/dist/index.js.map new file mode 100644 index 0000000..46a6051 --- /dev/null +++ b/backend/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,aAAa,MAAM,yBAAyB,CAAC;AACpD,OAAO,qBAAqB,MAAM,kCAAkC,CAAC;AAErE,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;AAE9C,aAAa;AACb,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAClB,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAChB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,wBAAwB;AACxB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC9B,GAAG,CAAC,IAAI,CAAC;QACP,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,gBAAgB;AAChB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAClC,GAAG,CAAC,IAAI,CAAC;QACP,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE;YACR,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,SAAS;YACnB,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,SAAS;YACxB,EAAE,EAAE,SAAS;SACd;KACF,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iBAAiB;AACjB,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;AACxC,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;AAEzD,eAAe;AACf,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,SAAS,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,eAAe,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,wBAAwB,CAAC,CAAC;AACnF,CAAC,CAAC,CAAC;AAEH,eAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/incoming-webhook.routes.d.ts b/backend/dist/routes/incoming-webhook.routes.d.ts new file mode 100644 index 0000000..d69ba43 --- /dev/null +++ b/backend/dist/routes/incoming-webhook.routes.d.ts @@ -0,0 +1,3 @@ +declare const router: any; +export default router; +//# sourceMappingURL=incoming-webhook.routes.d.ts.map \ No newline at end of file diff --git a/backend/dist/routes/incoming-webhook.routes.d.ts.map b/backend/dist/routes/incoming-webhook.routes.d.ts.map new file mode 100644 index 0000000..737124c --- /dev/null +++ b/backend/dist/routes/incoming-webhook.routes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"incoming-webhook.routes.d.ts","sourceRoot":"","sources":["../../src/routes/incoming-webhook.routes.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,KAAW,CAAC;AAsHxB,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/incoming-webhook.routes.js b/backend/dist/routes/incoming-webhook.routes.js new file mode 100644 index 0000000..75bed83 --- /dev/null +++ b/backend/dist/routes/incoming-webhook.routes.js @@ -0,0 +1,110 @@ +import { Router } from 'express'; +const router = Router(); +/** + * POST /api/incoming-webhooks/:service + * Receive webhook events from external services + * This endpoint accepts webhooks from services like Xano, Stripe, etc. + */ +router.post('/:service', async (req, res) => { + try { + const service = req.params.service; + const signature = req.headers['x-webhook-signature']; + const event = req.headers['x-webhook-event']; + // Log incoming webhook + console.log(`[Incoming Webhook] Service: ${service}, Event: ${event}`); + console.log(`[Incoming Webhook] Payload:`, req.body); + // Create webhook event + const webhookEvent = { + id: `evt_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`, + event: event || 'unknown', + timestamp: new Date().toISOString(), + data: req.body, + signature + }; + // Process based on service type + switch (service) { + case 'xano': + await handleXanoWebhook(webhookEvent); + break; + case 'stripe': + await handleStripeWebhook(webhookEvent); + break; + case 'custom': + await handleCustomWebhook(webhookEvent); + break; + default: + console.log(`[Incoming Webhook] Unknown service: ${service}`); + } + // Respond with success + res.status(200).json({ + success: true, + message: 'Webhook received successfully', + eventId: webhookEvent.id + }); + } + catch (error) { + console.error('[Incoming Webhook] Error:', error); + res.status(500).json({ + success: false, + error: 'Failed to process webhook', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * Handle Xano webhooks + */ +async function handleXanoWebhook(event) { + console.log('[Xano Webhook] Processing:', event.event); + // Add Xano-specific processing logic here + switch (event.event) { + case 'record.created': + console.log('[Xano Webhook] Record created:', event.data); + break; + case 'record.updated': + console.log('[Xano Webhook] Record updated:', event.data); + break; + case 'record.deleted': + console.log('[Xano Webhook] Record deleted:', event.data); + break; + default: + console.log('[Xano Webhook] Unhandled event:', event.event); + } +} +/** + * Handle Stripe webhooks + */ +async function handleStripeWebhook(event) { + console.log('[Stripe Webhook] Processing:', event.event); + // Add Stripe-specific processing logic here + switch (event.event) { + case 'payment_intent.succeeded': + console.log('[Stripe Webhook] Payment succeeded:', event.data); + break; + case 'payment_intent.failed': + console.log('[Stripe Webhook] Payment failed:', event.data); + break; + default: + console.log('[Stripe Webhook] Unhandled event:', event.event); + } +} +/** + * Handle custom webhooks + */ +async function handleCustomWebhook(event) { + console.log('[Custom Webhook] Processing:', event.event); + console.log('[Custom Webhook] Data:', event.data); +} +/** + * GET /api/incoming-webhooks/health + * Health check for incoming webhook endpoint + */ +router.get('/health', (req, res) => { + res.json({ + success: true, + message: 'Incoming webhook endpoint is healthy', + timestamp: new Date().toISOString() + }); +}); +export default router; +//# sourceMappingURL=incoming-webhook.routes.js.map \ No newline at end of file diff --git a/backend/dist/routes/incoming-webhook.routes.js.map b/backend/dist/routes/incoming-webhook.routes.js.map new file mode 100644 index 0000000..51fa9e1 --- /dev/null +++ b/backend/dist/routes/incoming-webhook.routes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"incoming-webhook.routes.js","sourceRoot":"","sources":["../../src/routes/incoming-webhook.routes.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/backend/dist/routes/webhook.routes.d.ts b/backend/dist/routes/webhook.routes.d.ts new file mode 100644 index 0000000..410b53d --- /dev/null +++ b/backend/dist/routes/webhook.routes.d.ts @@ -0,0 +1,3 @@ +declare const router: any; +export default router; +//# sourceMappingURL=webhook.routes.d.ts.map \ No newline at end of file diff --git a/backend/dist/routes/webhook.routes.d.ts.map b/backend/dist/routes/webhook.routes.d.ts.map new file mode 100644 index 0000000..15160da --- /dev/null +++ b/backend/dist/routes/webhook.routes.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.routes.d.ts","sourceRoot":"","sources":["../../src/routes/webhook.routes.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,KAAW,CAAC;AAoPxB,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/backend/dist/routes/webhook.routes.js b/backend/dist/routes/webhook.routes.js new file mode 100644 index 0000000..81c6858 --- /dev/null +++ b/backend/dist/routes/webhook.routes.js @@ -0,0 +1,235 @@ +import { Router } from 'express'; +import { webhookService } from '../webhooks/webhook.service'; +import { WebhookEventType } from '../types/webhook.types'; +const router = Router(); +/** + * GET /api/webhooks/events/types + * Get list of available webhook event types + * IMPORTANT: This must be defined before /:id routes + */ +router.get('/events/types', (req, res) => { + try { + const eventTypes = Object.values(WebhookEventType); + res.json({ + success: true, + count: eventTypes.length, + events: eventTypes + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to retrieve event types', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * POST /api/webhooks/trigger + * Manually trigger a webhook event (for testing) + * IMPORTANT: This must be defined before /:id routes + */ +router.post('/trigger', async (req, res) => { + try { + const { event, data } = req.body; + if (!event || !data) { + return res.status(400).json({ + success: false, + error: 'Invalid request', + message: 'Event and data are required' + }); + } + await webhookService.triggerEvent(event, data); + res.json({ + success: true, + message: 'Webhook event triggered successfully' + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to trigger webhook event', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * GET /api/webhooks + * List all registered webhooks + */ +router.get('/', (req, res) => { + try { + const webhooks = webhookService.getAllWebhooks(); + res.json({ + success: true, + count: webhooks.length, + webhooks: webhooks.map(webhook => ({ + ...webhook, + secret: '***' // Hide secret in response + })) + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to retrieve webhooks', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * GET /api/webhooks/:id/deliveries + * Get delivery history for a webhook + * IMPORTANT: This must be defined before the generic /:id route + */ +router.get('/:id/deliveries', (req, res) => { + try { + const deliveries = webhookService.getDeliveries(req.params.id); + res.json({ + success: true, + count: deliveries.length, + deliveries + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to retrieve deliveries', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * GET /api/webhooks/:id + * Get a specific webhook by ID + */ +router.get('/:id', (req, res) => { + try { + const webhook = webhookService.getWebhook(req.params.id); + if (!webhook) { + return res.status(404).json({ + success: false, + error: 'Webhook not found' + }); + } + res.json({ + success: true, + webhook: { + ...webhook, + secret: '***' // Hide secret in response + } + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to retrieve webhook', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * POST /api/webhooks + * Register a new webhook + */ +router.post('/', (req, res) => { + try { + const { name, url, events, secret } = req.body; + // Validation + if (!name || !url || !events || !Array.isArray(events)) { + return res.status(400).json({ + success: false, + error: 'Invalid request', + message: 'Name, URL, and events array are required' + }); + } + if (!url.startsWith('http://') && !url.startsWith('https://')) { + return res.status(400).json({ + success: false, + error: 'Invalid URL', + message: 'URL must start with http:// or https://' + }); + } + const webhook = webhookService.registerWebhook(name, url, events, secret); + res.status(201).json({ + success: true, + message: 'Webhook registered successfully', + webhook + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to register webhook', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * PUT /api/webhooks/:id + * Update an existing webhook + */ +router.put('/:id', (req, res) => { + try { + const { name, url, events, active } = req.body; + const updates = {}; + if (name !== undefined) + updates.name = name; + if (url !== undefined) + updates.url = url; + if (events !== undefined) + updates.events = events; + if (active !== undefined) + updates.active = active; + const webhook = webhookService.updateWebhook(req.params.id, updates); + if (!webhook) { + return res.status(404).json({ + success: false, + error: 'Webhook not found' + }); + } + res.json({ + success: true, + message: 'Webhook updated successfully', + webhook: { + ...webhook, + secret: '***' // Hide secret in response + } + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to update webhook', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +/** + * DELETE /api/webhooks/:id + * Delete a webhook + */ +router.delete('/:id', (req, res) => { + try { + const deleted = webhookService.deleteWebhook(req.params.id); + if (!deleted) { + return res.status(404).json({ + success: false, + error: 'Webhook not found' + }); + } + res.json({ + success: true, + message: 'Webhook deleted successfully' + }); + } + catch (error) { + res.status(500).json({ + success: false, + error: 'Failed to delete webhook', + message: error instanceof Error ? error.message : 'Unknown error' + }); + } +}); +export default router; +//# sourceMappingURL=webhook.routes.js.map \ No newline at end of file diff --git a/backend/dist/routes/webhook.routes.js.map b/backend/dist/routes/webhook.routes.js.map new file mode 100644 index 0000000..158bd7b --- /dev/null +++ b/backend/dist/routes/webhook.routes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.routes.js","sourceRoot":"","sources":["../../src/routes/webhook.routes.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/backend/dist/types/webhook.types.d.ts b/backend/dist/types/webhook.types.d.ts new file mode 100644 index 0000000..b63ab55 --- /dev/null +++ b/backend/dist/types/webhook.types.d.ts @@ -0,0 +1,61 @@ +/** + * Webhook Types for DEAF-FIRST Platform + * These types define the structure for webhook events and configurations + */ +export interface WebhookEvent { + id: string; + event: string; + timestamp: string; + data: any; + signature?: string; +} +export interface WebhookConfig { + id: string; + name: string; + url: string; + events: string[]; + secret: string; + active: boolean; + createdAt: string; + updatedAt: string; +} +export interface WebhookDelivery { + id: string; + webhookId: string; + event: string; + payload: any; + response?: { + status: number; + body: any; + }; + attempts: number; + status: 'pending' | 'success' | 'failed'; + timestamp: string; +} +export interface WebhookRequest { + name: string; + url: string; + events: string[]; + secret?: string; +} +export interface WebhookResponse { + success: boolean; + webhook?: WebhookConfig; + message?: string; + error?: string; +} +export declare enum WebhookEventType { + USER_CREATED = "user.created", + USER_UPDATED = "user.updated", + USER_DELETED = "user.deleted", + AUTH_LOGIN = "auth.login", + AUTH_LOGOUT = "auth.logout", + DOCUMENT_UPLOADED = "document.uploaded", + DOCUMENT_PROCESSED = "document.processed", + ACCESSIBILITY_REQUEST = "accessibility.request", + SYNC_STARTED = "sync.started", + SYNC_COMPLETED = "sync.completed", + AI_PROCESS_STARTED = "ai.process.started", + AI_PROCESS_COMPLETED = "ai.process.completed" +} +//# sourceMappingURL=webhook.types.d.ts.map \ No newline at end of file diff --git a/backend/dist/types/webhook.types.d.ts.map b/backend/dist/types/webhook.types.d.ts.map new file mode 100644 index 0000000..4b81538 --- /dev/null +++ b/backend/dist/types/webhook.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.types.d.ts","sourceRoot":"","sources":["../../src/types/webhook.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,GAAG,CAAC;IACV,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,GAAG,CAAC;KACX,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,oBAAY,gBAAgB;IAC1B,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,UAAU,eAAe;IACzB,WAAW,gBAAgB;IAC3B,iBAAiB,sBAAsB;IACvC,kBAAkB,uBAAuB;IACzC,qBAAqB,0BAA0B;IAC/C,YAAY,iBAAiB;IAC7B,cAAc,mBAAmB;IACjC,kBAAkB,uBAAuB;IACzC,oBAAoB,yBAAyB;CAC9C"} \ No newline at end of file diff --git a/backend/dist/types/webhook.types.js b/backend/dist/types/webhook.types.js new file mode 100644 index 0000000..1ba7ce3 --- /dev/null +++ b/backend/dist/types/webhook.types.js @@ -0,0 +1,21 @@ +/** + * Webhook Types for DEAF-FIRST Platform + * These types define the structure for webhook events and configurations + */ +// Available webhook event types +export var WebhookEventType; +(function (WebhookEventType) { + WebhookEventType["USER_CREATED"] = "user.created"; + WebhookEventType["USER_UPDATED"] = "user.updated"; + WebhookEventType["USER_DELETED"] = "user.deleted"; + WebhookEventType["AUTH_LOGIN"] = "auth.login"; + WebhookEventType["AUTH_LOGOUT"] = "auth.logout"; + WebhookEventType["DOCUMENT_UPLOADED"] = "document.uploaded"; + WebhookEventType["DOCUMENT_PROCESSED"] = "document.processed"; + WebhookEventType["ACCESSIBILITY_REQUEST"] = "accessibility.request"; + WebhookEventType["SYNC_STARTED"] = "sync.started"; + WebhookEventType["SYNC_COMPLETED"] = "sync.completed"; + WebhookEventType["AI_PROCESS_STARTED"] = "ai.process.started"; + WebhookEventType["AI_PROCESS_COMPLETED"] = "ai.process.completed"; +})(WebhookEventType || (WebhookEventType = {})); +//# sourceMappingURL=webhook.types.js.map \ No newline at end of file diff --git a/backend/dist/types/webhook.types.js.map b/backend/dist/types/webhook.types.js.map new file mode 100644 index 0000000..3a5c3e3 --- /dev/null +++ b/backend/dist/types/webhook.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.types.js","sourceRoot":"","sources":["../../src/types/webhook.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiDH,gCAAgC;AAChC,MAAM,CAAN,IAAY,gBAaX;AAbD,WAAY,gBAAgB;IAC1B,iDAA6B,CAAA;IAC7B,iDAA6B,CAAA;IAC7B,iDAA6B,CAAA;IAC7B,6CAAyB,CAAA;IACzB,+CAA2B,CAAA;IAC3B,2DAAuC,CAAA;IACvC,6DAAyC,CAAA;IACzC,mEAA+C,CAAA;IAC/C,iDAA6B,CAAA;IAC7B,qDAAiC,CAAA;IACjC,6DAAyC,CAAA;IACzC,iEAA6C,CAAA;AAC/C,CAAC,EAbW,gBAAgB,KAAhB,gBAAgB,QAa3B"} \ No newline at end of file diff --git a/backend/dist/webhooks/webhook.service.d.ts b/backend/dist/webhooks/webhook.service.d.ts new file mode 100644 index 0000000..db6183f --- /dev/null +++ b/backend/dist/webhooks/webhook.service.d.ts @@ -0,0 +1,59 @@ +import { WebhookConfig, WebhookDelivery } from '../types/webhook.types'; +/** + * In-memory storage for webhooks (in production, use a database) + */ +declare class WebhookService { + private webhooks; + private deliveries; + /** + * Register a new webhook + */ + registerWebhook(name: string, url: string, events: string[], secret?: string): WebhookConfig; + /** + * Get all registered webhooks + */ + getAllWebhooks(): WebhookConfig[]; + /** + * Get a specific webhook by ID + */ + getWebhook(id: string): WebhookConfig | undefined; + /** + * Update a webhook + */ + updateWebhook(id: string, updates: Partial): WebhookConfig | null; + /** + * Delete a webhook + */ + deleteWebhook(id: string): boolean; + /** + * Trigger webhook event + */ + triggerEvent(eventType: string, data: any): Promise; + /** + * Deliver webhook to endpoint + */ + private deliverWebhook; + /** + * Get delivery history for a webhook + */ + getDeliveries(webhookId?: string): WebhookDelivery[]; + /** + * Verify webhook signature + */ + verifySignature(payload: string, signature: string, secret: string): boolean; + /** + * Generate HMAC signature + */ + private generateSignature; + /** + * Generate unique ID + */ + private generateId; + /** + * Generate webhook secret + */ + private generateSecret; +} +export declare const webhookService: WebhookService; +export {}; +//# sourceMappingURL=webhook.service.d.ts.map \ No newline at end of file diff --git a/backend/dist/webhooks/webhook.service.d.ts.map b/backend/dist/webhooks/webhook.service.d.ts.map new file mode 100644 index 0000000..a7bfaf0 --- /dev/null +++ b/backend/dist/webhooks/webhook.service.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.service.d.ts","sourceRoot":"","sources":["../../src/webhooks/webhook.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEtF;;GAEG;AACH,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,UAAU,CAA2C;IAE7D;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa;IAmB5F;;OAEG;IACH,cAAc,IAAI,aAAa,EAAE;IAIjC;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjD;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,GAAG,IAAI;IAehF;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIlC;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/D;;OAEG;YACW,cAAc;IAsD5B;;OAEG;IACH,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,EAAE;IAQpD;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAiB5E;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,cAAc;CAGvB;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"} \ No newline at end of file diff --git a/backend/dist/webhooks/webhook.service.js b/backend/dist/webhooks/webhook.service.js new file mode 100644 index 0000000..0b66961 --- /dev/null +++ b/backend/dist/webhooks/webhook.service.js @@ -0,0 +1,161 @@ +import crypto from 'crypto'; +/** + * In-memory storage for webhooks (in production, use a database) + */ +class WebhookService { + webhooks = new Map(); + deliveries = new Map(); + /** + * Register a new webhook + */ + registerWebhook(name, url, events, secret) { + const id = this.generateId(); + const generatedSecret = secret || this.generateSecret(); + const webhook = { + id, + name, + url, + events, + secret: generatedSecret, + active: true, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; + this.webhooks.set(id, webhook); + return webhook; + } + /** + * Get all registered webhooks + */ + getAllWebhooks() { + return Array.from(this.webhooks.values()); + } + /** + * Get a specific webhook by ID + */ + getWebhook(id) { + return this.webhooks.get(id); + } + /** + * Update a webhook + */ + updateWebhook(id, updates) { + const webhook = this.webhooks.get(id); + if (!webhook) + return null; + const updated = { + ...webhook, + ...updates, + id: webhook.id, // Prevent ID change + updatedAt: new Date().toISOString(), + }; + this.webhooks.set(id, updated); + return updated; + } + /** + * Delete a webhook + */ + deleteWebhook(id) { + return this.webhooks.delete(id); + } + /** + * Trigger webhook event + */ + async triggerEvent(eventType, data) { + const webhooks = Array.from(this.webhooks.values()).filter((webhook) => webhook.active && webhook.events.includes(eventType)); + const deliveryPromises = webhooks.map((webhook) => this.deliverWebhook(webhook, eventType, data)); + await Promise.allSettled(deliveryPromises); + } + /** + * Deliver webhook to endpoint + */ + async deliverWebhook(webhook, eventType, data) { + const deliveryId = this.generateId(); + const payload = { + event: eventType, + timestamp: new Date().toISOString(), + data, + }; + const signature = this.generateSignature(JSON.stringify(payload), webhook.secret); + const delivery = { + id: deliveryId, + webhookId: webhook.id, + event: eventType, + payload, + attempts: 1, + status: 'pending', + timestamp: new Date().toISOString(), + }; + this.deliveries.set(deliveryId, delivery); + try { + const response = await fetch(webhook.url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Webhook-Signature': signature, + 'X-Webhook-Event': eventType, + 'X-Webhook-Delivery': deliveryId, + }, + body: JSON.stringify(payload), + }); + delivery.response = { + status: response.status, + body: await response.text(), + }; + delivery.status = response.ok ? 'success' : 'failed'; + } + catch (error) { + delivery.status = 'failed'; + delivery.response = { + status: 0, + body: error instanceof Error ? error.message : 'Unknown error', + }; + } + this.deliveries.set(deliveryId, delivery); + } + /** + * Get delivery history for a webhook + */ + getDeliveries(webhookId) { + const deliveries = Array.from(this.deliveries.values()); + if (webhookId) { + return deliveries.filter((d) => d.webhookId === webhookId); + } + return deliveries; + } + /** + * Verify webhook signature + */ + verifySignature(payload, signature, secret) { + const expectedSignature = this.generateSignature(payload, secret); + // Normalize signatures to ensure they're in the same format (hex) + const normalizedSignature = signature.toLowerCase().trim(); + const normalizedExpected = expectedSignature.toLowerCase().trim(); + // Ensure both signatures have the same length before comparison + if (normalizedSignature.length !== normalizedExpected.length) { + return false; + } + return crypto.timingSafeEqual(Buffer.from(normalizedSignature, 'hex'), Buffer.from(normalizedExpected, 'hex')); + } + /** + * Generate HMAC signature + */ + generateSignature(payload, secret) { + return crypto.createHmac('sha256', secret).update(payload).digest('hex'); + } + /** + * Generate unique ID + */ + generateId() { + return `wh_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`; + } + /** + * Generate webhook secret + */ + generateSecret() { + return crypto.randomBytes(32).toString('hex'); + } +} +// Export singleton instance +export const webhookService = new WebhookService(); +//# sourceMappingURL=webhook.service.js.map \ No newline at end of file diff --git a/backend/dist/webhooks/webhook.service.js.map b/backend/dist/webhooks/webhook.service.js.map new file mode 100644 index 0000000..6ed8d05 --- /dev/null +++ b/backend/dist/webhooks/webhook.service.js.map @@ -0,0 +1 @@ +{"version":3,"file":"webhook.service.js","sourceRoot":"","sources":["../../src/webhooks/webhook.service.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B;;GAEG;AACH,MAAM,cAAc;IACV,QAAQ,GAA+B,IAAI,GAAG,EAAE,CAAC;IACjD,UAAU,GAAiC,IAAI,GAAG,EAAE,CAAC;IAE7D;;OAEG;IACH,eAAe,CAAC,IAAY,EAAE,GAAW,EAAE,MAAgB,EAAE,MAAe;QAC1E,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,MAAM,eAAe,GAAG,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QAExD,MAAM,OAAO,GAAkB;YAC7B,EAAE;YACF,IAAI;YACJ,GAAG;YACH,MAAM;YACN,MAAM,EAAE,eAAe;YACvB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,EAAU,EAAE,OAA+B;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE1B,MAAM,OAAO,GAAG;YACd,GAAG,OAAO;YACV,GAAG,OAAO;YACV,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,oBAAoB;YACpC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,SAAiB,EAAE,IAAS;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CACxD,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAClE,CAAC;QAEF,MAAM,gBAAgB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAChD,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAC9C,CAAC;QAEF,MAAM,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,cAAc,CAC1B,OAAsB,EACtB,SAAiB,EACjB,IAAS;QAET,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI;SACL,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAElF,MAAM,QAAQ,GAAoB;YAChC,EAAE,EAAE,UAAU;YACd,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,KAAK,EAAE,SAAS;YAChB,OAAO;YACP,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAE1C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;gBACxC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,qBAAqB,EAAE,SAAS;oBAChC,iBAAiB,EAAE,SAAS;oBAC5B,oBAAoB,EAAE,UAAU;iBACjC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9B,CAAC,CAAC;YAEH,QAAQ,CAAC,QAAQ,GAAG;gBAClB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,IAAI,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE;aAC5B,CAAC;YACF,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC;YAC3B,QAAQ,CAAC,QAAQ,GAAG;gBAClB,MAAM,EAAE,CAAC;gBACT,IAAI,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;aAC/D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,SAAkB;QAC9B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,OAAe,EAAE,SAAiB,EAAE,MAAc;QAChE,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClE,kEAAkE;QAClE,MAAM,mBAAmB,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAElE,gEAAgE;QAChE,IAAI,mBAAmB,CAAC,MAAM,KAAK,kBAAkB,CAAC,MAAM,EAAE,CAAC;YAC7D,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,MAAM,CAAC,eAAe,CAC3B,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,EACvC,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CACvC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,OAAe,EAAE,MAAc;QACvD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3E,CAAC;IAED;;OAEG;IACK,UAAU;QAChB,OAAO,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACvE,CAAC;IAED;;OAEG;IACK,cAAc;QACpB,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;CACF;AAED,4BAA4B;AAC5B,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index ea5e42b..ff40b41 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,42 +1,42 @@ -{ - "name": "@deaf-first/backend", - "version": "2.0.0", - "private": true, - "description": "Deaf-first backend API server", - "type": "module", - "scripts": { - "dev": "tsx watch src/index.ts", - "build": "tsc", - "start": "node dist/index.js", - "db:setup": "tsx src/db/setup.ts", - "db:migrate": "tsx src/db/migrate.ts", - "db:seed": "tsx src/db/seed.ts", - "test": "vitest", - "lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0", - "type-check": "tsc --noEmit", - "clean": "rm -rf node_modules dist" - }, - "dependencies": { - "express": "^4.21.1", - "cors": "^2.8.5", - "helmet": "^8.0.0", - "dotenv": "^16.4.5", - "pg": "^8.13.1", - "jsonwebtoken": "^9.0.2", - "bcrypt": "^6.0.0" - }, - "devDependencies": { - "@types/express": "^5.0.0", - "@types/cors": "^2.8.17", - "@types/node": "^22.10.2", - "@types/pg": "^8.11.10", - "@types/jsonwebtoken": "^9.0.7", - "@types/bcrypt": "^5.0.2", - "@typescript-eslint/eslint-plugin": "^8.15.0", - "@typescript-eslint/parser": "^8.15.0", - "eslint": "^9.15.0", - "tsx": "^4.19.2", - "typescript": "^5.7.2", - "vitest": "^4.1.6" - } -} +{ + "name": "@deaf-first/backend", + "version": "2.0.0", + "private": true, + "description": "Deaf-first backend API server", + "type": "module", + "scripts": { + "dev": "tsx watch src/index.ts", + "build": "tsc", + "start": "node dist/index.js", + "db:setup": "tsx src/db/setup.ts", + "db:migrate": "tsx src/db/migrate.ts", + "db:seed": "tsx src/db/seed.ts", + "test": "vitest", + "lint": "eslint . --ext ts --report-unused-disable-directives --max-warnings 0", + "type-check": "tsc --noEmit", + "clean": "rm -rf node_modules dist" + }, + "dependencies": { + "express": "^4.21.1", + "cors": "^2.8.5", + "helmet": "^8.0.0", + "dotenv": "^16.4.5", + "pg": "^8.13.1", + "jsonwebtoken": "^9.0.2", + "bcrypt": "^6.0.0" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/cors": "^2.8.17", + "@types/node": "^22.10.2", + "@types/pg": "^8.11.10", + "@types/jsonwebtoken": "^9.0.7", + "@types/bcrypt": "^5.0.2", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "eslint": "^9.15.0", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "vitest": "^4.1.6" + } +} diff --git a/backend/src/index.ts b/backend/src/index.ts index 5e08b2d..860235e 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -17,11 +17,11 @@ app.use(express.json()); // Health check endpoint app.get('/health', (req, res) => { - res.json({ + res.json({ status: 'healthy', service: 'Backend API', version: '2.0.0', - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), }); }); @@ -36,7 +36,7 @@ app.get('/api/status', (req, res) => { fibonrose: 'running', accessibility: 'running', ai: 'running', - } + }, }); }); diff --git a/backend/src/routes/incoming-webhook.routes.ts b/backend/src/routes/incoming-webhook.routes.ts index f160509..d49bd70 100644 --- a/backend/src/routes/incoming-webhook.routes.ts +++ b/backend/src/routes/incoming-webhook.routes.ts @@ -24,7 +24,7 @@ router.post('/:service', async (req: Request, res: Response) => { event: event || 'unknown', timestamp: new Date().toISOString(), data: req.body, - signature + signature, }; // Process based on service type @@ -46,14 +46,14 @@ router.post('/:service', async (req: Request, res: Response) => { res.status(200).json({ success: true, message: 'Webhook received successfully', - eventId: webhookEvent.id + eventId: webhookEvent.id, }); } catch (error) { console.error('[Incoming Webhook] Error:', error); res.status(500).json({ success: false, error: 'Failed to process webhook', - message: error instanceof Error ? error.message : 'Unknown error' + message: error instanceof Error ? error.message : 'Unknown error', }); } }); @@ -63,7 +63,7 @@ router.post('/:service', async (req: Request, res: Response) => { */ async function handleXanoWebhook(event: WebhookEvent): Promise { console.log('[Xano Webhook] Processing:', event.event); - + // Add Xano-specific processing logic here switch (event.event) { case 'record.created': @@ -85,7 +85,7 @@ async function handleXanoWebhook(event: WebhookEvent): Promise { */ async function handleStripeWebhook(event: WebhookEvent): Promise { console.log('[Stripe Webhook] Processing:', event.event); - + // Add Stripe-specific processing logic here switch (event.event) { case 'payment_intent.succeeded': @@ -115,7 +115,7 @@ router.get('/health', (req: Request, res: Response) => { res.json({ success: true, message: 'Incoming webhook endpoint is healthy', - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), }); }); diff --git a/backend/src/webhooks/webhook.service.ts b/backend/src/webhooks/webhook.service.ts index 80f3974..924cf3c 100644 --- a/backend/src/webhooks/webhook.service.ts +++ b/backend/src/webhooks/webhook.service.ts @@ -14,7 +14,7 @@ class WebhookService { registerWebhook(name: string, url: string, events: string[], secret?: string): WebhookConfig { const id = this.generateId(); const generatedSecret = secret || this.generateSecret(); - + const webhook: WebhookConfig = { id, name, @@ -165,7 +165,7 @@ class WebhookService { if (!hexPattern.test(normalizedSignature) || !hexPattern.test(normalizedExpected)) { return false; } - + // Ensure both signatures have the same length before comparison if (normalizedSignature.length !== normalizedExpected.length) { return false; diff --git a/frontend/package.json b/frontend/package.json index 0cda381..f10e916 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,37 +1,37 @@ -{ - "name": "@deaf-first/frontend", - "version": "2.0.0", - "private": true, - "description": "Deaf-first accessible frontend application", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "test": "vitest", - "test:e2e": "playwright test", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "type-check": "tsc --noEmit", - "clean": "rm -rf node_modules dist" - }, - "dependencies": { - "react": "^19.2.6", - "react-dom": "^19.2.6", - "@tanstack/react-query": "^5.59.20", - "axios": "^1.7.8" - }, - "devDependencies": { - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.15.0", - "@typescript-eslint/parser": "^8.15.0", - "@vitejs/plugin-react": "^6.0.1", - "eslint": "^10.3.0", - "eslint-plugin-react-hooks": "^7.1.1", - "eslint-plugin-react-refresh": "^0.5.2", - "typescript": "^7.0.2", - "vite": "^8.0.12", - "vitest": "^4.0.15", - "@playwright/test": "^1.48.2" - } -} +{ + "name": "@deaf-first/frontend", + "version": "2.0.0", + "private": true, + "description": "Deaf-first accessible frontend application", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "test": "vitest", + "test:e2e": "playwright test", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "type-check": "tsc --noEmit", + "clean": "rm -rf node_modules dist" + }, + "dependencies": { + "react": "^19.2.6", + "react-dom": "^19.2.6", + "@tanstack/react-query": "^5.59.20", + "axios": "^1.7.8" + }, + "devDependencies": { + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "typescript": "^7.0.2", + "vite": "^8.0.12", + "vitest": "^4.0.15", + "@playwright/test": "^1.48.2" + } +} diff --git a/jest.config.js b/jest.config.js index d9067b5..80555cf 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,22 +1,16 @@ module.exports = { testEnvironment: 'node', coverageDirectory: 'coverage', - collectCoverageFrom: [ - 'tests/**/*.js', - '!tests/**/*.test.js', - '!tests/**/node_modules/**' - ], - testMatch: [ - '**/tests/**/*.test.js' - ], + collectCoverageFrom: ['tests/**/*.js', '!tests/**/*.test.js', '!tests/**/node_modules/**'], + testMatch: ['**/tests/**/*.test.js'], coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, - statements: 80 - } + statements: 80, + }, }, verbose: true, - testTimeout: 10000 + testTimeout: 10000, }; diff --git a/package-lock.json b/package-lock.json index 7605fb0..83e74b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "@modelcontextprotocol/sdk": "^1.25.2", "cors": "^2.8.5", "dotenv": "^16.4.5", - "express": "^4.21.1", + "express": "^5.2.1", "openai": "^4.73.1", "zod": "^3.23.8" }, @@ -58,94 +58,79 @@ "vitest": "^4.1.9" } }, - "ai/node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", - "dev": true, + "ai/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, - "bin": { - "eslint": "bin/eslint.js" + "engines": { + "node": ">= 0.6" + } + }, + "ai/node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "backend": { - "name": "@deaf-first/backend", + "ai/node_modules/body-parser/node_modules/content-type": { "version": "2.0.0", - "dependencies": { - "bcrypt": "^6.0.0", - "cors": "^2.8.5", - "dotenv": "^16.4.5", - "express": "^4.21.1", - "helmet": "^8.0.0", - "jsonwebtoken": "^9.0.2", - "pg": "^8.13.1" + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" }, - "devDependencies": { - "@types/bcrypt": "^5.0.2", - "@types/cors": "^2.8.17", - "@types/express": "^5.0.0", - "@types/jsonwebtoken": "^9.0.7", - "@types/node": "^22.10.2", - "@types/pg": "^8.11.10", - "@typescript-eslint/eslint-plugin": "^8.15.0", - "@typescript-eslint/parser": "^8.15.0", - "eslint": "^9.15.0", - "tsx": "^4.19.2", - "typescript": "^5.7.2", - "vitest": "^4.1.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "backend/node_modules/eslint": { + "ai/node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "ai/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "ai/node_modules/eslint": { "version": "9.39.4", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", @@ -205,438 +190,770 @@ } } }, - "frontend": { - "name": "@deaf-first/frontend", - "version": "2.0.0", + "ai/node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", "dependencies": { - "@tanstack/react-query": "^5.59.20", - "axios": "^1.7.8", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@playwright/test": "^1.48.2", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.15.0", - "@typescript-eslint/parser": "^8.15.0", - "@vitejs/plugin-react": "^6.0.1", - "eslint": "^10.3.0", - "eslint-plugin-react-hooks": "^7.1.1", - "eslint-plugin-react-refresh": "^0.5.2", - "typescript": "^6.0.3", - "vite": "^8.0.12", - "vitest": "^4.0.15" - } - }, - "frontend/node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">=14.17" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", - "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", - "dev": true, + "ai/node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 16" + "node": ">= 18.0.0" }, "funding": { - "url": "https://github.com/sponsors/philsturgeon" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "dev": true, + "ai/node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.8" } }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.1.tgz", - "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", - "dev": true, + "ai/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "11.7.2", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.2" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "engines": { + "node": ">=0.10.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, + "ai/node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", "license": "MIT", - "peerDependencies": { - "ajv": "^8.5.0" + "engines": { + "node": ">= 0.8" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, + "ai/node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, + "ai/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 0.6" } }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, + "ai/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/babel" + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/core/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" + "ai/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, + "ai/node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">=6.9.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, + "ai/node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/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": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, + "ai/node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, + "ai/node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", + "backend": { + "name": "@deaf-first/backend", + "version": "2.0.0", "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" + "bcrypt": "^6.0.0", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.21.1", + "helmet": "^8.0.0", + "jsonwebtoken": "^9.0.2", + "pg": "^8.13.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "devDependencies": { + "@types/bcrypt": "^5.0.2", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.0", + "@types/jsonwebtoken": "^9.0.7", + "@types/node": "^22.10.2", + "@types/pg": "^8.11.10", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "eslint": "^9.15.0", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "vitest": "^4.1.6" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "backend/node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "frontend": { + "name": "@deaf-first/frontend", + "version": "2.0.0", + "dependencies": { + "@tanstack/react-query": "^5.59.20", + "axios": "^1.7.8", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "typescript": "^7.0.2", + "vite": "^8.0.12", + "vitest": "^4.0.15" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "frontend/node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, "engines": { - "node": ">=6.9.0" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", + "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" }, "engines": { - "node": ">=6.9.0" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" } }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.1.tgz", + "integrity": "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@apidevtools/json-schema-ref-parser": "11.7.2", + "@apidevtools/openapi-schemas": "^2.1.0", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "openapi-types": ">=7" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { + "node_modules/@babel/compat-data": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", - "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/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/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/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/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -3902,6 +4219,346 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.3.tgz", diff --git a/scripts/generate-sdk.js b/scripts/generate-sdk.js index a6461f5..65e11c2 100644 --- a/scripts/generate-sdk.js +++ b/scripts/generate-sdk.js @@ -18,8 +18,8 @@ const SDK_CONFIGS = { npmName: '@mbtq/sdk', npmVersion: '1.0.0', supportsES6: true, - withSeparateModelsAndApi: true - } + withSeparateModelsAndApi: true, + }, }, python: { generator: 'python', @@ -27,9 +27,9 @@ const SDK_CONFIGS = { additionalProps: { packageName: 'mbtq_sdk', projectName: 'mbtq-sdk', - packageVersion: '1.0.0' - } - } + packageVersion: '1.0.0', + }, + }, }; function ensureDirectoryExists(dir) { @@ -41,16 +41,16 @@ function ensureDirectoryExists(dir) { function generateSDK(service, specPath, language) { const config = SDK_CONFIGS[language]; const outputDir = path.join(SDK_OUTPUT_DIR, config.outputDir, service); - + console.log(`\n📦 Generating ${language} SDK for ${service}...`); - + ensureDirectoryExists(outputDir); - + // Build additional properties string const additionalProps = Object.entries(config.additionalProps) .map(([key, value]) => `${key}=${value}`) .join(','); - + try { // Use openapi-generator-cli without invoking a shell const args = [ @@ -63,17 +63,17 @@ function generateSDK(service, specPath, language) { '-o', outputDir, `--additional-properties=${additionalProps}`, - '--skip-validate-spec' // We already validated + '--skip-validate-spec', // We already validated ]; const result = spawnSync('npx', args, { stdio: 'inherit' }); if (result.status !== 0) { throw new Error(`openapi-generator-cli exited with status ${result.status}`); } - + console.log(` ✅ ${language} SDK generated successfully`); console.log(` 📁 Output: ${outputDir}`); - + return true; } catch (error) { console.error(` ❌ Failed to generate ${language} SDK: ${error.message}`); @@ -85,18 +85,17 @@ function generateAllSDKs(language) { console.log('═══════════════════════════════════════════════════════════'); console.log(` Generating ${language.toUpperCase()} SDKs`); console.log('═══════════════════════════════════════════════════════════'); - - const services = fs.readdirSync(SERVICES_DIR) - .filter(name => { - const servicePath = path.join(SERVICES_DIR, name); - return fs.statSync(servicePath).isDirectory(); - }); - + + const services = fs.readdirSync(SERVICES_DIR).filter((name) => { + const servicePath = path.join(SERVICES_DIR, name); + return fs.statSync(servicePath).isDirectory(); + }); + let successCount = 0; - + for (const service of services) { const specPath = path.join(SERVICES_DIR, service, 'openapi', 'openapi.yaml'); - + if (fs.existsSync(specPath)) { const success = generateSDK(service, specPath, language); if (success) successCount++; @@ -104,15 +103,17 @@ function generateAllSDKs(language) { console.log(`\n⚠️ ${service}: No OpenAPI spec found`); } } - + console.log('\n═══════════════════════════════════════════════════════════'); console.log(`\n📊 Summary:`); console.log(` Services processed: ${services.length}`); console.log(` SDKs generated: ${successCount}`); - + if (successCount === services.length) { console.log(`\n✅ All ${language} SDKs generated successfully!`); - console.log(`📁 Output directory: ${path.join(SDK_OUTPUT_DIR, SDK_CONFIGS[language].outputDir)}`); + console.log( + `📁 Output directory: ${path.join(SDK_OUTPUT_DIR, SDK_CONFIGS[language].outputDir)}` + ); } else { console.log(`\n⚠️ Some SDKs failed to generate`); } diff --git a/scripts/validate-openapi.js b/scripts/validate-openapi.js index eb9ed39..ed95b50 100644 --- a/scripts/validate-openapi.js +++ b/scripts/validate-openapi.js @@ -60,7 +60,13 @@ async function validateAllSpecs() { } else { missingCount += 1; console.log(`\n⚠️ ${service}: No OpenAPI spec found`); - results.push({ valid: true, skipped: true, serviceName: service, pathCount: 0, endpointCount: 0 }); + results.push({ + valid: true, + skipped: true, + serviceName: service, + pathCount: 0, + endpointCount: 0, + }); } } diff --git a/tests/README.md b/tests/README.md index 6fd1267..65a7cb3 100644 --- a/tests/README.md +++ b/tests/README.md @@ -67,6 +67,7 @@ npm test -- tests/openapi.test.js The test suite covers: ### DeafAUTH (Identity Cortex) + - ✅ User registration - ✅ User login - ✅ Token verification @@ -75,6 +76,7 @@ The test suite covers: - ✅ Validation of email format ### PinkSync (Accessibility Engine) + - ✅ Sync status checking - ✅ Accessibility preferences updates - ✅ Feature listing @@ -82,6 +84,7 @@ The test suite covers: - ✅ Preference validation ### Fibonrose (Trust & Blockchain) + - ✅ Transaction verification - ✅ Trust score retrieval - ✅ Transaction recording @@ -89,6 +92,7 @@ The test suite covers: - ✅ Invalid transaction handling ### 360Magicians (AI Agent Platform) + - ✅ Agent creation - ✅ Agent listing and retrieval - ✅ Agent deletion @@ -99,6 +103,7 @@ The test suite covers: - ✅ Health checks ### DAO (Governance) + - ✅ Proposal listing - ✅ Vote submission - ✅ Member listing @@ -107,6 +112,7 @@ The test suite covers: - ✅ Status filtering ### OpenAPI Specifications + - ✅ Valid OpenAPI 3.1.0 version - ✅ Required info fields - ✅ Server definitions @@ -137,14 +143,14 @@ describe('Service Name API', () => { it('should perform expected action', async () => { // Mock response const mockResponse = { - data: { /* expected data */ } + data: {/* expected data */}, }; axios.get.mockResolvedValue(mockResponse); // Make request const response = await axios.get(`${baseURL}/endpoint`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); // Assertions @@ -188,6 +194,7 @@ npm run validate:openapi ``` This validates all OpenAPI specifications for: + - Correct OpenAPI version - Required fields - Valid schemas diff --git a/tests/dao/dao.test.js b/tests/dao/dao.test.js index 1ab34b5..d74b2ce 100644 --- a/tests/dao/dao.test.js +++ b/tests/dao/dao.test.js @@ -23,21 +23,21 @@ describe('MBTQ DAO - Governance API', () => { id: 'prop_1', title: 'Improve Accessibility Features', description: 'Proposal to enhance ASL support', - status: 'active' + status: 'active', }, { id: 'prop_2', title: 'Community Funding', description: 'Allocate funds for community projects', - status: 'pending' - } - ] + status: 'pending', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/proposals`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -54,18 +54,18 @@ describe('MBTQ DAO - Governance API', () => { id: 'prop_1', title: 'Active Proposal', description: 'An active proposal', - status: 'active' - } - ] + status: 'active', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/proposals?status=active`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); - expect(response.data.every(p => p.status === 'active')).toBe(true); + expect(response.data.every((p) => p.status === 'active')).toBe(true); }); }); @@ -73,17 +73,17 @@ describe('MBTQ DAO - Governance API', () => { it('should submit a vote successfully', async () => { const vote = { proposalId: 'prop_1', - vote: 'yes' + vote: 'yes', }; const mockResponse = { - data: vote + data: vote, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/vote`, vote, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data).toMatchObject(vote); @@ -95,21 +95,25 @@ describe('MBTQ DAO - Governance API', () => { axios.post.mockRejectedValue({ response: { status: 400, - data: { error: 'Invalid vote value. Must be yes, no, or abstain' } - } + data: { error: 'Invalid vote value. Must be yes, no, or abstain' }, + }, }); await expect( - axios.post(`${baseURL}/vote`, { - proposalId: 'prop_1', - vote: 'invalid' - }, { - headers: { Authorization: authToken } - }) + axios.post( + `${baseURL}/vote`, + { + proposalId: 'prop_1', + vote: 'invalid', + }, + { + headers: { Authorization: authToken }, + } + ) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 400 - }) + status: 400, + }), }); }); @@ -117,21 +121,25 @@ describe('MBTQ DAO - Governance API', () => { axios.post.mockRejectedValue({ response: { status: 409, - data: { error: 'User has already voted on this proposal' } - } + data: { error: 'User has already voted on this proposal' }, + }, }); await expect( - axios.post(`${baseURL}/vote`, { - proposalId: 'prop_1', - vote: 'yes' - }, { - headers: { Authorization: authToken } - }) + axios.post( + `${baseURL}/vote`, + { + proposalId: 'prop_1', + vote: 'yes', + }, + { + headers: { Authorization: authToken }, + } + ) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 409 - }) + status: 409, + }), }); }); }); @@ -142,19 +150,19 @@ describe('MBTQ DAO - Governance API', () => { data: [ { id: 'member_1', - joinedAt: '2024-01-01T00:00:00Z' + joinedAt: '2024-01-01T00:00:00Z', }, { id: 'member_2', - joinedAt: '2024-01-02T00:00:00Z' - } - ] + joinedAt: '2024-01-02T00:00:00Z', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/members`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -167,16 +175,14 @@ describe('MBTQ DAO - Governance API', () => { axios.get.mockRejectedValue({ response: { status: 401, - data: { error: 'Authentication required' } - } + data: { error: 'Authentication required' }, + }, }); - await expect( - axios.get(`${baseURL}/members`) - ).rejects.toMatchObject({ + await expect(axios.get(`${baseURL}/members`)).rejects.toMatchObject({ response: expect.objectContaining({ - status: 401 - }) + status: 401, + }), }); }); }); diff --git a/tests/deafauth/deafauth.test.js b/tests/deafauth/deafauth.test.js index f81210f..8a015c7 100644 --- a/tests/deafauth/deafauth.test.js +++ b/tests/deafauth/deafauth.test.js @@ -10,7 +10,7 @@ jest.mock('axios'); describe('DeafAUTH - Identity Cortex API', () => { const baseURL = 'https://api.mbtquniverse.com/auth'; - + beforeEach(() => { jest.clearAllMocks(); }); @@ -21,15 +21,15 @@ describe('DeafAUTH - Identity Cortex API', () => { data: { id: 'user_123', email: 'test@example.com', - createdAt: '2024-01-01T00:00:00Z' - } + createdAt: '2024-01-01T00:00:00Z', + }, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/register`, { email: 'test@example.com', - password: 'SecurePass123!' + password: 'SecurePass123!', }); expect(response.data).toHaveProperty('id'); @@ -39,7 +39,7 @@ describe('DeafAUTH - Identity Cortex API', () => { `${baseURL}/register`, expect.objectContaining({ email: 'test@example.com', - password: 'SecurePass123!' + password: 'SecurePass123!', }) ); }); @@ -48,19 +48,19 @@ describe('DeafAUTH - Identity Cortex API', () => { axios.post.mockRejectedValue({ response: { status: 400, - data: { error: 'Invalid email format' } - } + data: { error: 'Invalid email format' }, + }, }); await expect( axios.post(`${baseURL}/register`, { email: 'invalid-email', - password: 'SecurePass123!' + password: 'SecurePass123!', }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 400 - }) + status: 400, + }), }); }); }); @@ -71,15 +71,15 @@ describe('DeafAUTH - Identity Cortex API', () => { data: { accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', refreshToken: 'refresh_token_here', - expiresIn: 3600 - } + expiresIn: 3600, + }, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/login`, { email: 'test@example.com', - password: 'SecurePass123!' + password: 'SecurePass123!', }); expect(response.data).toHaveProperty('accessToken'); @@ -92,19 +92,19 @@ describe('DeafAUTH - Identity Cortex API', () => { axios.post.mockRejectedValue({ response: { status: 401, - data: { error: 'Invalid credentials' } - } + data: { error: 'Invalid credentials' }, + }, }); await expect( axios.post(`${baseURL}/login`, { email: 'test@example.com', - password: 'WrongPassword' + password: 'WrongPassword', }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 401 - }) + status: 401, + }), }); }); }); @@ -113,16 +113,16 @@ describe('DeafAUTH - Identity Cortex API', () => { it('should verify a valid token', async () => { const mockResponse = { data: { - valid: true - } + valid: true, + }, }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/verify`, { headers: { - Authorization: 'Bearer valid_token' - } + Authorization: 'Bearer valid_token', + }, }); expect(response.data.valid).toBe(true); @@ -132,20 +132,20 @@ describe('DeafAUTH - Identity Cortex API', () => { axios.get.mockRejectedValue({ response: { status: 403, - data: { error: 'Invalid token' } - } + data: { error: 'Invalid token' }, + }, }); await expect( axios.get(`${baseURL}/verify`, { headers: { - Authorization: 'Bearer invalid_token' - } + Authorization: 'Bearer invalid_token', + }, }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 403 - }) + status: 403, + }), }); }); }); @@ -156,14 +156,14 @@ describe('DeafAUTH - Identity Cortex API', () => { data: { accessToken: 'new_access_token', refreshToken: 'new_refresh_token', - expiresIn: 3600 - } + expiresIn: 3600, + }, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/refresh`, { - refreshToken: 'valid_refresh_token' + refreshToken: 'valid_refresh_token', }); expect(response.data).toHaveProperty('accessToken'); @@ -174,18 +174,18 @@ describe('DeafAUTH - Identity Cortex API', () => { axios.post.mockRejectedValue({ response: { status: 401, - data: { error: 'Refresh token expired' } - } + data: { error: 'Refresh token expired' }, + }, }); await expect( axios.post(`${baseURL}/refresh`, { - refreshToken: 'expired_token' + refreshToken: 'expired_token', }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 401 - }) + status: 401, + }), }); }); }); diff --git a/tests/fibonrose/fibonrose.test.js b/tests/fibonrose/fibonrose.test.js index 241005d..e715458 100644 --- a/tests/fibonrose/fibonrose.test.js +++ b/tests/fibonrose/fibonrose.test.js @@ -19,17 +19,21 @@ describe('Fibonrose - Trust & Blockchain API', () => { it('should verify a blockchain transaction', async () => { const mockResponse = { data: { - valid: true - } + valid: true, + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/verify`, { - txId: '0x123456789abcdef' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/verify`, + { + txId: '0x123456789abcdef', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data.valid).toBe(true); }); @@ -37,17 +41,21 @@ describe('Fibonrose - Trust & Blockchain API', () => { it('should fail verification for invalid transaction', async () => { const mockResponse = { data: { - valid: false - } + valid: false, + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/verify`, { - txId: 'invalid_tx_id' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/verify`, + { + txId: 'invalid_tx_id', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data.valid).toBe(false); }); @@ -56,18 +64,22 @@ describe('Fibonrose - Trust & Blockchain API', () => { axios.post.mockRejectedValue({ response: { status: 400, - data: { error: 'txId is required' } - } + data: { error: 'txId is required' }, + }, }); await expect( - axios.post(`${baseURL}/verify`, {}, { - headers: { Authorization: authToken } - }) + axios.post( + `${baseURL}/verify`, + {}, + { + headers: { Authorization: authToken }, + } + ) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 400 - }) + status: 400, + }), }); }); }); @@ -77,14 +89,14 @@ describe('Fibonrose - Trust & Blockchain API', () => { const mockResponse = { data: { score: 95.5, - lastUpdated: '2024-01-01T00:00:00Z' - } + lastUpdated: '2024-01-01T00:00:00Z', + }, }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/trust-score`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data).toHaveProperty('score'); @@ -96,16 +108,14 @@ describe('Fibonrose - Trust & Blockchain API', () => { axios.get.mockRejectedValue({ response: { status: 401, - data: { error: 'Authentication required' } - } + data: { error: 'Authentication required' }, + }, }); - await expect( - axios.get(`${baseURL}/trust-score`) - ).rejects.toMatchObject({ + await expect(axios.get(`${baseURL}/trust-score`)).rejects.toMatchObject({ response: expect.objectContaining({ - status: 401 - }) + status: 401, + }), }); }); }); @@ -117,18 +127,18 @@ describe('Fibonrose - Trust & Blockchain API', () => { timestamp: '2024-01-01T00:00:00Z', payload: { type: 'verification', - data: { verified: true } - } + data: { verified: true }, + }, }; const mockResponse = { - data: transaction + data: transaction, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/record`, transaction, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data).toMatchObject(transaction); @@ -139,20 +149,24 @@ describe('Fibonrose - Trust & Blockchain API', () => { axios.post.mockRejectedValue({ response: { status: 400, - data: { error: 'Invalid transaction format' } - } + data: { error: 'Invalid transaction format' }, + }, }); await expect( - axios.post(`${baseURL}/record`, { - invalidField: 'value' - }, { - headers: { Authorization: authToken } - }) + axios.post( + `${baseURL}/record`, + { + invalidField: 'value', + }, + { + headers: { Authorization: authToken }, + } + ) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 400 - }) + status: 400, + }), }); }); }); diff --git a/tests/magicians/magicians.test.js b/tests/magicians/magicians.test.js index 2491c3b..6f1bcaf 100644 --- a/tests/magicians/magicians.test.js +++ b/tests/magicians/magicians.test.js @@ -23,18 +23,22 @@ describe('360Magicians - AI Agent Platform API', () => { id: 'agent_123', name: 'Test Agent', model: 'gpt-4', - createdAt: '2024-01-01T00:00:00Z' - } + createdAt: '2024-01-01T00:00:00Z', + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/agents`, { - name: 'Test Agent', - model: 'gpt-4' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/agents`, + { + name: 'Test Agent', + model: 'gpt-4', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data).toHaveProperty('id'); expect(response.data.name).toBe('Test Agent'); @@ -50,21 +54,21 @@ describe('360Magicians - AI Agent Platform API', () => { id: 'agent_1', name: 'Agent 1', model: 'gpt-4', - createdAt: '2024-01-01T00:00:00Z' + createdAt: '2024-01-01T00:00:00Z', }, { id: 'agent_2', name: 'Agent 2', model: 'claude-3', - createdAt: '2024-01-02T00:00:00Z' - } - ] + createdAt: '2024-01-02T00:00:00Z', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/agents`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -79,14 +83,14 @@ describe('360Magicians - AI Agent Platform API', () => { id: 'agent_123', name: 'Test Agent', model: 'gpt-4', - createdAt: '2024-01-01T00:00:00Z' - } + createdAt: '2024-01-01T00:00:00Z', + }, }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/agents/agent_123`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data.id).toBe('agent_123'); @@ -96,18 +100,18 @@ describe('360Magicians - AI Agent Platform API', () => { axios.get.mockRejectedValue({ response: { status: 404, - data: { error: 'Agent not found' } - } + data: { error: 'Agent not found' }, + }, }); await expect( axios.get(`${baseURL}/agents/invalid_id`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 404 - }) + status: 404, + }), }); }); }); @@ -117,7 +121,7 @@ describe('360Magicians - AI Agent Platform API', () => { axios.delete.mockResolvedValue({ status: 204 }); const response = await axios.delete(`${baseURL}/agents/agent_123`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.status).toBe(204); @@ -133,17 +137,21 @@ describe('360Magicians - AI Agent Platform API', () => { id: 'run_123', status: 'completed', startedAt: '2024-01-01T00:00:00Z', - output: 'Agent response here' - } + output: 'Agent response here', + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/agents/agent_123/execute`, { - input: 'Test input' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/agents/agent_123/execute`, + { + input: 'Test input', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data).toHaveProperty('id'); expect(response.data).toHaveProperty('status'); @@ -157,14 +165,14 @@ describe('360Magicians - AI Agent Platform API', () => { data: { id: 'run_123', status: 'in_progress', - startedAt: '2024-01-01T00:00:00Z' - } + startedAt: '2024-01-01T00:00:00Z', + }, }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/runs/run_123`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data.id).toBe('run_123'); @@ -181,20 +189,20 @@ describe('360Magicians - AI Agent Platform API', () => { { id: 'tool_1', name: 'Web Search', - description: 'Search the web for information' + description: 'Search the web for information', }, { id: 'tool_2', name: 'Calculator', - description: 'Perform mathematical calculations' - } - ] + description: 'Perform mathematical calculations', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/tools`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -208,18 +216,22 @@ describe('360Magicians - AI Agent Platform API', () => { data: { id: 'tool_custom', name: 'Custom Tool', - description: 'A custom tool for specific tasks' - } + description: 'A custom tool for specific tasks', + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/tools`, { - name: 'Custom Tool', - description: 'A custom tool for specific tasks' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/tools`, + { + name: 'Custom Tool', + description: 'A custom tool for specific tasks', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data).toHaveProperty('id'); expect(response.data.name).toBe('Custom Tool'); @@ -235,15 +247,15 @@ describe('360Magicians - AI Agent Platform API', () => { { id: 'mem_1', content: 'Previous conversation context', - timestamp: '2024-01-01T00:00:00Z' - } - ] + timestamp: '2024-01-01T00:00:00Z', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/agents/agent_123/memory`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -256,17 +268,21 @@ describe('360Magicians - AI Agent Platform API', () => { data: { id: 'mem_new', content: 'New memory content', - timestamp: '2024-01-01T00:00:00Z' - } + timestamp: '2024-01-01T00:00:00Z', + }, }; axios.post.mockResolvedValue(mockResponse); - const response = await axios.post(`${baseURL}/agents/agent_123/memory`, { - content: 'New memory content' - }, { - headers: { Authorization: authToken } - }); + const response = await axios.post( + `${baseURL}/agents/agent_123/memory`, + { + content: 'New memory content', + }, + { + headers: { Authorization: authToken }, + } + ); expect(response.data).toHaveProperty('id'); expect(response.data.content).toBe('New memory content'); @@ -279,8 +295,8 @@ describe('360Magicians - AI Agent Platform API', () => { it('should return health status', async () => { const mockResponse = { data: { - status: 'healthy' - } + status: 'healthy', + }, }; axios.get.mockResolvedValue(mockResponse); diff --git a/tests/pinksync/pinksync.test.js b/tests/pinksync/pinksync.test.js index 98c31ed..1782bdf 100644 --- a/tests/pinksync/pinksync.test.js +++ b/tests/pinksync/pinksync.test.js @@ -20,14 +20,14 @@ describe('PinkSync - Accessibility Engine API', () => { const mockResponse = { data: { online: true, - latencyMs: 45 - } + latencyMs: 45, + }, }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/status`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data).toHaveProperty('online'); @@ -40,18 +40,18 @@ describe('PinkSync - Accessibility Engine API', () => { axios.get.mockRejectedValue({ response: { status: 503, - data: { error: 'Service temporarily unavailable' } - } + data: { error: 'Service temporarily unavailable' }, + }, }); await expect( axios.get(`${baseURL}/status`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 503 - }) + status: 503, + }), }); }); }); @@ -62,17 +62,17 @@ describe('PinkSync - Accessibility Engine API', () => { captions: true, aslMode: true, contrast: 'high', - fontSize: 'large' + fontSize: 'large', }; const mockResponse = { - data: preferences + data: preferences, }; axios.post.mockResolvedValue(mockResponse); const response = await axios.post(`${baseURL}/preferences`, preferences, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(response.data).toMatchObject(preferences); @@ -84,21 +84,25 @@ describe('PinkSync - Accessibility Engine API', () => { axios.post.mockRejectedValue({ response: { status: 400, - data: { error: 'Invalid contrast value' } - } + data: { error: 'Invalid contrast value' }, + }, }); await expect( - axios.post(`${baseURL}/preferences`, { - captions: true, - contrast: 'invalid_value' - }, { - headers: { Authorization: authToken } - }) + axios.post( + `${baseURL}/preferences`, + { + captions: true, + contrast: 'invalid_value', + }, + { + headers: { Authorization: authToken }, + } + ) ).rejects.toMatchObject({ response: expect.objectContaining({ - status: 400 - }) + status: 400, + }), }); }); }); @@ -110,25 +114,25 @@ describe('PinkSync - Accessibility Engine API', () => { { id: 'captions', name: 'Real-time Captions', - description: 'Auto-generated captions for all audio content' + description: 'Auto-generated captions for all audio content', }, { id: 'asl', name: 'ASL Mode', - description: 'American Sign Language video interpretation' + description: 'American Sign Language video interpretation', }, { id: 'contrast', name: 'High Contrast', - description: 'Enhanced visual contrast for better readability' - } - ] + description: 'Enhanced visual contrast for better readability', + }, + ], }; axios.get.mockResolvedValue(mockResponse); const response = await axios.get(`${baseURL}/features`, { - headers: { Authorization: authToken } + headers: { Authorization: authToken }, }); expect(Array.isArray(response.data)).toBe(true); @@ -142,16 +146,14 @@ describe('PinkSync - Accessibility Engine API', () => { axios.get.mockRejectedValue({ response: { status: 401, - data: { error: 'Authentication required' } - } + data: { error: 'Authentication required' }, + }, }); - await expect( - axios.get(`${baseURL}/features`) - ).rejects.toMatchObject({ + await expect(axios.get(`${baseURL}/features`)).rejects.toMatchObject({ response: expect.objectContaining({ - status: 401 - }) + status: 401, + }), }); }); });