diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0809e71 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +.next +.git +.github +.claude +.vscode +.env*.local +data/config.json +data/history.json +output +*.md +!README.md +.DS_Store +nul +npm-debug.log* diff --git a/.env.local.example b/.env.local.example index 5e11022..be442f5 100644 --- a/.env.local.example +++ b/.env.local.example @@ -4,6 +4,11 @@ # Your deAPI API token (get it from https://deapi.ai) DEAPI_API_TOKEN=your_token_here +# Site URL for metadata (used for OG and Twitter images) +# Optional: defaults to http://localhost:3000 +# Set this if deploying to production (e.g., https://your-domain.com) +# NEXT_PUBLIC_SITE_URL=https://your-domain.com + # API URL (default: https://api.deapi.ai/api/v1/client) DEAPI_API_URL=https://api.deapi.ai/api/v1/client diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..eb2aa5e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing to deAPI Tester + +Thanks for your interest in contributing! + +## Development Setup + +```bash +git clone https://github.com/deapi-ai/deapi-tester.git +cd deapi-tester +npm install +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000). + +## Code Style + +- TypeScript strict mode — no `any` +- PascalCase for components, camelCase for functions/variables +- Use `@/` alias for imports +- Tailwind classes for styling (CSS variables for theme-aware colors) +- One component per file, keep under ~300 lines + +## Submitting Changes + +1. Create a branch: `git checkout -b feature/my-feature` +2. Make changes and test locally +3. Run `npm run lint` to check for issues +4. Commit with a clear message +5. Push and open a Pull Request + +## Adding Endpoints + +See the [Adding New Endpoints](../README.md#adding-new-endpoints) section in the README. Only `src/lib/endpoint-registry.ts` needs editing — form UI is generated automatically. + +## Reporting Bugs + +Use [GitHub Issues](https://github.com/deapi-ai/deapi-tester/issues) and include: +- Description of the bug +- Steps to reproduce +- Expected vs actual behavior +- Screenshots if applicable diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..875e06f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug Report +about: Report a bug to help us improve +title: '[Bug] ' +labels: bug +--- + +## Description + +A clear description of the bug. + +## Steps to Reproduce + +1. Go to '...' +2. Click on '...' +3. See error + +## Expected Behavior + +What you expected to happen. + +## Actual Behavior + +What actually happened. + +## Environment + +- OS: [e.g. Windows 11, macOS 14] +- Node.js: [e.g. 20.10] +- Browser: [e.g. Chrome 120] +- Docker: [yes/no] + +## Screenshots + +If applicable, add screenshots. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..30e5195 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: Suggest a new feature +title: '[Feature] ' +labels: enhancement +--- + +## Description + +A clear description of the feature you'd like. + +## Use Case + +Why is this feature useful? What problem does it solve? + +## Proposed Solution + +How would you like it to work? diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..c42c4d6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +## Description + +Brief description of changes. + +## Type of Change + +- [ ] Bug fix +- [ ] New feature +- [ ] Documentation +- [ ] Refactoring + +## Testing + +How was this tested? + +## Checklist + +- [ ] Code follows project style guidelines +- [ ] No debug code left in +- [ ] Tested locally +- [ ] Updated README if needed diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..90d033d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint-and-build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: ['18.18.x', '20.x'] + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - run: npm ci + + - run: npm run lint + + - run: npm run build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..893cf41 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 deAPI.ai + +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 de1bf77..003737b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ # deAPI Tester -A local developer tool for testing [deAPI.ai](https://deapi.ai) endpoints - unified AI inference API for image generation, video creation, audio synthesis, and more. +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Node.js 18.18.0+](https://img.shields.io/badge/Node.js-18.18.0%2B-green.svg)](https://nodejs.org/) +[![Next.js 15](https://img.shields.io/badge/Next.js-15-black.svg)](https://nextjs.org/) +[![Docker](https://img.shields.io/badge/Docker-ready-blue.svg)](https://www.docker.com/) + +A local developer tool for testing [deAPI.ai](https://deapi.ai) endpoints — unified AI inference API for image generation, video creation, audio synthesis, and more. + +> **What is deAPI?** A single API to access multiple AI models (Stable Diffusion, Flux, Kling, Minimax, etc.) for image generation, video creation, text-to-speech, transcription and more. Learn more at [deapi.ai](https://deapi.ai). + +## Screenshot + +![deAPI Tester — Dark Mode](docs/screenshot-dark.png) ## Features @@ -38,8 +49,8 @@ A local developer tool for testing [deAPI.ai](https://deapi.ai) endpoints - unif ```bash # Clone the repository -git clone https://github.com/deapi-ai/deapi-develop-tester.git -cd deapi-develop-tester +git clone https://github.com/deapi-ai/deapi-tester.git +cd deapi-tester ``` ### Docker (recommended) @@ -204,11 +215,22 @@ The form is automatically generated. Model options, limits, and defaults are loa - Adding a new model to deAPI requires **zero code changes** — it auto-appears in the UI - Configuration and history are stored in local JSON files +## Contributing + +Contributions are welcome! Please read the [Contributing Guide](.github/CONTRIBUTING.md) before submitting a PR. + +1. Fork the repository +2. Create your branch: `git checkout -b feature/my-feature` +3. Commit your changes +4. Push and open a Pull Request + ## License -MIT +[MIT](LICENSE) -## Links +## deAPI Ecosystem -- [deAPI.ai](https://deapi.ai) - AI inference API -- [deAPI Documentation](https://docs.deapi.ai) - API documentation +- [deAPI.ai](https://deapi.ai) — Unified AI inference API +- [API Documentation](https://docs.deapi.ai) — Full endpoint reference, auth, webhooks, WebSockets +- [Claude Code Skills](https://github.com/deapi-ai/claude-code-skills) — Use deAPI directly from Claude Code terminal (generate images, videos, audio, transcribe and more) +- [Report a Bug](https://github.com/deapi-ai/deapi-tester/issues) diff --git a/docs/screenshot-dark.png b/docs/screenshot-dark.png new file mode 100644 index 0000000..c905a09 Binary files /dev/null and b/docs/screenshot-dark.png differ diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..954a3ef --- /dev/null +++ b/llms.txt @@ -0,0 +1,71 @@ +# deAPI — Unified AI Inference API + +> One API to access all AI models. Image generation, video creation, text-to-speech, transcription, OCR, embeddings and more. + +## What is deAPI? + +deAPI.ai is a unified AI inference API that gives developers access to multiple AI models through a single endpoint. Instead of integrating separately with Stability AI, Replicate, ElevenLabs, OpenAI and others, developers use one API — deAPI — to access all of them. + +deAPI runs on a decentralized GPU network, offering cost-effective AI inference compared to traditional cloud providers. + +Website: https://deapi.ai +API documentation: https://docs.deapi.ai +Full API reference for LLMs: https://docs.deapi.ai/llms-full.txt + +## Supported Capabilities + +- **Image Generation** — Text-to-image (txt2img) and image-to-image (img2img) with models like Flux, Stable Diffusion, and more +- **Video Generation** — Text-to-video (txt2video) and image-to-video (img2video) with models like Kling, Minimax, and more +- **Text-to-Speech** — High-quality speech synthesis with multiple voices and languages +- **Transcription** — Audio, video, YouTube, Twitch, X Spaces, and Kick stream transcription +- **OCR** — Optical character recognition from images +- **Image Utilities** — Upscale, remove background, style transfer +- **Embeddings** — Text-to-embedding generation +- **Prompt Enhancement** — AI-powered prompt optimization for image, video, and speech + +New models and capabilities are added continuously — no client-side code changes needed. + +## How the API Works + +All endpoints are asynchronous. A request returns a `request_id`, and results can be retrieved via: +1. **Webhooks** (recommended) — Automatic delivery with retries +2. **WebSockets** — Real-time updates with live previews +3. **Polling** — Manual status checks via `/request-status` + +Base URL: `https://api.deapi.ai` +Authentication: Bearer token in Authorization header. + +## Pricing + +Pay-per-use model. New accounts receive $5 free credit. Each endpoint has a price calculator to estimate costs before sending requests. Full pricing details at https://docs.deapi.ai. + +## Integrations + +- **MCP Server** — Use deAPI from AI assistants and IDEs (Claude, Cursor, etc.) +- **Claude Code Skills** — Generate images, videos, audio, transcribe and more directly from terminal: https://github.com/deapi-ai/claude-code-skills +- **n8n Integration** — Workflow automation with deAPI nodes +- **deAPI Tester** — Open-source web UI for testing all endpoints with dynamic forms, job tracking and result preview: https://github.com/deapi-ai/deapi-tester + +## Available Models + +Models are auto-discovered via the `/models` API endpoint. Current categories include: +- Image generation: Flux (Schnell, Dev, Pro), Stable Diffusion, and more +- Video generation: Kling, Minimax, and more +- TTS: Multiple providers with various voices and languages +- Transcription: Whisper-based models +- OCR, upscaling, background removal, embeddings + +The model list grows as new providers are onboarded — no API changes required. + +## Links + +- Website: https://deapi.ai +- API Documentation: https://docs.deapi.ai +- API Reference (LLM-readable): https://docs.deapi.ai/llms-full.txt +- Claude Code Skills: https://github.com/deapi-ai/claude-code-skills +- deAPI Tester (this repo): https://github.com/deapi-ai/deapi-tester +- Support: https://docs.deapi.ai (FAQ & contact) + +## License + +This repository (deAPI Tester) is MIT licensed. diff --git a/package-lock.json b/package-lock.json index 70e6958..5163ff2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "deapi-tester", "version": "0.1.0", + "license": "MIT", "dependencies": { "lucide-react": "^0.563.0", "next": "^15.5.12", @@ -19,7 +20,7 @@ "@types/react-dom": "^19.2.3", "autoprefixer": "^10.4.17", "eslint": "^8.56.0", - "eslint-config-next": "^14.2.0", + "eslint-config-next": "^15.5.12", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "^5.3.3" @@ -638,53 +639,6 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -744,13 +698,43 @@ "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "14.2.35", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.35.tgz", - "integrity": "sha512-Jw9A3ICz2183qSsqwi7fgq4SBPiNfmOLmTPXKvlnzstUwyvBrtySiY+8RXJweNAs9KThb1+bYhZh9XWcNOr2zQ==", + "version": "15.5.12", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.12.tgz", + "integrity": "sha512-+ZRSDFTv4aC96aMb5E41rMjysx8ApkryevnvEYZvPZO52KvkqP5rNExLUXJFr9P4s0f3oqNQR6vopCZsPWKDcQ==", "dev": true, "license": "MIT", "dependencies": { - "glob": "10.3.10" + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/@next/swc-darwin-arm64": { @@ -929,17 +913,6 @@ "node": ">=12.4.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -997,6 +970,7 @@ "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1056,6 +1030,7 @@ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", @@ -1562,6 +1537,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1991,6 +1967,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2402,13 +2379,6 @@ "node": ">= 0.4" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", @@ -2630,6 +2600,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2681,25 +2652,25 @@ } }, "node_modules/eslint-config-next": { - "version": "14.2.35", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.35.tgz", - "integrity": "sha512-BpLsv01UisH193WyT/1lpHqq5iJ/Orfz9h/NOOlAmTUq4GY349PextQ62K4XpnaM9supeiEn3TaOTeQO07gURg==", + "version": "15.5.12", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.12.tgz", + "integrity": "sha512-ktW3XLfd+ztEltY5scJNjxjHwtKWk6vU2iwzZqSN09UsbBmMeE/cVlJ1yESg6Yx5LW7p/Z8WzUAgYXGLEmGIpg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "14.2.35", - "@rushstack/eslint-patch": "^1.3.3", + "@next/eslint-plugin-next": "15.5.12", + "@rushstack/eslint-patch": "^1.10.3", "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^5.0.0" }, "peerDependencies": { - "eslint": "^7.23.0 || ^8.0.0", + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", "typescript": ">=3.3.1" }, "peerDependenciesMeta": { @@ -2924,16 +2895,16 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.0.0-canary-7118f5dd7-20230705", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0-canary-7118f5dd7-20230705.tgz", - "integrity": "sha512-AZYbMo/NW9chdL7vk6HQzQhT+PvTAEVqWk9ziruUoW2kAOcN5qNyelv70e0F1VNQAbvutOC9oc+xfWycI9FxDw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", "dev": true, "license": "MIT", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "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/doctrine": { @@ -3213,23 +3184,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fraction.js": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", @@ -3387,29 +3341,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3423,32 +3354,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -3851,16 +3756,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-function": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", @@ -4134,31 +4029,13 @@ "node": ">= 0.4" } }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jiti": { "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4333,13 +4210,6 @@ "loose-envify": "cli.js" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/lucide-react": { "version": "0.563.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz", @@ -4406,16 +4276,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4834,23 +4694,6 @@ "dev": true, "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4920,6 +4763,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5121,6 +4965,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5130,6 +4975,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -5593,19 +5439,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5636,76 +5469,6 @@ "node": ">= 0.4" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -5832,20 +5595,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -6050,6 +5799,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -6219,6 +5969,7 @@ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6451,107 +6202,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 69b21d7..ffc85f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,34 @@ { "name": "deapi-tester", "version": "0.1.0", + "description": "Local developer testing app for deAPI.ai — unified AI inference API for image generation, video creation, audio synthesis and more", + "author": { + "name": "deAPI", + "url": "https://deapi.ai" + }, + "license": "MIT", + "engines": { + "node": ">=18.18.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/deapi-ai/deapi-tester.git" + }, + "homepage": "https://github.com/deapi-ai/deapi-tester", + "bugs": { + "url": "https://github.com/deapi-ai/deapi-tester/issues" + }, + "keywords": [ + "deapi", + "ai", + "inference", + "api-tester", + "image-generation", + "video-generation", + "text-to-speech", + "developer-tool", + "nextjs" + ], "private": true, "scripts": { "dev": "next dev", @@ -20,7 +48,7 @@ "@types/react-dom": "^19.2.3", "autoprefixer": "^10.4.17", "eslint": "^8.56.0", - "eslint-config-next": "^14.2.0", + "eslint-config-next": "^15.5.12", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "^5.3.3" diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..05bf2e8 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..a0fd462 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/og-image.png b/public/og-image.png new file mode 100644 index 0000000..c905a09 Binary files /dev/null and b/public/og-image.png differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ba2084b..ae2575e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,9 +2,70 @@ import type { Metadata } from 'next'; import './globals.css'; import { Providers } from '@/components/Providers'; +function getMetadataBaseUrl(): string { + const fallback = 'http://localhost:3000'; + const rawSiteUrl = process.env.NEXT_PUBLIC_SITE_URL; + + if (!rawSiteUrl) { + return fallback; + } + + let normalized = rawSiteUrl.trim(); + + // Ensure URL has a protocol; default to https, or http for localhost/127.0.0.1 + if (!/^https?:\/\//i.test(normalized)) { + const isLocalHostLike = /^localhost(:\d+)?$/i.test(normalized) || /^127\.0\.0\.1(:\d+)?$/i.test(normalized); + const protocol = isLocalHostLike ? 'http://' : 'https://'; + normalized = protocol + normalized; + } + + try { + // Validate that the resulting string is a proper URL + // eslint-disable-next-line no-new + new URL(normalized); + return normalized; + } catch { + console.warn( + `Invalid NEXT_PUBLIC_SITE_URL ('${rawSiteUrl}'). Falling back to ${fallback}` + ); + return fallback; + } +} + export const metadata: Metadata = { - title: 'deAPI Tester', - description: 'Local developer testing app for deAPI.ai endpoints', + metadataBase: new URL(getMetadataBaseUrl()), + title: 'deAPI Tester — Test AI Inference Endpoints', + description: + 'Local developer tool for testing deAPI.ai endpoints. Generate images, videos, audio and more with dynamic forms, async job tracking, and result preview.', + keywords: [ + 'deapi', + 'ai inference', + 'api tester', + 'image generation', + 'video generation', + 'text to speech', + 'developer tool', + ], + authors: [{ name: 'deAPI', url: 'https://deapi.ai' }], + openGraph: { + title: 'deAPI Tester — Test AI Inference Endpoints', + description: + 'Test deAPI.ai endpoints locally with dynamic forms, async job tracking, price calculator and result preview.', + type: 'website', + siteName: 'deAPI Tester', + images: ['/og-image.png'], + }, + twitter: { + card: 'summary_large_image', + title: 'deAPI Tester — Test AI Inference Endpoints', + description: + 'Test deAPI.ai endpoints locally with dynamic forms, async job tracking, price calculator and result preview.', + images: ['/og-image.png'], + }, + icons: { + icon: '/favicon.ico', + apple: '/apple-touch-icon.png', + }, }; export default function RootLayout({