-
Notifications
You must be signed in to change notification settings - Fork 0
Fix broken documentation links on GitHub Pages with security improvements #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fe39a66
51edfa5
d8f217c
7b9875d
1ae9fb3
ae43053
8a1353d
d024808
4a98375
8538eb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| # Jacare Developer Guide 🧑💻🐊 | ||
|
|
||
| > **⚠️ IMPORTANT NOTICE**: The main crocdb source is currently offline, causing data access failures. A root cause has been identified and a fix is in progress. An update will be published shortly with restored availability. | ||
|
|
||
| Welcome to the full technical README for **Jacare**, the Brazilian-inspired desktop ROM library manager that wraps the Crocdb API with an Electron + Express + React stack. | ||
|
|
||
| ## Table of contents | ||
| - [Project overview](#project-overview) | ||
| - [Architecture](#architecture) | ||
| - [Repository layout](#repository-layout) | ||
| - [Prerequisites](#prerequisites) | ||
| - [Installation](#installation) | ||
| - [Development scripts](#development-scripts) | ||
| - [Configuration](#configuration) | ||
| - [Data & storage](#data--storage) | ||
| - [API reference](#api-reference) | ||
| - [Production build](#production-build) | ||
| - [Support](#support) | ||
|
|
||
| ## Project overview | ||
| Jacare helps you browse, enrich, and launch ROMs from one place. It keeps your library on disk while pulling metadata from [Crocdb](https://crocdb.net) and reporting long-running work through jobs and SSE streams. | ||
|
|
||
| ## Architecture | ||
| - **Electron shell** boots the server and ships the React UI for a native desktop experience. | ||
| - **Express API** powers Crocdb searches, manifest writing, and job orchestration. | ||
| - **React + Vite UI** calls the API over REST + SSE for real-time job updates. | ||
| - **SQLite backing store** keeps settings, cached Crocdb responses, library items, and job tracking tables. | ||
|
|
||
| ## Repository layout | ||
| - `apps/server` – Express API, jobs, local scanning, and Crocdb client. | ||
| - `apps/web` – React UI (Vite) served by the server or opened directly in dev. | ||
| - `apps/desktop` – Electron main process that wraps the server and UI. | ||
| - `packages/shared` – Shared types, defaults, and the manifest schema used across workspaces. | ||
|
|
||
| ## Prerequisites | ||
| - Node.js 20+ | ||
| - npm | ||
| - Optional: Git LFS if you store binaries or media in the repo. | ||
|
|
||
| ## Installation | ||
| ```bash | ||
| npm ci | ||
| ``` | ||
|
|
||
| ## Development scripts | ||
| - `npm run dev` – Run shared build watch + server + web + desktop together. | ||
| - `npm run dev:shared` – Start the shared package in watch mode. | ||
| - `npm run dev:server` – Start the Express API and job runners. | ||
| - `npm run dev:web` – Start the React UI via Vite. | ||
| - `npm run dev:desktop` – Start the Electron shell pointing at the dev server. | ||
| - `npm run build` – Build all workspaces. | ||
| - `npm run typecheck` – Type-check the monorepo. | ||
| - `npm run lint` – Lint all TypeScript and React code. | ||
| - `npm run test:unit` – Run unit tests with Vitest. | ||
|
|
||
| ## Configuration | ||
| - `CROCDESK_PORT` (default `3333`) – Server port | ||
| - `CROCDESK_DATA_DIR` (default `./data`) – Directory for SQLite databases and cache | ||
| - `CROCDB_BASE_URL` (default `https://api.crocdb.net`) – Crocdb API base URL | ||
| - `CROCDB_CACHE_TTL_MS` (default `86400000`) – Cache TTL in milliseconds (24 hours) | ||
| - `CROCDESK_DEV_URL` (default `http://localhost:5173`) – Dev server URL for Electron | ||
|
|
||
| Settings stored in the database: | ||
| - `downloadDir` – Temporary directory for zip file downloads (deleted after extraction) | ||
| - `libraryDir` – Root directory where extracted game files are stored. All scanning and library operations work from this root. | ||
| - `queue.concurrency` (optional) – Maximum concurrent jobs | ||
|
|
||
| ## Data & storage | ||
| - **SQLite tables:** | ||
| - `settings` – Application settings (downloadDir, libraryDir, queue config) | ||
| - `crocdb_cache_search` – Cached search results from Crocdb | ||
| - `crocdb_cache_entry` – Cached entry data from Crocdb | ||
| - `library_items` – Indexed ROM files with metadata | ||
| - `jobs` – Job records (scan_local, download_and_install) | ||
| - `job_steps` – Individual step progress for jobs | ||
| - **Manifests:** Each scanned ROM folder receives a `.crocdesk.json` manifest describing the game entry. | ||
| - **Data directory:** Defaults to `./data`; point it to a faster disk or network share as needed. | ||
|
|
||
| ## API reference | ||
| - **Base URL:** `http://localhost:<CROCDESK_PORT>` (3333 by default) or the packaged server inside Electron. | ||
|
|
||
| ### Crocdb endpoints | ||
| - `POST /crocdb/search` – Query Crocdb for matches. Request body: `{ search_key?, platforms?, regions?, rom_id?, max_results?, page? }` | ||
| - `POST /crocdb/entry` – Pull metadata and assets for a specific result. Request body: `{ slug }` | ||
| - `GET /crocdb/platforms` – Get available platforms | ||
| - `GET /crocdb/regions` – Get available regions | ||
| - `GET /crocdb/info` – Get Crocdb service info | ||
|
|
||
| ### Library endpoints | ||
| - `GET /library/items?platform=<platform>` – List library items (optionally filtered by platform) | ||
| - `GET /library/games?platform=<platform>` – List library games (optionally filtered by platform) | ||
| - `POST /library/scan/local` – Trigger a local scan job | ||
| - `DELETE /library/item?dir=<path>` – Delete a library item and its directory | ||
|
|
||
| ### Jobs endpoints | ||
| - `GET /jobs` – List all jobs with preview data | ||
| - `GET /jobs/:id` – Get job details and steps | ||
| - `POST /jobs/download` – Enqueue a download and install job. Request body: `{ slug, linkIndex? }` | ||
| - `POST /jobs/:id/cancel` – Cancel a job | ||
| - `POST /jobs/:id/pause` – Pause a job | ||
| - `POST /jobs/:id/resume` – Resume a paused job | ||
| - `POST /jobs/pause-all` – Pause all jobs | ||
| - `POST /jobs/resume-all` – Resume all paused jobs | ||
|
|
||
| ### Settings endpoints | ||
| - `GET /settings` – Get current settings | ||
| - `PUT /settings` – Update settings. Request body: Settings object | ||
|
|
||
| ### Other endpoints | ||
| - `GET /events` – SSE stream for job progress (scans, downloads, cache refreshes) | ||
| - `GET /file?path=<path>` – Serve files from the library directory (JSON files are parsed, others are streamed) | ||
| - `GET /health` – Health check endpoint | ||
| - `GET /api-config` – API configuration endpoint. Returns `{ apiUrl: string, port: number }` for frontend runtime configuration. The frontend uses this to auto-detect the correct API base URL. | ||
|
|
||
| **Responses:** Wrapped as `{ info, data }` objects for consistency. | ||
|
|
||
| ## Production build | ||
|
|
||
| ### Standalone Bundle (Recommended) | ||
|
|
||
| Create a single standalone binary that includes both the server and web UI: | ||
|
|
||
| ```bash | ||
| npm run package:bundle | ||
| ``` | ||
|
|
||
| This will create binaries in `release/bundle/`: | ||
| - `jacare-win.exe` (Windows) | ||
| - `jacare-macos` (macOS) | ||
| - `jacare-linux` (Linux) | ||
|
|
||
| The bundle includes: | ||
| - Express server | ||
| - Web UI static assets | ||
| - All dependencies (including native modules) | ||
|
|
||
| No Node.js installation required—users can run the binary directly. | ||
|
|
||
| ### Desktop App | ||
|
|
||
| Package the Electron app from `apps/desktop`: | ||
|
|
||
| ```bash | ||
| npm run package:desktop | ||
| ``` | ||
|
|
||
| This bundles the server and web assets for a native desktop experience. | ||
|
|
||
| ### Server Binary Only | ||
|
|
||
| Package just the server binary: | ||
|
|
||
| ```bash | ||
| npm run package:server | ||
| ``` | ||
|
|
||
| ### CI/CD | ||
|
|
||
| CI on `main` automatically publishes release archives with: | ||
| - Desktop app packages (Windows, macOS, Linux) | ||
| - Standalone bundle binaries | ||
| - Server-only binaries | ||
| - Latest changelog and README | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Port and API URL Configuration Issues | ||
|
|
||
| **Problem**: Frontend shows CORS errors or can't connect to API, especially in Docker deployments. | ||
|
|
||
| **Solution**: The frontend uses runtime API URL detection. It will: | ||
| 1. Check for `window.API_URL` (injected via script tag) | ||
| 2. Fetch `/api-config` endpoint to auto-detect the API URL | ||
| 3. Fall back to relative URLs for same-origin serving | ||
|
|
||
| **For Docker with custom port:** | ||
| - The `/api-config` endpoint automatically returns the correct API URL based on the request origin | ||
| - If frontend and backend are on different origins, inject `window.API_URL` in `index.html` via entrypoint script | ||
| - Never hardcode `localhost:3333` in frontend code | ||
|
|
||
| **Common issues:** | ||
| - **CORS errors**: Usually means frontend is trying to connect to wrong origin. Check that `/api-config` returns the correct URL. | ||
| - **Connection refused**: Frontend is using hardcoded `localhost:3333` instead of `getApiUrl()`. Always use `getApiUrl()` function. | ||
| - **Vite proxy not working**: Ensure `CROCDESK_PORT` environment variable is set when running `npm run dev:web`. | ||
|
|
||
| ## Support | ||
| - Issues & roadmap: [GitHub Issues](https://github.com/luandev/jacare/issues) | ||
| - Crocdb service: [https://crocdb.net](https://crocdb.net) and [https://api.crocdb.net](https://api.crocdb.net) | ||
| - Tech stack docs: [Electron](https://www.electronjs.org/), [Express](https://expressjs.com/), [Vite](https://vitejs.dev/), [React](https://react.dev/) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,124 @@ | ||||||||||||||||||||||||||||||||||||||
| <!DOCTYPE html> | ||||||||||||||||||||||||||||||||||||||
| <html lang="en"> | ||||||||||||||||||||||||||||||||||||||
| <head> | ||||||||||||||||||||||||||||||||||||||
| <meta charset="UTF-8"> | ||||||||||||||||||||||||||||||||||||||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||||||||||||||||||||||||||||||||||
| <title>Jacare Developer Guide</title> | ||||||||||||||||||||||||||||||||||||||
| <meta name="description" content="Technical documentation and developer guide for Jacare ROM library manager"> | ||||||||||||||||||||||||||||||||||||||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.5.1/github-markdown.min.css" integrity="sha384-OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb" crossorigin="anonymous"> | ||||||||||||||||||||||||||||||||||||||
| <style> | ||||||||||||||||||||||||||||||||||||||
| :root { | ||||||||||||||||||||||||||||||||||||||
| --bg: #0d1117; | ||||||||||||||||||||||||||||||||||||||
| --text: #c9d1d9; | ||||||||||||||||||||||||||||||||||||||
| --link: #58a6ff; | ||||||||||||||||||||||||||||||||||||||
| --border: #30363d; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @media (prefers-color-scheme: light) { | ||||||||||||||||||||||||||||||||||||||
| :root { | ||||||||||||||||||||||||||||||||||||||
| --bg: #ffffff; | ||||||||||||||||||||||||||||||||||||||
| --text: #24292f; | ||||||||||||||||||||||||||||||||||||||
| --link: #0969da; | ||||||||||||||||||||||||||||||||||||||
| --border: #d0d7de; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| body { | ||||||||||||||||||||||||||||||||||||||
| margin: 0; | ||||||||||||||||||||||||||||||||||||||
| padding: 0; | ||||||||||||||||||||||||||||||||||||||
| background: var(--bg); | ||||||||||||||||||||||||||||||||||||||
| color: var(--text); | ||||||||||||||||||||||||||||||||||||||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .header { | ||||||||||||||||||||||||||||||||||||||
| background: var(--bg); | ||||||||||||||||||||||||||||||||||||||
| border-bottom: 1px solid var(--border); | ||||||||||||||||||||||||||||||||||||||
| padding: 16px 24px; | ||||||||||||||||||||||||||||||||||||||
| position: sticky; | ||||||||||||||||||||||||||||||||||||||
| top: 0; | ||||||||||||||||||||||||||||||||||||||
| z-index: 100; | ||||||||||||||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||||||||||||||
| justify-content: space-between; | ||||||||||||||||||||||||||||||||||||||
| align-items: center; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .header-title { | ||||||||||||||||||||||||||||||||||||||
| font-size: 18px; | ||||||||||||||||||||||||||||||||||||||
| font-weight: 600; | ||||||||||||||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||||||||||||||
| align-items: center; | ||||||||||||||||||||||||||||||||||||||
| gap: 8px; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .header-links { | ||||||||||||||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||||||||||||||
| gap: 12px; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .header-links a { | ||||||||||||||||||||||||||||||||||||||
| color: var(--link); | ||||||||||||||||||||||||||||||||||||||
| text-decoration: none; | ||||||||||||||||||||||||||||||||||||||
| font-size: 14px; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .header-links a:hover { | ||||||||||||||||||||||||||||||||||||||
| text-decoration: underline; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .container { | ||||||||||||||||||||||||||||||||||||||
| max-width: 980px; | ||||||||||||||||||||||||||||||||||||||
| margin: 0 auto; | ||||||||||||||||||||||||||||||||||||||
| padding: 24px; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| .markdown-body { | ||||||||||||||||||||||||||||||||||||||
| box-sizing: border-box; | ||||||||||||||||||||||||||||||||||||||
| min-width: 200px; | ||||||||||||||||||||||||||||||||||||||
| max-width: 980px; | ||||||||||||||||||||||||||||||||||||||
| margin: 0 auto; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @media (max-width: 767px) { | ||||||||||||||||||||||||||||||||||||||
| .container { | ||||||||||||||||||||||||||||||||||||||
| padding: 15px; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| </style> | ||||||||||||||||||||||||||||||||||||||
| </head> | ||||||||||||||||||||||||||||||||||||||
| <body> | ||||||||||||||||||||||||||||||||||||||
| <div class="header"> | ||||||||||||||||||||||||||||||||||||||
| <div class="header-title"> | ||||||||||||||||||||||||||||||||||||||
| <span>🐊</span> | ||||||||||||||||||||||||||||||||||||||
| <span>Jacare Developer Guide</span> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| <div class="header-links"> | ||||||||||||||||||||||||||||||||||||||
| <a href="../../">Home</a> | ||||||||||||||||||||||||||||||||||||||
| <a href="../user/">User Guide</a> | ||||||||||||||||||||||||||||||||||||||
| <a href="https://github.com/luandev/jacare">GitHub</a> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| <div class="container"> | ||||||||||||||||||||||||||||||||||||||
| <article class="markdown-body" id="content"> | ||||||||||||||||||||||||||||||||||||||
| <p>Loading documentation...</p> | ||||||||||||||||||||||||||||||||||||||
| </article> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| <script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js" integrity="sha384-aPoKub31DR9aRXyS6APWjc2IV99R+k/2y2HPv8P8X1wH4L3eZrFbEMlMxPYxzFLR" crossorigin="anonymous"></script> | ||||||||||||||||||||||||||||||||||||||
| <script> | ||||||||||||||||||||||||||||||||||||||
| async function loadMarkdown() { | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| const response = await fetch('./README.md'); | ||||||||||||||||||||||||||||||||||||||
| const markdown = await response.text(); | ||||||||||||||||||||||||||||||||||||||
| const html = marked.parse(markdown); | ||||||||||||||||||||||||||||||||||||||
| document.getElementById('content').innerHTML = html; | ||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||
| document.getElementById('content').innerHTML = '<p>Error loading documentation. Please visit the <a href="https://github.com/luandev/jacare">GitHub repository</a> for the latest documentation.</p>'; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| document.getElementById('content').innerHTML = '<p>Error loading documentation. Please visit the <a href="https://github.com/luandev/jacare">GitHub repository</a> for the latest documentation.</p>'; | |
| const contentEl = document.getElementById('content'); | |
| if (!contentEl) return; | |
| // Clear any existing content | |
| contentEl.textContent = ''; | |
| const paragraph = document.createElement('p'); | |
| paragraph.textContent = 'Error loading documentation. Please visit the '; | |
| const link = document.createElement('a'); | |
| link.href = 'https://github.com/luandev/jacare'; | |
| link.textContent = 'GitHub repository'; | |
| paragraph.appendChild(link); | |
| paragraph.appendChild(document.createTextNode(' for the latest documentation.')); | |
| contentEl.appendChild(paragraph); |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,68 @@ | ||||||||||
| # Jacare Friendly Guide 😀🐊 | ||||||||||
|
|
||||||||||
|
||||||||||
| > **Important:** The main Crocdb metadata service is currently offline/unavailable. | |
| > Jacare will still work for managing your local ROM library, but features that depend on Crocdb (online search, metadata enrichment, and downloads) may be limited or fail until the service is restored. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the Crocdb offline warning notice to the nested user guide. (4a98375)
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This statement is inaccurate. According to the project's coding guidelines, downloads are disabled by default for safety and require setting CROCDESK_ENABLE_DOWNLOADS=true to enable. The text should be corrected to: "Downloads are disabled by default. Enable them with CROCDESK_ENABLE_DOWNLOADS=true environment variable."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed! Downloads are now correctly documented as disabled by default, with CROCDESK_ENABLE_DOWNLOADS=true required to enable them. (4a98375)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The important warning notice about Crocdb being offline is missing from this new documentation file. The original docs/README.md includes a critical notice at the top about the main Crocdb source being offline. This information should be included here for consistency and to inform users of current service status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the Crocdb offline warning notice to the nested developer guide. (4a98375)