/** * Pull unread replies (used for badge count). */ export async function getUnreadCount( threadId: string, token: string ): Promise<number> const data = await authFetch( `https://api.f95zone.to/v1/threads/$threadId/replies?unread=true`, token ); return data.unreadCount ?? 0;
For developers who prefer a no‑code approach, the plugin can expose a “Generate markdown” button that copies the output to the clipboard, allowing manual posting if the API is unavailable. 7️⃣ UI Mock‑up (Textual Description) +--------------------------------------------------------------+ | JSK Studio – Bottom Panel | |--------------------------------------------------------------| | [F95Zone] Connect | Status: Connected as <username> | |--------------------------------------------------------------| | Game Title: <input> | Category: <dropdown> | | Version: <input> | Cover image: <preview + upload> | |--------------------------------------------------------------| | [Publish Build] [Sync Changelog] [View Thread] [Analytics]| |--------------------------------------------------------------| | Unread Replies: 3 (badge) | Views: 1,254 Likes: 87 | +--------------------------------------------------------------+ All controls are optional – the developer can enable only the parts they need. 8️⃣ Testing & QA Checklist | Test | Description | |------|-------------| | OAuth flow | Verify token retrieval, expiration handling, and revocation. | | Thread creation | Mock API response; ensure markdown is correctly escaped. | | Update comment | Confirm that only the new part of the changelog is added. | | Badge count | Simulate a new reply and confirm badge increments. | | Analytics | Use a fake stats endpoint and verify chart rendering. | | Error handling | Force 429/500 responses and verify exponential back‑off. | | Security | Run static analysis to ensure no token leaks in logs. | | Cross‑platform | Test on Windows/macOS/Linux installations of JSK Studio. | 9️⃣ Release Plan | Milestone | Scope | Approx. Effort | |-----------|-------|----------------| | MVP | OAuth, thread creation, markdown
import createThread, appendComment, buildReleaseMarkdown, from "./f95Client"; jsk studio f95zone
## Download [Get the build here]($downloadUrl)
If F95Zone does expose a public API , the Bridge can fall back to HTML scraping (with a small cheerio ‑style parser). All scraping logic lives behind an abstraction layer so the same UI works no matter which method is used. 5️⃣ Security & Privacy Considerations | Concern | Mitigation | |---------|------------| | OAuth token leakage | Store token encrypted using the IDE’s secret‑vault (e.g., VS Code secret storage). Refresh tokens are never written to disk unencrypted. | | Cross‑site request forgery | All POST/PUT calls use the Bearer token header; no cookies are used. | | User‑generated markdown | Escape any raw HTML before posting; only allow a whitelist of tags ( <b> , <i> , <img> ). | | Rate limiting | The bridge respects the Retry‑After header from F95Zone and backs off exponentially. | | Data retention | No forum content is persisted longer than 30 days on the local machine; the user can clear the cache from the settings page. | 6️⃣ Sample Code – Minimal Node/TypeScript Client The snippet below shows the core “post‑or‑update” logic. It can be dropped into the plugin’s backend ( src/backend/f95Client.ts ). // f95Client.ts import fetch from "node-fetch"; /** * Pull unread replies (used for badge count)
$coverImgUrl ? `\n` : ""
if (!res.ok) const txt = await res.text(); throw new Error(`F95Zone error $res.status: $txt`); return res.json(); } | | Update comment | Confirm that only
/** * Helper – perform an authorized request. */ async function authFetch( url: string, token: string, init: RequestInit = {} ) { const res = await fetch(url, { ...init, headers: { ...(init.headers ?? {}), Authorization: `Bearer $token`, "Content-Type": "application/json", }, });