diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 42e7d82..5b9704e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -76,6 +76,36 @@ jobs: VERSION=$(node -p "require('./package.json').version") echo "version=$VERSION" >> "$GITHUB_OUTPUT" + - name: Update docs version + run: | + VERSION=${{ steps.get_version.outputs.version }} + export VERSION + node - <<'EOF' +const fs = require('fs'); +const version = process.env.VERSION; + +// update backend api JSON docs +const jsonPath = 'backend/docs/api-documentation.json'; +if (fs.existsSync(jsonPath)) { + const doc = JSON.parse(fs.readFileSync(jsonPath, 'utf8')); + doc.info = doc.info || {}; + doc.info.version = version; + fs.writeFileSync(jsonPath, JSON.stringify(doc, null, 2)); +} + +// update any README files with Version: lines +const updateReadme = (p) => { + if (fs.existsSync(p)) { + let c = fs.readFileSync(p, 'utf8'); + c = c.replace(/\*\*Version:\*\* .*/, `**Version:** ${version}`); + fs.writeFileSync(p, c); + } +}; +updateReadme('backend/docs/README.md'); +updateReadme('README.md'); +updateReadme('frontend/README.md'); +EOF + - name: Commit version changes id: commit_versions run: | @@ -83,6 +113,10 @@ jobs: if [ -f package.json ]; then FILES="$FILES package.json"; fi if [ -f frontend/package.json ]; then FILES="$FILES frontend/package.json"; fi if [ -f backend/package.json ]; then FILES="$FILES backend/package.json"; fi + if [ -f backend/docs/api-documentation.json ]; then FILES="$FILES backend/docs/api-documentation.json"; fi + if [ -f backend/docs/README.md ]; then FILES="$FILES backend/docs/README.md"; fi + if [ -f README.md ]; then FILES="$FILES README.md"; fi + if [ -f frontend/README.md ]; then FILES="$FILES frontend/README.md"; fi if [ -n "$FILES" ]; then git add $FILES; fi if git diff --cached --quiet; then @@ -90,7 +124,7 @@ jobs: exit 0 fi - git commit -m "chore: bump versions for ${{ github.event.inputs.release_type }} release" + git commit -m "chore: bump versions for ${{ github.event.inputs.release_type }} v${{ steps.get_version.outputs.version }} release" # Check if tag already exists TAG_NAME="v${{ steps.get_version.outputs.version }}" did_commit=false diff --git a/README.md b/README.md index f0ec23b..85c0c6d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # 🛠️ dkutils — The Ultimate Multi-Utility Platform +**Version:** 2.0.1 + ![dkutils Logo](frontend/public/logo.png) [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC) diff --git a/backend/docs/README.md b/backend/docs/README.md index 1cad89d..dd53746 100644 --- a/backend/docs/README.md +++ b/backend/docs/README.md @@ -2,8 +2,8 @@ Auto-generated API documentation for Express.js application -**Version:** 1.3.2 -**Generated:** 2/1/2026, 11:57:39 PM +**Version:** 2.0.1 +**Generated:** 2/28/2026, 5:53:03 PM Generated By: create-express-doc ## API Endpoints @@ -45,9 +45,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/analytics/stats` @@ -65,17 +62,25 @@ Generated By: create-express-doc "msg": "Invalid category" } - - ``` - ``` - **200** - Success - Content-Type: `application/json` - Schema: - ```json - "{stats}" + ```json + { + + "data": "{stats}", + "pagination": { + "currentPage": "{pageNum}", + "limit": "{limitNum}", + "total": "{total}", + "totalPages": "unknown", + "hasNext": "unknown", + "hasPrev": "unknown" + } + } ``` - **500** - Internal Server Error @@ -87,15 +92,14 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/analytics/track` #### POST /api/analytics/track +**Middleware:** trackLimiter + **Responses:** - **400** - Bad Request @@ -107,9 +111,6 @@ Generated By: create-express-doc "msg": "Tool name and category are required." } - - ``` - ``` - **400** - Bad Request @@ -121,9 +122,6 @@ Generated By: create-express-doc "msg": "Invalid category" } - - ``` - ``` - **200** - Success @@ -136,23 +134,67 @@ Generated By: create-express-doc "success": "boolean", "usageCount": "unknown" } + ``` + +- **500** - Internal Server Error + - Content-Type: `application/json` + - Schema: + + ```json + { + "msg": "Server Error" + } ``` +### `/api/auth/forgot-password` + +#### POST /api/auth/forgot-password + +**Responses:** + +- **400** - Bad Request + - Content-Type: `application/json` + - Schema: + + ```json + { + + "errors": "unknown" + } ``` -- **500** - Internal Server Error +- **200** - Success - Content-Type: `application/json` - Schema: ```json { - "msg": "Server Error" + "msg": "If an account with that email exists, a password reset link has been sent." } + ``` + +- **200** - Success + - Content-Type: `application/json` + - Schema: + + ```json + { + "msg": "If an account with that email exists, a password reset link has been sent." + } ``` +- **500** - Internal Server Error + - Content-Type: `application/json` + - Schema: + + ```json + { + + "msg": "Server error" + } ``` ### `/api/auth/login` @@ -170,9 +212,6 @@ Generated By: create-express-doc "errors": "unknown" } - - ``` - ``` - **400** - Bad Request @@ -184,9 +223,6 @@ Generated By: create-express-doc "msg": "Invalid Credentials" } - - ``` - ``` - **400** - Bad Request @@ -198,9 +234,6 @@ Generated By: create-express-doc "msg": "Invalid Credentials" } - - ``` - ``` - **200** - Success @@ -212,9 +245,6 @@ Generated By: create-express-doc "token": "{token}" } - - ``` - ``` - **500** - Internal Server Error @@ -226,9 +256,6 @@ Generated By: create-express-doc "msg": "Server error" } - - ``` - ``` ### `/api/auth/register` @@ -246,9 +273,6 @@ Generated By: create-express-doc "errors": "unknown" } - - ``` - ``` - **400** - Bad Request @@ -258,11 +282,19 @@ Generated By: create-express-doc ```json { - "msg": "User already exists" + "msg": "User with this email already exists" } - ``` +- **400** - Bad Request + - Content-Type: `application/json` + - Schema: + + ```json + { + + "msg": "Username already taken" + } ``` - **200** - Success @@ -274,9 +306,6 @@ Generated By: create-express-doc "token": "{token}" } - - ``` - ``` - **500** - Internal Server Error @@ -288,9 +317,6 @@ Generated By: create-express-doc "msg": "Server error" } - - ``` - ``` ### `/api/clean-supabase` @@ -308,9 +334,6 @@ Generated By: create-express-doc "msg": "Supabase cleanup triggered successfully." } - - ``` - ``` - **500** - Internal Server Error @@ -323,9 +346,6 @@ Generated By: create-express-doc "msg": "Failed to trigger Supabase cleanup.", "error": "unknown" } - - ``` - ``` ### `/api/clean-supabase/trigger` @@ -343,9 +363,6 @@ Generated By: create-express-doc "msg": "Supabase cleanup triggered successfully." } - - ``` - ``` - **500** - Internal Server Error @@ -358,9 +375,6 @@ Generated By: create-express-doc "msg": "Failed to trigger Supabase cleanup.", "error": "unknown" } - - ``` - ``` ### `/api/convert/base64-image` @@ -378,9 +392,6 @@ Generated By: create-express-doc "msg": "No image file uploaded for encoding." } - - ``` - ``` - **200** - Success @@ -392,9 +403,6 @@ Generated By: create-express-doc "base64": "{base64}" } - - ``` - ``` - **400** - Bad Request @@ -406,9 +414,6 @@ Generated By: create-express-doc "msg": "No base64 string provided for decoding." } - - ``` - ``` - **200** - Success @@ -418,12 +423,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } - - ``` - ``` - **400** - Bad Request @@ -435,9 +437,6 @@ Generated By: create-express-doc "msg": "Invalid request type. Must be \"encode\" or \"decode\"." } - - ``` - ``` - **500** - Internal Server Error @@ -449,9 +448,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/base64-text` @@ -469,9 +465,6 @@ Generated By: create-express-doc "msg": "Text and type (encode/decode) are required." } - - ``` - ``` - **400** - Bad Request @@ -483,9 +476,6 @@ Generated By: create-express-doc "msg": "Invalid type. Must be 'encode' or 'decode'." } - - ``` - ``` - **200** - Success @@ -497,9 +487,6 @@ Generated By: create-express-doc "result": "{result}" } - - ``` - ``` - **500** - Internal Server Error @@ -511,9 +498,6 @@ Generated By: create-express-doc "msg": "Server error during Base64 conversion." } - - ``` - ``` ### `/api/convert/compress-image` @@ -531,9 +515,6 @@ Generated By: create-express-doc "msg": "No image files uploaded for compression." } - - ``` - ``` - **400** - Bad Request @@ -545,9 +526,18 @@ Generated By: create-express-doc "msg": "Invalid quality provided. Must be a number between 0 and 100." } - ``` +- **200** - Success + - Content-Type: `application/json` + - Schema: + + ```json + { + + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } ``` - **200** - Success @@ -557,12 +547,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -574,9 +561,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/compress-pdf` @@ -585,21 +569,20 @@ Generated By: create-express-doc **Responses:** -- **200** - Success +- **200** - OK - Content-Type: `application/json` - Schema: ```json { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", - "message": "PDF compressed successfully!" + "message": "unknown", + "compressionRatio": "{compressionRatio}", + "compressionLevel": "{compressionLevel}" } - - ``` - ``` ### `/api/convert/convert-image-format` @@ -617,9 +600,6 @@ Generated By: create-express-doc "msg": "No image files uploaded." } - - ``` - ``` - **400** - Bad Request @@ -631,9 +611,18 @@ Generated By: create-express-doc "msg": "unknown" } - ``` +- **200** - Success + - Content-Type: `application/json` + - Schema: + + ```json + { + + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } ``` - **200** - Success @@ -643,12 +632,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -660,23 +646,42 @@ Generated By: create-express-doc "msg": "Server Error" } - ``` +### `/api/convert/download` + +#### GET /api/convert/download + +**Responses:** + +- **400** - Bad Request + - Content-Type: `application/json` + - Schema: + + ```json + { + + "msg": "Filename is required." + } ``` -### `/api/convert/download-image/:filename` +- **403** - Forbidden + - Content-Type: `application/json` + - Schema: -#### GET /api/convert/download-image/:filename + ```json + { -**Responses:** + "msg": "Invalid filename." + } + ``` - **200** - Success - Content-Type: `text/html` - Schema: ```json - "{data}" + "{buffer}" ``` - **500** - Internal Server Error @@ -688,9 +693,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/image-flip` @@ -708,9 +710,6 @@ Generated By: create-express-doc "msg": "No image file uploaded." } - - ``` - ``` - **400** - Bad Request @@ -722,9 +721,6 @@ Generated By: create-express-doc "msg": "Invalid flip direction. Must be 'horizontal' or 'vertical'." } - - ``` - ``` - **200** - Success @@ -734,12 +730,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -751,9 +744,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/image-grayscale` @@ -771,9 +761,6 @@ Generated By: create-express-doc "msg": "No image file uploaded." } - - ``` - ``` - **200** - Success @@ -783,12 +770,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -800,9 +784,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/image-to-base64` @@ -820,9 +801,6 @@ Generated By: create-express-doc "msg": "No image file uploaded." } - - ``` - ``` - **200** - Success @@ -834,9 +812,6 @@ Generated By: create-express-doc "base64": "{base64}" } - - ``` - ``` - **500** - Internal Server Error @@ -848,9 +823,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/image-to-pdf` @@ -868,9 +840,6 @@ Generated By: create-express-doc "msg": "No image files uploaded." } - - ``` - ``` - **200** - Success @@ -880,12 +849,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -897,9 +863,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/json-to-xml` @@ -917,9 +880,6 @@ Generated By: create-express-doc "msg": "JSON string is required." } - - ``` - ``` - **200** - OK @@ -931,9 +891,6 @@ Generated By: create-express-doc "xmlString": "{xmlString}" } - - ``` - ``` - **400** - Bad Request @@ -946,9 +903,6 @@ Generated By: create-express-doc "msg": "Invalid JSON format or conversion error.", "error": "unknown" } - - ``` - ``` ### `/api/convert/merge-pdfs` @@ -966,9 +920,6 @@ Generated By: create-express-doc "msg": "No files uploaded. Please select at least one PDF file." } - - ``` - ``` - **400** - Bad Request @@ -980,9 +931,6 @@ Generated By: create-express-doc "msg": "Please upload at least 2 PDF files to merge." } - - ``` - ``` - **200** - Success @@ -992,14 +940,11 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDFs merged successfully!" } - - ``` - ``` ### `/api/convert/pdf-rotate` @@ -1017,9 +962,6 @@ Generated By: create-express-doc "msg": "Invalid rotation angle. Must be 90, 180, or 270." } - - ``` - ``` - **200** - Success @@ -1029,14 +971,11 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDF rotated successfully!" } - - ``` - ``` ### `/api/convert/pdf-to-excel` @@ -1054,9 +993,6 @@ Generated By: create-express-doc "msg": "No PDF file uploaded." } - - ``` - ``` - **200** - Success @@ -1066,12 +1002,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{fileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -1083,9 +1016,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/pdf-to-text` @@ -1125,9 +1055,6 @@ Generated By: create-express-doc "msg": "No PDF file uploaded." } - - ``` - ``` - **200** - Success @@ -1137,12 +1064,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{fileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -1154,9 +1078,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/png-to-jpg` @@ -1174,9 +1095,18 @@ Generated By: create-express-doc "msg": "No image files uploaded." } - ``` +- **200** - Success + - Content-Type: `application/json` + - Schema: + + ```json + { + + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } ``` - **200** - Success @@ -1186,12 +1116,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -1203,9 +1130,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/resize-image` @@ -1223,9 +1147,6 @@ Generated By: create-express-doc "msg": "No image files uploaded." } - - ``` - ``` - **400** - Bad Request @@ -1237,9 +1158,18 @@ Generated By: create-express-doc "msg": "Invalid width or height provided. Must be positive numbers." } - ``` +- **200** - Success + - Content-Type: `application/json` + - Schema: + + ```json + { + + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } ``` - **200** - Success @@ -1249,12 +1179,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -1266,9 +1193,6 @@ Generated By: create-express-doc "msg": "Server Error" } - - ``` - ``` ### `/api/convert/split-pdf` @@ -1286,9 +1210,6 @@ Generated By: create-express-doc "msg": "No page ranges provided." } - - ``` - ``` - **200** - Success @@ -1298,14 +1219,11 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDF split successfully!" } - - ``` - ``` ### `/api/convert/text-to-pdf` @@ -1323,9 +1241,6 @@ Generated By: create-express-doc "msg": "Text is required and must be a non-empty string" } - - ``` - ``` - **200** - Success @@ -1333,7 +1248,7 @@ Generated By: create-express-doc - Schema: ```json - "{archiveBuffer}" + "{pdfBuffer}" ``` - **500** - Internal Server Error @@ -1359,9 +1274,6 @@ Generated By: create-express-doc "msg": "XML string is required." } - - ``` - ``` - **200** - OK @@ -1373,9 +1285,6 @@ Generated By: create-express-doc "jsonString": "unknown" } - - ``` - ``` - **400** - Bad Request @@ -1388,9 +1297,6 @@ Generated By: create-express-doc "msg": "Invalid XML format or conversion error.", "error": "unknown" } - - ``` - ``` ### `/api/favicon` @@ -1408,9 +1314,30 @@ Generated By: create-express-doc "msg": "URL is required" } + ``` + +- **500** - Internal Server Error + - Content-Type: `application/json` + - Schema: + + ```json + { + "msg": "Failed to upload favicon to Supabase", + "error": "unknown" + } ``` +- **200** - OK + - Content-Type: `application/json` + - Schema: + + ```json + { + + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } ``` - **500** - Internal Server Error @@ -1423,9 +1350,6 @@ Generated By: create-express-doc "msg": "Failed to upload favicon ZIP to Supabase", "error": "unknown" } - - ``` - ``` - **200** - OK @@ -1435,12 +1359,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } - - ``` - ``` - **500** - Internal Server Error @@ -1453,9 +1374,6 @@ Generated By: create-express-doc "msg": "Failed to extract favicons. Please check the URL.", "error": "unknown" } - - ``` - ``` ### `/api/keep-alive` @@ -1474,9 +1392,6 @@ Generated By: create-express-doc "msg": "Failed to upload file to Supabase", "error": "unknown" } - - ``` - ``` - **200** - OK @@ -1489,9 +1404,6 @@ Generated By: create-express-doc "msg": "Keep-alive file uploaded successfully", "path": "unknown" } - - ``` - ``` - **500** - Internal Server Error @@ -1503,9 +1415,35 @@ Generated By: create-express-doc "msg": "Server Error" } + ``` + +### `/api/password-strength` +#### POST /api/password-strength + +**Responses:** + +- **400** - Bad Request + - Content-Type: `application/json` + - Schema: + + ```json + { + + "msg": "Password is required." + } ``` +- **200** - OK + - Content-Type: `application/json` + - Schema: + + ```json + { + + "score": "{score}", + "feedback": "{feedback}" + } ``` ### `/api/redirect-checker` @@ -1523,9 +1461,6 @@ Generated By: create-express-doc "msg": "URL is required" } - - ``` - ``` - **200** - OK @@ -1537,9 +1472,6 @@ Generated By: create-express-doc "chain": "{redirectChain}" } - - ``` - ``` - **500** - Internal Server Error @@ -1551,9 +1483,6 @@ Generated By: create-express-doc "msg": "{errorMessage}" } - - ``` - ``` ### `/api/screenshot` @@ -1571,9 +1500,6 @@ Generated By: create-express-doc "msg": "URL is required" } - - ``` - ``` - **500** - Internal Server Error @@ -1583,12 +1509,9 @@ Generated By: create-express-doc ```json { - "msg": "Failed to upload screenshot ZIP to Supabase", + "msg": "Failed to upload screenshot to Supabase", "error": "unknown" } - - ``` - ``` - **200** - OK @@ -1598,12 +1521,9 @@ Generated By: create-express-doc ```json { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } - - ``` - ``` - **408** - Unknown Status @@ -1616,9 +1536,6 @@ Generated By: create-express-doc "msg": "Request timeout. The screenshot API took too long to respond.", "error": "unknown" } - - ``` - ``` - **500** - Internal Server Error @@ -1631,9 +1548,6 @@ Generated By: create-express-doc "msg": "Failed to generate screenshot. Please check the URL and API key.", "error": "unknown" } - - ``` - ``` ### `/api/seo/robots-txt` @@ -1651,9 +1565,6 @@ Generated By: create-express-doc "msg": "Domain is required." } - - ``` - ``` - **400** - Bad Request @@ -1665,9 +1576,6 @@ Generated By: create-express-doc "msg": "unknown" } - - ``` - ``` - **200** - OK @@ -1693,9 +1601,6 @@ Generated By: create-express-doc "msg": "Domain is required." } - - ``` - ``` - **400** - Bad Request @@ -1707,9 +1612,6 @@ Generated By: create-express-doc "msg": "unknown" } - - ``` - ``` - **200** - OK @@ -1757,9 +1659,6 @@ Generated By: create-express-doc "msg": "Server error during URL redirection." } - - ``` - ``` ### `/shorten` @@ -1777,9 +1676,6 @@ Generated By: create-express-doc "msg": "Server configuration error: BASE_URL environment variable is not set." } - - ``` - ``` - **400** - Bad Request @@ -1791,9 +1687,6 @@ Generated By: create-express-doc "msg": "Please enter a valid URL." } - - ``` - ``` - **200** - Success @@ -1821,9 +1714,6 @@ Generated By: create-express-doc "msg": "Server error during URL shortening." } - - ``` - ``` --- diff --git a/backend/docs/api-documentation.json b/backend/docs/api-documentation.json index a4ea9e0..8e2998b 100644 --- a/backend/docs/api-documentation.json +++ b/backend/docs/api-documentation.json @@ -1,9 +1,9 @@ { "info": { "title": "API Documentation", - "version": "1.3.2", + "version": "2.0.1", "description": "Auto-generated API documentation for Express.js application", - "generatedAt": "2026-02-01T18:27:39.455Z" + "generatedAt": "2026-02-28T12:23:03.048Z" }, "paths": { "/shorten": { @@ -89,7 +89,16 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "path": "{downloadUrl}", "originalname": "{zipFileName}" } }, @@ -105,15 +114,31 @@ "middleware": [] } }, - "/api/convert/download-image/:filename": { + "/api/convert/download": { "get": { - "summary": "GET /api/convert/download-image/:filename", + "summary": "GET /api/convert/download", "responses": [ + { + "status": 400, + "description": "Bad Request", + "contentType": "application/json", + "schema": { + "msg": "Filename is required." + } + }, + { + "status": 403, + "description": "Forbidden", + "contentType": "application/json", + "schema": { + "msg": "Invalid filename." + } + }, { "status": 200, "description": "Success", "contentType": "text/html", - "schema": "{data}" + "schema": "{buffer}" }, { "status": 500, @@ -144,8 +169,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } }, { @@ -185,7 +210,16 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "path": "{downloadUrl}", "originalname": "{zipFileName}" } }, @@ -226,7 +260,16 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "path": "{downloadUrl}", "originalname": "{zipFileName}" } }, @@ -267,7 +310,16 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "path": "{downloadUrl}", "originalname": "{zipFileName}" } }, @@ -316,8 +368,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } }, { @@ -365,8 +417,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } }, { @@ -430,8 +482,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } }, { @@ -471,8 +523,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDFs merged successfully!" } @@ -498,8 +550,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDF split successfully!" } @@ -545,8 +597,8 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", "message": "PDF rotated successfully!" } @@ -561,13 +613,15 @@ "responses": [ { "status": 200, - "description": "Success", + "description": "OK", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}", + "path": "{downloadUrl}", + "originalname": "{outputFileName}", "success": "boolean", - "message": "PDF compressed successfully!" + "message": "unknown", + "compressionRatio": "{compressionRatio}", + "compressionLevel": "{compressionLevel}" } } ], @@ -590,7 +644,7 @@ "status": 200, "description": "Success", "contentType": "text/plain", - "schema": "{archiveBuffer}" + "schema": "{pdfBuffer}" }, { "status": 500, @@ -619,7 +673,7 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{fileName}" } }, @@ -652,7 +706,7 @@ "description": "Success", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{fileName}" } }, @@ -725,7 +779,15 @@ "description": "Bad Request", "contentType": "application/json", "schema": { - "msg": "User already exists" + "msg": "User with this email already exists" + } + }, + { + "status": 400, + "description": "Bad Request", + "contentType": "application/json", + "schema": { + "msg": "Username already taken" } }, { @@ -796,6 +858,46 @@ "middleware": [] } }, + "/api/auth/forgot-password": { + "post": { + "summary": "POST /api/auth/forgot-password", + "responses": [ + { + "status": 400, + "description": "Bad Request", + "contentType": "application/json", + "schema": { + "errors": "unknown" + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "msg": "If an account with that email exists, a password reset link has been sent." + } + }, + { + "status": 200, + "description": "Success", + "contentType": "application/json", + "schema": { + "msg": "If an account with that email exists, a password reset link has been sent." + } + }, + { + "status": 500, + "description": "Internal Server Error", + "contentType": "application/json", + "schema": { + "msg": "Server error" + } + } + ], + "middleware": [] + } + }, "/api/keep-alive": { "post": { "summary": "POST /api/keep-alive", @@ -897,7 +999,7 @@ "description": "Internal Server Error", "contentType": "application/json", "schema": { - "msg": "Failed to upload screenshot ZIP to Supabase", + "msg": "Failed to upload screenshot to Supabase", "error": "unknown" } }, @@ -906,8 +1008,8 @@ "description": "OK", "contentType": "application/json", "schema": { - "path": "unknown", - "originalname": "{zipFileName}" + "path": "{downloadUrl}", + "originalname": "{outputFileName}" } }, { @@ -944,6 +1046,24 @@ "msg": "URL is required" } }, + { + "status": 500, + "description": "Internal Server Error", + "contentType": "application/json", + "schema": { + "msg": "Failed to upload favicon to Supabase", + "error": "unknown" + } + }, + { + "status": 200, + "description": "OK", + "contentType": "application/json", + "schema": { + "path": "{downloadUrl}", + "originalname": "{outputFileName}" + } + }, { "status": 500, "description": "Internal Server Error", @@ -958,7 +1078,7 @@ "description": "OK", "contentType": "application/json", "schema": { - "path": "unknown", + "path": "{downloadUrl}", "originalname": "{zipFileName}" } }, @@ -1171,7 +1291,7 @@ } } ], - "middleware": [] + "middleware": ["trackLimiter"] } }, "/api/analytics/stats": { @@ -1190,7 +1310,17 @@ "status": 200, "description": "Success", "contentType": "application/json", - "schema": "{stats}" + "schema": { + "data": "{stats}", + "pagination": { + "currentPage": "{pageNum}", + "limit": "{limitNum}", + "total": "{total}", + "totalPages": "unknown", + "hasNext": "unknown", + "hasPrev": "unknown" + } + } }, { "status": 500, @@ -1226,6 +1356,31 @@ "middleware": [] } }, + "/api/password-strength": { + "post": { + "summary": "POST /api/password-strength", + "responses": [ + { + "status": 400, + "description": "Bad Request", + "contentType": "application/json", + "schema": { + "msg": "Password is required." + } + }, + { + "status": 200, + "description": "OK", + "contentType": "application/json", + "schema": { + "score": "{score}", + "feedback": "{feedback}" + } + } + ], + "middleware": [] + } + }, "/": { "get": { "summary": "GET /", @@ -1256,14 +1411,14 @@ } }, "stats": { - "totalEndpoints": 38, + "totalEndpoints": 40, "methodCounts": { - "POST": 31, + "POST": 33, "GET": 7 }, - "statusCodes": [200, 400, 404, 408, 500], - "pathsWithParams": 2, - "middlewareUsage": [] + "statusCodes": [200, 400, 403, 404, 408, 500], + "pathsWithParams": 1, + "middlewareUsage": ["trackLimiter"] }, "tags": { "shorten": { @@ -1281,7 +1436,7 @@ "description": "Routes under /api", "paths": [ "/api/convert/png-to-jpg", - "/api/convert/download-image/:filename", + "/api/convert/download", "/api/convert/image-to-pdf", "/api/convert/resize-image", "/api/convert/compress-image", @@ -1301,6 +1456,7 @@ "/api/convert/base64-text", "/api/auth/register", "/api/auth/login", + "/api/auth/forgot-password", "/api/keep-alive", "/api/clean-supabase", "/api/clean-supabase/trigger", @@ -1313,7 +1469,8 @@ "/api/seo/sitemap-xml", "/api/analytics/track", "/api/analytics/stats", - "/api/analytics/popular" + "/api/analytics/popular", + "/api/password-strength" ] }, "root": { diff --git a/frontend/README.md b/frontend/README.md index 3533f11..631324d 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,5 +1,7 @@ # Frontend for dkutils +**Version:** 2.0.1 + This directory contains the frontend application for dkutils, built with React and Vite. ## Technologies Used diff --git a/frontend/src/components/ImageCompressor.jsx b/frontend/src/components/ImageCompressor.jsx index b604f65..7a5b9af 100644 --- a/frontend/src/components/ImageCompressor.jsx +++ b/frontend/src/components/ImageCompressor.jsx @@ -59,13 +59,26 @@ const ImageCompressor = () => { setQuality(e.target.value); }; - const handleDownload = (fileUrl, fileName) => { - const link = document.createElement("a"); - link.href = fileUrl; - link.setAttribute("download", fileName); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); + // fetch the file as a blob and trigger download + const handleDownload = async (fileUrl, fileName) => { + try { + const downloadRes = await axios.get(fileUrl, { responseType: "blob" }); + const url = window.URL.createObjectURL(downloadRes.data); + + const link = document.createElement("a"); + link.href = url; + link.setAttribute("download", fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + // cleanup + window.URL.revokeObjectURL(url); + } catch (err) { + console.error("Error downloading file:", err); + toast.error("Failed to download compressed image. You can try again."); + throw err; + } }; const onSubmit = async (e) => { @@ -96,7 +109,8 @@ const ImageCompressor = () => { ); setConvertedZipFile(res.data); - handleDownload(res.data.path, res.data.originalname); + // trigger download and wait so we can show toast after it completes / errors + await handleDownload(res.data.path, res.data.originalname); toast.success("Images compressed successfully!"); setSelectedFiles([]); if (fileInputRef.current) {