From bc3768819fa0db285ed772a198c6de09958f7f2f Mon Sep 17 00:00:00 2001 From: Jamil Afouri Date: Sun, 22 Mar 2026 20:10:01 +0300 Subject: [PATCH 1/2] Prepare repository for open-source release - Remove proprietary branding from layout, icon, and sample webhook events - Replace domain-specific events with generic e-commerce examples - Rewrite README with features, setup guide, and API reference - Add LICENSE (MIT), CONTRIBUTING, CODE_OF_CONDUCT, SECURITY.md - Add CHANGELOG following Keep a Changelog format - Parameterize hardcoded credentials across Docker and shell scripts - Add engines field to package.json and .nvmrc for Node 20 - Add GitHub issue/PR templates (YAML forms), dependabot config - Add README badges (license, Node, TypeScript, Docker, PRs welcome) - Fix .dockerignore to exclude all .env variants --- .dockerignore | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 94 ++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/feature_request.yml | 50 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 22 +++ .github/dependabot.yml | 17 +++ .nvmrc | 1 + CHANGELOG.md | 21 +++ CODE_OF_CONDUCT.md | 33 +++++ CONTRIBUTING.md | 63 ++++++++ Dockerfile | 2 +- LICENSE | 21 +++ README.md | 160 ++++++++++++++++++--- SECURITY.md | 59 ++++++++ docker-compose.yml | 6 +- docker-entrypoint.sh | 4 +- package.json | 3 + src/app/icon.svg | 8 +- src/app/layout.tsx | 4 +- src/components/test-trigger-panel.tsx | 76 +++++----- start.sh | 9 +- 21 files changed, 582 insertions(+), 78 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .nvmrc create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 SECURITY.md diff --git a/.dockerignore b/.dockerignore index 01b87ea..bc5e028 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ node_modules .next .git -.env +.env* *.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..74a0694 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,94 @@ +name: Bug Report +description: Report a bug or unexpected behavior +title: "[Bug]: " +labels: ["bug"] + +body: + - type: textarea + id: description + attributes: + label: Description + description: A clear description of the bug. + placeholder: Describe the bug you encountered. + validations: + required: true + + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps to Reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. Scroll down to '...' + 4. See error + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: What you expected to happen. + placeholder: Describe what you expected to happen. + validations: + required: true + + - type: textarea + id: actual-behavior + attributes: + label: Actual Behavior + description: What actually happened. + placeholder: Describe what actually happened. + validations: + required: true + + - type: dropdown + id: os + attributes: + label: Operating System + description: Which operating system are you using? + options: + - macOS + - Windows + - Linux + - Other + validations: + required: true + + - type: input + id: node-version + attributes: + label: Node.js Version + description: What version of Node.js are you running? + placeholder: e.g. 20.11.0 + validations: + required: false + + - type: input + id: docker-version + attributes: + label: Docker Version + description: What version of Docker are you running, if applicable? + placeholder: e.g. 24.0.7 + validations: + required: false + + - type: input + id: browser + attributes: + label: Browser + description: Which browser are you using, if this is a UI-related issue? + placeholder: e.g. Chrome 122, Firefox 124, Safari 17 + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Any other information, screenshots, or logs that might help. + placeholder: Add any other context about the problem here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a45080b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Discussions + url: https://github.com/keyper/webhook-tester/discussions + about: Ask questions and discuss ideas in GitHub Discussions. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..2b440f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,50 @@ +name: Feature Request +description: Suggest a new feature or improvement +title: "[Feature]: " +labels: ["enhancement"] + +body: + - type: textarea + id: description + attributes: + label: Description + description: A clear description of the feature you would like. + placeholder: Describe the feature you are requesting. + validations: + required: true + + - type: textarea + id: use-case + attributes: + label: Use Case + description: Why is this feature needed? What problem does it solve? + placeholder: Explain the use case and motivation for this feature. + validations: + required: true + + - type: textarea + id: proposed-solution + attributes: + label: Proposed Solution + description: How you think this could work. Include API designs, UI mockups, or behavior descriptions if relevant. + placeholder: Describe your proposed solution. + validations: + required: false + + - type: textarea + id: alternatives-considered + attributes: + label: Alternatives Considered + description: Any alternative approaches you have thought about. + placeholder: Describe any alternative solutions or features you have considered. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Any other information that might be helpful. + placeholder: Add any other context about the feature request here. + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..20baccf --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +## Description + +What does this PR do? Briefly describe the change. + +## Type of Change + +- [ ] Bug fix +- [ ] New feature +- [ ] Documentation update +- [ ] Refactoring +- [ ] Other (describe): + +## Testing + +- [ ] Tested locally with `npm run dev` +- [ ] Linting passes (`npm run lint`) +- [ ] Docker build works (`docker build -t webhook-tester .`) +- [ ] Existing functionality is not broken + +## Notes + +Any additional context or notes for reviewers. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3c5f79d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + target-branch: "main" + open-pull-requests-limit: 10 + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + target-branch: "main" + open-pull-requests-limit: 10 diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ab613fd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2026-03-22 + +### Added + +- Initial open-source release +- Channel management with unique webhook URLs +- Configurable response behaviors (success, errors, timeouts, slow responses, redirects) +- Behavior sequences for rotating through responses +- JWT signature verification support +- 24 predefined test scenarios +- Real-time event streaming via Server-Sent Events +- Full webhook history with request/response details +- Docker support with embedded PostgreSQL +- Web UI for channel management and webhook inspection diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..da9bcb5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,33 @@ +# Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a welcoming experience for everyone. + +## Our Standards + +Examples of behavior that contributes to a positive environment: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community + +Examples of unacceptable behavior: + +- Trolling, insulting or derogatory comments, and personal attacks +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement + +Instances of unacceptable behavior may be reported to the project maintainers. +All complaints will be reviewed and investigated and will result in a response +that is deemed necessary and appropriate to the circumstances. + +## Attribution + +This Code of Conduct is adapted from the +[Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..584a5b0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# Contributing to Webhook Tester + +Thanks for your interest in contributing! This document covers the essentials. + +## Getting Started + +See the [README](README.md) for instructions on setting up the development environment. + +## Reporting Issues + +- Search existing issues before opening a new one. +- Use the appropriate issue template (bug report or feature request). +- Provide as much detail as possible, including steps to reproduce for bugs. + +## Submitting Pull Requests + +1. Fork the repository and create a branch from `main`. +2. Make your changes in a focused, single-purpose branch. +3. Ensure your code passes linting and any existing tests. +4. Fill out the pull request template when submitting. +5. Keep pull requests small and reviewable when possible. + +## Code Style + +This project includes an ESLint configuration (`eslint.config.mjs`). Run the linter before submitting: + +```bash +npm run lint +``` + +Follow the existing code patterns and conventions you see in the codebase. + +## Commit Messages + +This project follows [Conventional Commits](https://www.conventionalcommits.org/). Format your commit messages as: + +``` +(): + +[optional body] +``` + +Common types: + +- `feat` -- a new feature +- `fix` -- a bug fix +- `docs` -- documentation changes +- `style` -- formatting, no code change +- `refactor` -- code restructuring without behavior change +- `test` -- adding or updating tests +- `chore` -- maintenance tasks + +Examples: + +``` +feat(api): add webhook retry endpoint +fix(ui): correct timestamp display in request list +docs: update setup instructions in README +``` + +## Code of Conduct + +This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. diff --git a/Dockerfile b/Dockerfile index d454d6f..e5ed2b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,6 +47,6 @@ RUN chmod +x /docker-entrypoint.sh EXPOSE 4100 ENV PORT=4100 ENV HOSTNAME="0.0.0.0" -ENV DATABASE_URL="postgres://webhook:webhook_local@localhost:5432/webhook_tester" +ENV DATABASE_URL=${DATABASE_URL:-postgres://webhook:webhook_local@localhost:5432/webhook_tester} ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a489b16 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024-present Webhook Tester Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e215bc4..0528e16 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,152 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# Webhook Tester -## Getting Started +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Node.js](https://img.shields.io/badge/Node.js-20%2B-green.svg)](https://nodejs.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5-blue.svg)](https://www.typescriptlang.org/) [![Docker](https://img.shields.io/badge/Docker-ready-blue.svg)](Dockerfile) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) -First, run the development server: +A self-hosted tool for testing webhook delivery, retry logic, and failure handling. -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +## What It Does + +Webhook Tester lets you create isolated channels that receive webhooks and respond with configurable behaviors. Point your webhook producer at a channel URL, then simulate successes, errors, timeouts, slow responses, and more. Use it to verify retry logic, test circuit breaker behavior, validate JWT signatures, and run predefined test scenarios -- all through a web UI or REST API. + +## Features + +- Create isolated webhook channels, each with a unique URL, behavior config, and history +- Simulate responses: 200 OK, 400/401/404/429, 500, timeouts, slow responses, redirects +- Behavior sequences -- rotate through a list of responses across consecutive requests +- JWT signature verification (RS256) via configurable public key per channel +- 24 predefined test scenarios covering retry logic, circuit breakers, exponential backoff, edge cases, and more +- Real-time event stream via Server-Sent Events (SSE) +- Full webhook history with request headers, body, and response details +- Delivery analysis that groups attempts by event ID and computes retry gaps +- Docker-ready with embedded PostgreSQL -- single container, no external dependencies + +## Quick Start + +### Docker (single command) + +```sh +docker build -t webhook-tester . && docker run -p 4100:4100 webhook-tester ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Open `http://localhost:4100`. Create a channel, then send webhooks to `http://localhost:4100/api/webhook/{slug}`. + +### Local Development + +Requires Node.js 20+ and Docker (for PostgreSQL). + +```sh +./start.sh dev +``` + +This starts PostgreSQL in Docker, runs migrations, and launches the dev server with hot reload on port 4100. + +## Local Development Setup + +```sh +# Clone the repository +git clone && cd webhook-tester + +# Install dependencies +npm install + +# Create environment file +cp .env.example .env + +# Start PostgreSQL +docker compose up -d db + +# Run database migrations +DATABASE_URL="postgres://webhook:webhook_local@localhost:5433/webhook_tester" npx prisma db push + +# Generate Prisma client +npx prisma generate + +# Start the dev server +DATABASE_URL="postgres://webhook:webhook_local@localhost:5433/webhook_tester" npm run dev +``` + +Or simply run `./start.sh` which handles all of the above automatically. + +## Usage + +1. **Create a channel** -- Open the UI at `http://localhost:4100` and create a channel with a slug (e.g., `my-test`). +2. **Send webhooks** -- Point your webhook producer at `http://localhost:4100/api/webhook/my-test`. +3. **Configure behavior** -- Use the UI or API to set how the channel responds (success, error, timeout, sequence, etc.). +4. **Observe results** -- Watch incoming webhooks in real time. Review history, retry patterns, and delivery analysis. +5. **Run scenarios** -- Activate a predefined scenario to test specific patterns like retry exhaustion or circuit breaker tripping. + +## API Reference + +### Health + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/health` | Health check and uptime | + +### Channel Management + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/channels` | List all channels | +| POST | `/api/channels` | Create a channel (`{ slug, name }`) | +| GET | `/api/channels/:slug` | Get channel details and state | +| DELETE | `/api/channels/:slug` | Delete a channel and all its data | +| GET | `/api/channels/:slug/status` | Get current channel state | +| POST | `/api/channels/:slug/behavior` | Set response behavior (`{ behavior, delayMs?, statusCode? }`) | +| POST | `/api/channels/:slug/sequence` | Set behavior sequence (`{ steps: [{ behavior, delayMs? }] }`) | +| POST | `/api/channels/:slug/public-key` | Set public key for JWT verification (`{ publicKey }`) | +| POST | `/api/channels/:slug/reset` | Reset channel to defaults and clear history | + +### Webhook Receiver + +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/api/webhook/:slug` | Receive a webhook (this is the URL you give to producers) | +| POST | `/api/webhook/:slug/*` | Receive a webhook on any sub-path | + +### History and Analysis + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/channels/:slug/history` | Get webhook history (`?limit=&offset=&event=`) | +| DELETE | `/api/channels/:slug/history` | Clear webhook history | +| GET | `/api/channels/:slug/history/last` | Get the most recent webhook | +| GET | `/api/channels/:slug/history/:id` | Get a specific webhook by ID | +| GET | `/api/channels/:slug/observe` | Delivery analysis (grouped by event ID) | +| GET | `/api/channels/:slug/observe/:eventId` | Delivery analysis for a specific event | + +### Scenarios + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/scenarios` | List all predefined scenarios | +| POST | `/api/channels/:slug/scenarios/:name/activate` | Activate a scenario on a channel | + +### Real-Time Events + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/channels/:slug/events` | SSE stream (events: `webhook`, `state-change`, `reset`, `history-cleared`) | + +## Configuration -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +| Variable | Default | Description | +|----------|---------|-------------| +| `DATABASE_URL` | `postgres://webhook:webhook_local@localhost:5433/webhook_tester` | PostgreSQL connection string | +| `PORT` | `4100` | Server port | -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +## Security Note -## Learn More +Management endpoints (channel creation, behavior configuration, history) have no authentication. This tool is intended for local development and internal test environments. If you deploy it on a publicly accessible server, put it behind a reverse proxy with authentication. -To learn more about Next.js, take a look at the following resources: +## Tech Stack -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +Next.js, React, PostgreSQL, Prisma, TypeScript, Tailwind CSS -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +## Contributing -## Deploy on Vercel +See [CONTRIBUTING.md](CONTRIBUTING.md). -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +## License -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +[MIT](LICENSE) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..4af8101 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,59 @@ +# Security Policy + +We take the security of this project seriously. If you believe you have found a security vulnerability, please follow the responsible disclosure process outlined below. + +## Reporting a Vulnerability + +**Do NOT report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Instead, please use [GitHub's Private Vulnerability Reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) feature to submit your report. This ensures that sensitive details remain confidential until a fix is available. + +When reporting, please include as much of the following as possible: + +- A description of the vulnerability and its potential impact +- Step-by-step instructions to reproduce the issue +- Any relevant logs, screenshots, or proof-of-concept code +- The version(s) affected, if known + +## Response Timeline + +- **Acknowledgment:** We will acknowledge receipt of your report within 48 hours. +- **Detailed response:** We will provide a detailed response within 7 days, including an assessment of the issue and an expected timeline for a fix. +- **Fix and disclosure:** Once a fix is ready, we will coordinate with you on an appropriate disclosure timeline. + +## What Qualifies as a Security Issue + +Security issues include, but are not limited to: + +- Authentication or authorization bypasses +- Injection vulnerabilities (SQL, command, etc.) +- Cross-site scripting (XSS) or cross-site request forgery (CSRF) +- Exposure of sensitive data (credentials, tokens, personal information) +- Remote code execution +- Privilege escalation +- Denial of service vulnerabilities with a clear exploit path + +The following are generally **not** security issues and should be filed as regular bug reports: + +- Application crashes without a security impact +- UI/UX bugs +- Performance issues +- Feature requests +- Issues requiring physical access to a user's device + +If you are unsure whether something qualifies as a security issue, err on the side of caution and report it through the private vulnerability reporting process. + +## Coordinated Disclosure + +We follow a coordinated disclosure model: + +1. The reporter submits the vulnerability privately. +2. We work to verify and develop a fix. +3. We coordinate with the reporter on a disclosure date, typically once a fix has been released. +4. We publicly disclose the vulnerability along with credit to the reporter (unless anonymity is requested). + +We ask that reporters refrain from publicly disclosing the vulnerability until we have had a reasonable opportunity to address it. + +## Thank You + +We appreciate the efforts of security researchers and community members who help keep this project safe. Responsible disclosure makes a meaningful difference. diff --git a/docker-compose.yml b/docker-compose.yml index c67c7d1..ccaec37 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,9 @@ services: db: image: postgres:16-alpine environment: - POSTGRES_DB: webhook_tester - POSTGRES_USER: webhook - POSTGRES_PASSWORD: webhook_local + POSTGRES_USER: ${POSTGRES_USER:-webhook} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-webhook_local} + POSTGRES_DB: ${POSTGRES_DB:-webhook_tester} ports: - '5433:5432' volumes: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index f805735..0926532 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -3,8 +3,8 @@ set -e PGDATA="/var/lib/postgresql/data" DB_NAME="webhook_tester" -DB_USER="webhook" -DB_PASS="webhook_local" +DB_USER="${DB_USER:-webhook}" +DB_PASS="${DB_PASS:-webhook_local}" # ── 1. Initialize PostgreSQL if needed ─────────────────────── if [ ! -f "$PGDATA/PG_VERSION" ]; then diff --git a/package.json b/package.json index d5a49e2..cb57d9d 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "webhook-tester", "version": "0.1.0", "private": true, + "engines": { + "node": ">=20.0.0" + }, "scripts": { "dev": "next dev", "build": "next build", diff --git a/src/app/icon.svg b/src/app/icon.svg index c835663..a0dc008 100644 --- a/src/app/icon.svg +++ b/src/app/icon.svg @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9607aa9..7ed736d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,8 +5,8 @@ import './globals.css' const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { - title: 'Webhook Tester — Keyper', - description: 'QA tool for testing the full webhook delivery lifecycle', + title: 'Webhook Tester', + description: 'A developer tool for testing webhook delivery, retry logic, and failure scenarios', } export const viewport: Viewport = { diff --git a/src/components/test-trigger-panel.tsx b/src/components/test-trigger-panel.tsx index 27ef98b..254eac6 100644 --- a/src/components/test-trigger-panel.tsx +++ b/src/components/test-trigger-panel.tsx @@ -5,62 +5,60 @@ import { useState, useEffect } from 'react' type WebhookEventDef = { value: string label: string - category: 'application' | 'tenancy' | 'test' + category: 'order' | 'payment' | 'test' payload: object context: Record } const webhookEvents: WebhookEventDef[] = [ - // Application lifecycle - { value: 'application.qualified', label: 'Qualified', category: 'application', payload: { annualRentalPower: 144000 }, context: { applicationId: 'test-app-001' } }, - { value: 'application.approved', label: 'Approved', category: 'application', payload: {}, context: { applicationId: 'test-app-001' } }, - { value: 'application.rejected', label: 'Rejected', category: 'application', payload: { reason: { code: 'INSUFFICIENT_INCOME', message: 'Insufficient income documentation' } }, context: { applicationId: 'test-app-001' } }, - { value: 'application.change_requested', label: 'Change Requested', category: 'application', payload: { requestedDocuments: [{ action: 'reupload', documentType: 'general', reason: 'Please re-upload the tenancy contract with valid signatures' }] }, context: { applicationId: 'test-app-001' } }, - { value: 'application.withdrawn', label: 'Withdrawn', category: 'application', payload: { previousStatus: 'document_submitted', reason: 'Tenant chose a different property' }, context: { applicationId: 'test-app-001' } }, - { value: 'application.documents_submitted', label: 'Documents Submitted', category: 'application', payload: {}, context: { applicationId: 'test-app-001' } }, + // Order lifecycle + { value: 'order.created', label: 'Created', category: 'order', payload: { orderId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', totalAmount: 14999, currency: 'USD' }, context: { orderId: 'test-order-001' } }, + { value: 'order.confirmed', label: 'Confirmed', category: 'order', payload: {}, context: { orderId: 'test-order-001' } }, + { value: 'order.cancelled', label: 'Cancelled', category: 'order', payload: { reason: { code: 'CUSTOMER_REQUEST', message: 'Customer requested cancellation' } }, context: { orderId: 'test-order-001' } }, + { value: 'order.updated', label: 'Updated', category: 'order', payload: { changes: [{ field: 'shipping_address', reason: 'Customer updated their delivery address' }] }, context: { orderId: 'test-order-001' } }, + { value: 'order.refunded', label: 'Refunded', category: 'order', payload: { previousStatus: 'confirmed', reason: 'Item out of stock' }, context: { orderId: 'test-order-001' } }, + { value: 'order.fulfilled', label: 'Fulfilled', category: 'order', payload: { trackingNumber: '1Z999AA10123456784', carrier: 'UPS' }, context: { orderId: 'test-order-001' } }, - // Tenancy signing lifecycle - { value: 'tenancy.in_signing', label: 'In Signing', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.rent_confirmed', label: 'Rent Confirmed', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.payment_plan_confirmed', label: 'Payment Plan Confirmed', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.tpma_tenant_signed', label: 'Tenant Signed', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.tpma_tenant_declined', label: 'Tenant Declined', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.tpma_keyper_signed', label: 'Keyper Signed', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.tpma_keyper_declined', label: 'Keyper Declined', category: 'tenancy', payload: { tenancyId: 'a0B7Q000001XXXXYY' }, context: { tenancyId: 'test-tenancy-001' } }, - { value: 'tenancy.published', label: 'Published', category: 'tenancy', payload: { - tenancyId: 'a0B7Q000001XXXXYY', - firstPayments: [ - { id: 'a0C7Q000001XXXXYY', type: 'RENT_RNPL', amount: 12000, from: 'tenant', to: 'keyper', status: 'Paid' }, - { id: 'a0C7Q000001XXXXYZ', type: 'RENT', amount: 5000, from: 'keyper', to: 'landlord', status: 'Pending' }, + // Payment lifecycle + { value: 'payment.completed', label: 'Completed', category: 'payment', payload: { paymentId: 'c9bf9e57-1685-4c89-bafb-ff5af830be8a' }, context: { paymentId: 'test-payment-001' } }, + { value: 'payment.failed', label: 'Failed', category: 'payment', payload: { paymentId: 'c9bf9e57-1685-4c89-bafb-ff5af830be8a', errorCode: 'CARD_DECLINED' }, context: { paymentId: 'test-payment-001' } }, + { value: 'payment.refunded', label: 'Refunded', category: 'payment', payload: { paymentId: 'c9bf9e57-1685-4c89-bafb-ff5af830be8a', refundAmount: 4999 }, context: { paymentId: 'test-payment-001' } }, + { value: 'invoice.paid', label: 'Invoice Paid', category: 'payment', payload: { invoiceId: 'e4d909c2-90d0-4b05-9c59-f5b21bde4e50', amount: 9900, currency: 'USD' }, context: { invoiceId: 'test-invoice-001' } }, + { value: 'invoice.overdue', label: 'Invoice Overdue', category: 'payment', payload: { invoiceId: 'e4d909c2-90d0-4b05-9c59-f5b21bde4e50', dueDate: '2025-01-15', daysOverdue: 7 }, context: { invoiceId: 'test-invoice-001' } }, + { value: 'subscription.renewed', label: 'Subscription Renewed', category: 'payment', payload: { + subscriptionId: 'b2d8f636-28a2-4b6e-bc6e-31f58c27a9b3', + plan: 'pro', + billingPeriod: 'monthly', + nextBillingDate: '2025-03-01T00:00:00.000Z', + lineItems: [ + { id: '7c9e6679-7425-40de-944b-e07fc1f90ae7', type: 'SUBSCRIPTION_FEE', amount: 4900, description: 'Pro plan - monthly', status: 'Paid' }, + { id: 'aab3238e-e612-4e3a-b2e5-7c5e2b0c93f1', type: 'PLATFORM_FEE', amount: 500, description: 'Platform usage fee', status: 'Paid' }, ], - payments: [ - { id: 'a0C7Q000001XXXXZZ', type: 'RENT_RNPL', amount: 5000, from: 'tenant', to: 'keyper', status: 'Pending' }, - ], - }, context: { tenancyId: 'test-tenancy-001' } }, + }, context: { subscriptionId: 'test-sub-001' } }, - // Tenancy payment lifecycle - { value: 'tenancy.tpma_first_payment_attempt', label: 'First Payment Attempt', category: 'tenancy', payload: { - tenancyId: 'a0B7Q000001XXXXYY', + // Payment attempt details + { value: 'payment.initial_attempt', label: 'Initial Attempt', category: 'payment', payload: { + orderId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', totalAmount: 15000, status: 'succeeded', successfulPayments: [ - { paymentId: 'a0C7Q000001XXXXYY', amount: 12000, paymentType: 'RENT_RNPL', clearedAt: '2024-06-15T10:30:00.000Z' }, - { paymentId: 'a0C7Q000001XXXXYZ', amount: 3000, paymentType: 'DIGITAL_MANAGEMENT_FEE', clearedAt: '2024-06-15T10:30:00.000Z' }, + { paymentId: '7c9e6679-7425-40de-944b-e07fc1f90ae7', amount: 12000, paymentType: 'ORDER_PAYMENT', clearedAt: '2025-01-15T10:30:00.000Z' }, + { paymentId: 'aab3238e-e612-4e3a-b2e5-7c5e2b0c93f1', amount: 3000, paymentType: 'SERVICE_FEE', clearedAt: '2025-01-15T10:30:00.000Z' }, ], failedPayments: [], - }, context: { tenancyId: 'test-tenancy-001', paymentId: 'test-payment-001' } }, - { value: 'tenancy.payment_attempt', label: 'Payment Attempt', category: 'tenancy', payload: { - tenancyId: 'a0B7Q000001XXXXYY', + }, context: { orderId: 'test-order-001', paymentId: 'test-payment-001' } }, + { value: 'payment.retry_attempt', label: 'Retry Attempt', category: 'payment', payload: { + orderId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', totalAmount: 5000, status: 'succeeded', - type: 'user', + type: 'retry', payments: [ - { paymentId: 'a0C7Q000001XXXXYY', amount: 5000, paymentType: 'RENT_RNPL', from: 'tenant', to: 'keyper', status: 'succeeded', clearedAt: '2024-07-01T09:00:00.000Z' }, + { paymentId: '7c9e6679-7425-40de-944b-e07fc1f90ae7', amount: 5000, paymentType: 'ORDER_PAYMENT', from: 'customer', to: 'merchant', status: 'succeeded', clearedAt: '2025-02-01T09:00:00.000Z' }, ], - }, context: { tenancyId: 'test-tenancy-001', paymentId: 'test-payment-001' } }, + }, context: { orderId: 'test-order-001', paymentId: 'test-payment-001' } }, // Test - { value: 'test.ping', label: 'Test Ping', category: 'test', payload: { message: 'This is a test webhook from Keyper' }, context: {} }, + { value: 'test.ping', label: 'Test Ping', category: 'test', payload: { message: 'This is a test webhook event' }, context: {} }, ] const DEFAULT_EVENT_INDEX = Math.max(0, webhookEvents.findIndex(e => e.value === 'test.ping')) @@ -183,9 +181,9 @@ export function TestTriggerPanel({ channelSlug }: { channelSlug: string }) { {/* Event type */}
- {(['application', 'tenancy', 'test'] as const).map(category => { + {(['order', 'payment', 'test'] as const).map(category => { const categoryEvents = webhookEvents.filter(e => e.category === category) - const categoryLabel = { application: 'Application', tenancy: 'Tenancy', test: 'Test' }[category] + const categoryLabel = { order: 'Order', payment: 'Payment', test: 'Test' }[category] return (
{categoryLabel}
diff --git a/start.sh b/start.sh index d828c92..d3fe543 100755 --- a/start.sh +++ b/start.sh @@ -4,7 +4,7 @@ # # Usage: # ./start.sh # Dev mode (hot reload) -# ./start.sh prod # Production (single Docker container for EC2) +# ./start.sh prod # Production (single Docker container for server) # ./start.sh --port 4200 # Custom port # # Stop: ./stop.sh or Ctrl+C @@ -24,7 +24,7 @@ while [[ $# -gt 0 ]]; do echo "" echo " Usage:" echo " ./start.sh Dev (hot reload + DB in Docker)" - echo " ./start.sh prod Production (single container for EC2)" + echo " ./start.sh prod Production (single container for server)" echo " ./start.sh --port 4200 Custom port" echo "" exit 0 @@ -87,7 +87,8 @@ fi # Migrations echo " Running migrations..." -DATABASE_URL="postgres://webhook:webhook_local@localhost:5433/webhook_tester" npx prisma db push --skip-generate 2>&1 | grep -v "^$" | sed 's/^/ /' +source .env 2>/dev/null || true +DATABASE_URL="${DATABASE_URL:-postgres://webhook:webhook_local@localhost:5433/webhook_tester}" npx prisma db push --skip-generate 2>&1 | grep -v "^$" | sed 's/^/ /' # Kill existing EXISTING=$(lsof -ti:$PORT 2>/dev/null || true) @@ -100,4 +101,4 @@ echo " http://localhost:$PORT" echo " Webhook URL: http://localhost:$PORT/api/webhook/{slug}" echo "" -DATABASE_URL="postgres://webhook:webhook_local@localhost:5433/webhook_tester" PORT=$PORT npx next dev -p "$PORT" +DATABASE_URL="${DATABASE_URL:-postgres://webhook:webhook_local@localhost:5433/webhook_tester}" PORT=$PORT npx next dev -p "$PORT" From 9ca3f51910c763ee5ad7364ed1d6b4c9d43f57ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:12:09 +0000 Subject: [PATCH 2/2] Bump eslint from 9.39.4 to 10.1.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.39.4 to 10.1.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v9.39.4...v10.1.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.1.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 719 ++++++++++++++++++---------------------------- package.json | 2 +- 2 files changed, 282 insertions(+), 439 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9eea82e..cc7277c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,10 +25,13 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "eslint": "^9", + "eslint": "^10", "eslint-config-next": "16.1.6", "tailwindcss": "^4", "typescript": "^5" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@alloc/quick-lru": { @@ -100,6 +103,19 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@babel/generator": { "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", @@ -207,23 +223,23 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { @@ -420,105 +436,68 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.3", "debug": "^4.3.1", - "minimatch": "^3.1.5" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", + "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.1.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@hono/node-server": { @@ -1742,6 +1721,70 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.8.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.8.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", @@ -1801,6 +1844,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -2067,45 +2117,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -2161,19 +2172,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", @@ -2483,29 +2481,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -2739,11 +2714,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/baseline-browser-mapping": { "version": "2.10.0", @@ -2758,14 +2736,16 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -2911,16 +2891,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001777", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", @@ -2941,23 +2911,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/chevrotain": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", @@ -3002,26 +2955,6 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3293,9 +3226,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", "dev": true, "license": "ISC" }, @@ -3419,9 +3352,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.0.tgz", - "integrity": "sha512-04cg8iJFDOxWcYlu0GFFWgs7vtaEPCmr5w1nrj9V3z3axu/48HCMwK6VMp45Zh3ZB+xLP1ifbJfrq86+1ypKKQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.1.tgz", + "integrity": "sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3531,33 +3464,30 @@ } }, "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz", + "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", "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", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.3", + "@eslint/config-helpers": "^0.5.3", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.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", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3567,8 +3497,7 @@ "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", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3576,7 +3505,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -3617,42 +3546,25 @@ } } }, - "node_modules/eslint-config-next/node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "node_modules/eslint-config-next/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } + "license": "MIT" }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-config-next/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint-import-resolver-typescript": { + "node_modules/eslint-config-next/node_modules/eslint-import-resolver-typescript": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", @@ -3687,35 +3599,7 @@ } } }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { + "node_modules/eslint-config-next/node_modules/eslint-plugin-import": { "version": "2.32.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", @@ -3749,7 +3633,7 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { + "node_modules/eslint-config-next/node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", @@ -3759,7 +3643,7 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-jsx-a11y": { + "node_modules/eslint-config-next/node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", @@ -3789,7 +3673,7 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, - "node_modules/eslint-plugin-react": { + "node_modules/eslint-config-next/node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", @@ -3822,7 +3706,7 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react-hooks": { + "node_modules/eslint-config-next/node_modules/eslint-plugin-react-hooks": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", @@ -3842,7 +3726,33 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-next/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-config-next/node_modules/resolve": { "version": "2.0.0-next.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", @@ -3866,49 +3776,101 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -4279,9 +4241,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4321,19 +4283,6 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -4395,16 +4344,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -4534,23 +4473,6 @@ "node": ">= 4" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -5044,19 +4966,6 @@ "dev": true, "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -5092,16 +5001,16 @@ "license": "MIT" }, "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, "bin": { "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" } }, "node_modules/jsonwebtoken": { @@ -5547,13 +5456,6 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -5649,16 +5551,19 @@ } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -6089,19 +5994,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6672,16 +6564,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -7231,19 +7113,6 @@ "node": ">=4" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -7267,19 +7136,6 @@ } } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -7410,19 +7266,6 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", diff --git a/package.json b/package.json index cb57d9d..bb37cee 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "eslint": "^9", + "eslint": "^10", "eslint-config-next": "16.1.6", "tailwindcss": "^4", "typescript": "^5"