A Deno-powered backend service for Plants vs. Zombies: MODDED. [Read-only GitHub mirror] docs.pvzm.net
express typescript expressjs plant deno jspvz pvzm game online backend plants-vs-zombies zombie javascript plants modded vs plantsvszombies openapi pvz noads
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix github action and shut up markdownlint

Clay 11a5ef88 af4bf4aa

+114 -114
+1 -1
.github/workflows/lint-format.yml
··· 44 44 git config user.name github-actions 45 45 git config user.email github-actions@github.com 46 46 git add . 47 - git commit -m "${{ github.actor }} - ${{ steps.get_commit_message.outputs.message }} 47 + git commit -m "${{ steps.get_commit_message.outputs.message }} 48 48 Original commit: https://github.com/${{ github.repository }}/commit/${{ github.sha }} 49 49 50 50 Co-authored-by: ${{ github.actor }} <${{ steps.get_commit_message.outputs.author_email }}>" || exit 0
+76 -76
README.md
··· 20 20 21 21 - **Access**: Navigate to `/admin.html` or click the "Admin Dashboard" link on the main page 22 22 - **Features**: 23 - - View all levels with pagination 24 - - Search levels by name, author, or ID 25 - - Edit level properties (name, author, sun, water status, difficulty, statistics) 26 - - Delete levels (including related files and database entries) 23 + - View all levels with pagination 24 + - Search levels by name, author, or ID 25 + - Edit level properties (name, author, sun, water status, difficulty, statistics) 26 + - Delete levels (including related files and database entries) 27 27 > Authentication: The admin UI supports optional GitHub OAuth. If `USE_GITHUB_AUTH=true`, users must sign in with GitHub and be included in `GITHUB_ALLOWED_USERS` to access admin endpoints. If `USE_GITHUB_AUTH=false`, the admin endpoints are not protected (not recommended in production). 28 28 > The admin dashboard also supports one-time-token links for a single edit/delete action: 29 - - Edit: `/admin.html?token=...&action=edit&level=123` 30 - - Delete: `/admin.html?token=...&action=delete&level=123` 29 + - Edit: `/admin.html?token=...&action=edit&level=123` 30 + - Delete: `/admin.html?token=...&action=delete&level=123` 31 31 After a successful token-based edit/delete, the page attempts to call `window.close()` (some browsers only allow this for windows opened by script). 32 32 33 33 ## Getting Started ··· 83 83 - **URL:** `/api/levels` 84 84 - **Method:** `POST` 85 85 - **Content Types:** 86 - - `application/octet-stream` 86 + - `application/octet-stream` 87 87 - **URL Params:** None 88 88 - **Query Params:** (for octet-stream) 89 - - `author`: Author name 90 - - `turnstileResponse`: Captcha verification token (if enabled) 89 + - `author`: Author name 90 + - `turnstileResponse`: Captcha verification token (if enabled) 91 91 - **Notes:** Only IZL3 is supported (v2 is deprecated). 92 92 - **Request Body:** Raw binary level data (`.izl3`), sent as the request body. 93 93 - **Success Response:** 94 - - **Code:** 201 95 - - **Content:** 94 + - **Code:** 201 95 + - **Content:** 96 96 97 97 ```json 98 98 { ··· 109 109 Note: `is_water` is stored as `0/1` in the database and is returned as `0/1` in list/detail endpoints. 110 110 111 111 - **Error Responses:** 112 - - **Code:** 400 113 - - **Content:** `{ "error": "Missing required fields" }` 114 - - **Code:** 400 115 - - **Content:** `{ "error": "Content contains inappropriate language or content" }` 116 - - **Code:** 400 117 - - **Content:** `{ "error": "Captcha verification required" }` 118 - - **Code:** 400 119 - - **Content:** `{ "error": "Invalid captcha" }` 120 - - **Code:** 500 121 - - **Content:** `{ "error": "Failed to upload level" }` 112 + - **Code:** 400 113 + - **Content:** `{ "error": "Missing required fields" }` 114 + - **Code:** 400 115 + - **Content:** `{ "error": "Content contains inappropriate language or content" }` 116 + - **Code:** 400 117 + - **Content:** `{ "error": "Captcha verification required" }` 118 + - **Code:** 400 119 + - **Content:** `{ "error": "Invalid captcha" }` 120 + - **Code:** 500 121 + - **Content:** `{ "error": "Failed to upload level" }` 122 122 123 123 ##### List Levels 124 124 ··· 126 126 - **Method:** `GET` 127 127 - **URL Params:** None 128 128 - **Query Params:** 129 - - `page`: Page number (default: 1) 130 - - `limit`: Results per page (default: 10) 131 - - `author`: Filter by author name (partial match) 132 - - `is_water`: Filter by water levels ("true"/"false") 133 - - `version`: Filter by level version (currently always `3`; reserved for future versions) 134 - - `sort`: Sorting mode. Default is by play count (`plays`). Use `recent` to sort by creation time (`created_at`) and `favorites` to sort by favorite count. 135 - - `reversed_order`: Reverse the sort order (`true` or `1`). By default, sorting is descending. 136 - - `token`: One-time token. If provided and valid, the response is filtered to the single level associated with that token (and pagination becomes `page=1`, `limit=1`). If the token is invalid, the endpoint returns `401`. 129 + - `page`: Page number (default: 1) 130 + - `limit`: Results per page (default: 10) 131 + - `author`: Filter by author name (partial match) 132 + - `is_water`: Filter by water levels ("true"/"false") 133 + - `version`: Filter by level version (currently always `3`; reserved for future versions) 134 + - `sort`: Sorting mode. Default is by play count (`plays`). Use `recent` to sort by creation time (`created_at`) and `favorites` to sort by favorite count. 135 + - `reversed_order`: Reverse the sort order (`true` or `1`). By default, sorting is descending. 136 + - `token`: One-time token. If provided and valid, the response is filtered to the single level associated with that token (and pagination becomes `page=1`, `limit=1`). If the token is invalid, the endpoint returns `401`. 137 137 - **Success Response:** 138 - - **Code:** 200 139 - - **Content:** 138 + - **Code:** 200 139 + - **Content:** 140 140 141 141 ```json 142 142 { ··· 165 165 ``` 166 166 167 167 - **Error Response:** 168 - - **Code:** 401 169 - - **Content:** `{ "error": "Invalid token" }` 170 - - **Code:** 500 171 - - **Content:** `{ "error": "Failed to list levels" }` 168 + - **Code:** 401 169 + - **Content:** `{ "error": "Invalid token" }` 170 + - **Code:** 500 171 + - **Content:** `{ "error": "Failed to list levels" }` 172 172 173 173 ##### Get Level Details 174 174 175 175 - **URL:** `/api/levels/:id` 176 176 - **Method:** `GET` 177 177 - **URL Params:** 178 - - `id`: Level ID 178 + - `id`: Level ID 179 179 - **Success Response:** 180 - - **Code:** 200 181 - - **Content:** 180 + - **Code:** 200 181 + - **Content:** 182 182 183 183 ```json 184 184 { ··· 197 197 ``` 198 198 199 199 - **Error Responses:** 200 - - **Code:** 400 201 - - **Content:** `{ "error": "Invalid level ID" }` 202 - - **Code:** 404 203 - - **Content:** `{ "error": "Level not found" }` 204 - - **Code:** 500 205 - - **Content:** `{ "error": "Failed to get level" }` 200 + - **Code:** 400 201 + - **Content:** `{ "error": "Invalid level ID" }` 202 + - **Code:** 404 203 + - **Content:** `{ "error": "Level not found" }` 204 + - **Code:** 500 205 + - **Content:** `{ "error": "Failed to get level" }` 206 206 207 207 ##### Download Level 208 208 209 209 - **URL:** `/api/levels/:id/download` 210 210 - **Method:** `GET` 211 211 - **URL Params:** 212 - - `id`: Level ID 212 + - `id`: Level ID 213 213 - **Success Response:** 214 - - **Code:** 200 215 - - **Content:** Binary file download with `.izl3` extension 214 + - **Code:** 200 215 + - **Content:** Binary file download with `.izl3` extension 216 216 - **Error Responses:** 217 - - **Code:** 400 218 - - **Content:** `{ "error": "Invalid level ID" }` 219 - - **Code:** 404 220 - - **Content:** `{ "error": "Level not found" }` or `{ "error": "Level file not found" }` 221 - - **Code:** 500 222 - - **Content:** `{ "error": "Failed to download level" }` 217 + - **Code:** 400 218 + - **Content:** `{ "error": "Invalid level ID" }` 219 + - **Code:** 404 220 + - **Content:** `{ "error": "Level not found" }` or `{ "error": "Level file not found" }` 221 + - **Code:** 500 222 + - **Content:** `{ "error": "Failed to download level" }` 223 223 224 224 #### Favorites 225 225 ··· 228 228 - **URL:** `/api/levels/:id/favorite` 229 229 - **Method:** `POST` 230 230 - **URL Params:** 231 - - `id`: Level ID 231 + - `id`: Level ID 232 232 - **Request Body:** None (this endpoint always toggles favorite on/off) 233 233 - **Success Response:** 234 - - **Code:** 200 235 - - **Content:** `{ "success": true, "level": { "id": 123, "favorites": 5, ... } }` 234 + - **Code:** 200 235 + - **Content:** `{ "success": true, "level": { "id": 123, "favorites": 5, ... } }` 236 236 - **Error Responses:** 237 - - **Code:** 400 238 - - **Content:** `{ "error": "Invalid level ID" }` 239 - - **Code:** 404 240 - - **Content:** `{ "error": "Level not found" }` 241 - - **Code:** 500 242 - - **Content:** `{ "error": "Failed to favorite level" }` 237 + - **Code:** 400 238 + - **Content:** `{ "error": "Invalid level ID" }` 239 + - **Code:** 404 240 + - **Content:** `{ "error": "Level not found" }` 241 + - **Code:** 500 242 + - **Content:** `{ "error": "Failed to favorite level" }` 243 243 Note: Captcha verification is not required for favoriting. 244 244 245 245 #### Reporting ··· 249 249 - **URL:** `/api/levels/:id/report` 250 250 - **Method:** `POST` 251 251 - **URL Params:** 252 - - `id`: Level ID 252 + - `id`: Level ID 253 253 - **Request Body:** 254 254 255 255 ```json ··· 259 259 ``` 260 260 261 261 - **Behavior:** 262 - - If `USE_REPORTING=false`, this endpoint returns 404. 263 - - If `DISCORD_REPORT_WEBHOOK_URL` is configured, the server sends the report to the Discord webhook (and attaches the level file if available). 264 - - If no webhook is configured, the server still accepts the report and returns success. 262 + - If `USE_REPORTING=false`, this endpoint returns 404. 263 + - If `DISCORD_REPORT_WEBHOOK_URL` is configured, the server sends the report to the Discord webhook (and attaches the level file if available). 264 + - If no webhook is configured, the server still accepts the report and returns success. 265 265 - **Success Response:** 266 - - **Code:** 200 267 - - **Content:** `{ "success": true }` 266 + - **Code:** 200 267 + - **Content:** `{ "success": true }` 268 268 - **Error Responses:** 269 - - **Code:** 400 270 - - **Content:** `{ "error": "Invalid input" }` 271 - - **Code:** 404 272 - - **Content:** `{ "error": "Level not found" }` 273 - - **Code:** 500 274 - - **Content:** `{ "error": "Failed to report level" }` 269 + - **Code:** 400 270 + - **Content:** `{ "error": "Invalid input" }` 271 + - **Code:** 404 272 + - **Content:** `{ "error": "Level not found" }` 273 + - **Code:** 500 274 + - **Content:** `{ "error": "Failed to report level" }` 275 275 276 276 #### Configuration 277 277 ··· 280 280 - **URL:** `/api/config` 281 281 - **Method:** `GET` 282 282 - **Success Response:** 283 - - **Code:** 200 284 - - **Content:** 283 + - **Code:** 200 284 + - **Content:** 285 285 286 286 ```json 287 287 {
+37 -37
TODO.md
··· 3 3 ## High Priority 4 4 5 5 - [x] **Separate Test UI and Admin UI Controls**: There should be a way to disable the test UI without also disabling the admin UI 6 - - Add `USE_TEST_UI` environment variable to control access to `/index.html` test interface 7 - - Keep `USE_PUBLIC_FOLDER` for admin UI but add conditional routing for test interface 8 - - This would allow production deployments to disable testing while keeping admin functionality 6 + - Add `USE_TEST_UI` environment variable to control access to `/index.html` test interface 7 + - Keep `USE_PUBLIC_FOLDER` for admin UI but add conditional routing for test interface 8 + - This would allow production deployments to disable testing while keeping admin functionality 9 9 10 10 - [x] _(Removed in favor of NGINX)_ ~~**Fix SSL/HTTPS Implementation**: The current SSL implementation is incomplete and non-functional~~ 11 - - The SSL certificate and key are read but not actually used to create an HTTPS server 12 - - Need to implement proper HTTPS server with Express.js or migrate to native Deno HTTPS 13 - - Add proper SSL error handling and validation 11 + - The SSL certificate and key are read but not actually used to create an HTTPS server 12 + - Need to implement proper HTTPS server with Express.js or migrate to native Deno HTTPS 13 + - Add proper SSL error handling and validation 14 14 15 15 ## Medium Priority 16 16 17 17 - [x] **Environment Configuration Management** 18 - - Create a `.env.example` file with all available environment variables 19 - - Add environment variable validation on startup 20 - - Document all configuration options in README.md 18 + - Create a `.env.example` file with all available environment variables 19 + - Add environment variable validation on startup 20 + - Document all configuration options in README.md 21 21 22 22 - [x] **API Security Improvements** 23 - - Implement API key authentication for programmatic access 24 - - Add request size limits for file uploads 25 - - Consider adding CSRF protection for admin endpoints 26 - - _(Handled by Cloudflare)_ ~~Add rate limiting for API endpoints (especially `/api/levels` POST)~~ 23 + - Implement API key authentication for programmatic access 24 + - Add request size limits for file uploads 25 + - Consider adding CSRF protection for admin endpoints 26 + - _(Handled by Cloudflare)_ ~~Add rate limiting for API endpoints (especially `/api/levels` POST)~~ 27 27 28 28 - [ ] **Database Improvements** 29 - - Add database migrations system for schema changes 30 - - Implement database connection pooling 31 - - Add database backup/restore functionality 32 - - Add indexes for better query performance (author, created_at, etc.) 29 + - Add database migrations system for schema changes 30 + - Implement database connection pooling 31 + - Add database backup/restore functionality 32 + - Add indexes for better query performance (author, created_at, etc.) 33 33 34 34 - [ ] **Error Handling & Logging** 35 - - Implement structured logging (JSON format) 36 - - Add error tracking/monitoring integration 37 - - Improve error messages for better debugging 38 - - Add request/response logging middleware 35 + - Implement structured logging (JSON format) 36 + - Add error tracking/monitoring integration 37 + - Improve error messages for better debugging 38 + - Add request/response logging middleware 39 39 40 40 ## Low Priority 41 41 42 42 - [x] **Code Quality & Maintenance** 43 - - Split main.ts into separate modules (routes, middleware, database, etc.) 44 - - Add TypeScript strict mode configuration 45 - - Implement unit tests for core functionality 46 - - _(Decided against: API should not be public. README.md has instructions for the API.)_ ~~Add API documentation (OpenAPI/Swagger)~~ 43 + - Split main.ts into separate modules (routes, middleware, database, etc.) 44 + - Add TypeScript strict mode configuration 45 + - Implement unit tests for core functionality 46 + - _(Decided against: API should not be public. README.md has instructions for the API.)_ ~~Add API documentation (OpenAPI/Swagger)~~ 47 47 48 48 - [ ] **Feature Enhancements** 49 - - Add level search by tags/categories 50 - - Implement level comments/reviews system 51 - - Add user profiles and level collections 52 - - Add level statistics and analytics dashboard 49 + - Add level search by tags/categories 50 + - Implement level comments/reviews system 51 + - Add user profiles and level collections 52 + - Add level statistics and analytics dashboard 53 53 54 54 - [ ] **Performance Optimizations** 55 - - Implement response caching for level listings 56 - - Add CDN support for static files 57 - - Optimize database queries with prepared statements 58 - - Add pagination limits and validation 55 + - Implement response caching for level listings 56 + - Add CDN support for static files 57 + - Optimize database queries with prepared statements 58 + - Add pagination limits and validation 59 59 60 60 - [ ] **Deployment & DevOps** 61 - - Add Docker containerization 62 - - Create deployment scripts 63 - - Add health check endpoint (`/api/health`) 64 - - Implement graceful shutdown handling 61 + - Add Docker containerization 62 + - Create deployment scripts 63 + - Add health check endpoint (`/api/health`) 64 + - Implement graceful shutdown handling