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 26917c8a42224f230f8929f7481b96729cda2975 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:12:23 +0000 Subject: [PATCH 2/2] Bump next from 16.1.6 to 16.2.1 Bumps [next](https://github.com/vercel/next.js) from 16.1.6 to 16.2.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v16.1.6...v16.2.1) --- updated-dependencies: - dependency-name: next dependency-version: 16.2.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 151 +++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 110 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9eea82e..e6349d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@prisma/client": "^7.5.0", "dotenv": "^17.3.1", "jsonwebtoken": "^9.0.3", - "next": "16.1.6", + "next": "16.2.1", "pg": "^8.20.0", "prisma": "^7.5.0", "react": "19.2.3", @@ -29,6 +29,9 @@ "eslint-config-next": "16.1.6", "tailwindcss": "^4", "typescript": "^5" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@alloc/quick-lru": { @@ -1128,9 +1131,9 @@ } }, "node_modules/@next/env": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", - "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.1.tgz", + "integrity": "sha512-n8P/HCkIWW+gVal2Z8XqXJ6aB3J0tuM29OcHpCsobWlChH/SITBs1DFBk/HajgrwDkqqBXPbuUuzgDvUekREPg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1144,9 +1147,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", - "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz", + "integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==", "cpu": [ "arm64" ], @@ -1160,9 +1163,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", - "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz", + "integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==", "cpu": [ "x64" ], @@ -1176,9 +1179,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", - "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz", + "integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==", "cpu": [ "arm64" ], @@ -1192,9 +1195,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", - "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz", + "integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==", "cpu": [ "arm64" ], @@ -1208,9 +1211,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", - "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz", + "integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==", "cpu": [ "x64" ], @@ -1224,9 +1227,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", - "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz", + "integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==", "cpu": [ "x64" ], @@ -1240,9 +1243,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", - "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz", + "integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==", "cpu": [ "arm64" ], @@ -1256,9 +1259,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", - "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz", + "integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==", "cpu": [ "x64" ], @@ -1742,6 +1745,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", @@ -5751,14 +5818,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", - "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.1.tgz", + "integrity": "sha512-VaChzNL7o9rbfdt60HUj8tev4m6d7iC1igAy157526+cJlXOQu5LzsBXNT+xaJnTP/k+utSX5vMv7m0G+zKH+Q==", "license": "MIT", "dependencies": { - "@next/env": "16.1.6", + "@next/env": "16.2.1", "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", + "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -5770,15 +5837,15 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.6", - "@next/swc-darwin-x64": "16.1.6", - "@next/swc-linux-arm64-gnu": "16.1.6", - "@next/swc-linux-arm64-musl": "16.1.6", - "@next/swc-linux-x64-gnu": "16.1.6", - "@next/swc-linux-x64-musl": "16.1.6", - "@next/swc-win32-arm64-msvc": "16.1.6", - "@next/swc-win32-x64-msvc": "16.1.6", - "sharp": "^0.34.4" + "@next/swc-darwin-arm64": "16.2.1", + "@next/swc-darwin-x64": "16.2.1", + "@next/swc-linux-arm64-gnu": "16.2.1", + "@next/swc-linux-arm64-musl": "16.2.1", + "@next/swc-linux-x64-gnu": "16.2.1", + "@next/swc-linux-x64-musl": "16.2.1", + "@next/swc-win32-arm64-msvc": "16.2.1", + "@next/swc-win32-x64-msvc": "16.2.1", + "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/package.json b/package.json index cb57d9d..7bcd370 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@prisma/client": "^7.5.0", "dotenv": "^17.3.1", "jsonwebtoken": "^9.0.3", - "next": "16.1.6", + "next": "16.2.1", "pg": "^8.20.0", "prisma": "^7.5.0", "react": "19.2.3",