From 840777d28963f18a81c5d9d0466216ab15748348 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 3 Jun 2026 19:06:44 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20pin=20js-dos=20to=20v8.3.14=20(emulators?= =?UTF-8?q?=208.3.3)=20=E2=80=94=20the=20last=20working=20CDN=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The js-dos CDN 'latest' was upgraded to 8.3.20 (emulators 8.3.8) which ships a rebuilt wlibzip.wasm (113,081 bytes vs 112,732 in 8.3.3). The _zipfile_add WASM function in this newer libzip binary fails on our bundles with 'Unable to add .jsdos/jsdos.json into bundle.zip', breaking ALL games. Pinning to 8.3.14 (emulators 8.3.3, wlibzip.wasm 112,732 bytes) restores the working libzip WASM. The JavaScript wrapper code is identical between versions — only the compiled WASM binary differs. Also restored .jsdos/ config files in bundles (no longer need to strip them) and reverted the autoStart workaround. --- frontend/src/pages/Play.svelte | 6 +-- .../java/com/dostalgia/UploadResource.java | 37 ++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/Play.svelte b/frontend/src/pages/Play.svelte index 41ce335..5602e38 100644 --- a/frontend/src/pages/Play.svelte +++ b/frontend/src/pages/Play.svelte @@ -44,7 +44,7 @@ // Load js-dos CSS const link = document.createElement("link"); link.rel = "stylesheet"; - link.href = "https://v8.js-dos.com/latest/js-dos.css"; + link.href = "https://v8.js-dos.com/8.xx/8.3.14/js-dos.css"; document.head.appendChild(link); injectedLink = link; @@ -53,7 +53,7 @@ try { await new Promise((resolve, reject) => { const s = document.createElement("script"); - s.src = "https://v8.js-dos.com/latest/js-dos.js"; + s.src = "https://v8.js-dos.com/8.xx/8.3.14/js-dos.js"; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); @@ -70,7 +70,7 @@ try { const url = isSetup ? setupBundleUrl(game) : bundleUrl(game); if (!url || !window.Dos) throw new Error("Failed to resolve game bundle"); - dosCI = await window.Dos(dosContainer, { url, autoStart: true, countDownStart: 0 }); + dosCI = await window.Dos(dosContainer, { url }); running = true; } catch (e) { error = e.message; diff --git a/src/main/java/com/dostalgia/UploadResource.java b/src/main/java/com/dostalgia/UploadResource.java index 5ded448..1764b6a 100644 --- a/src/main/java/com/dostalgia/UploadResource.java +++ b/src/main/java/com/dostalgia/UploadResource.java @@ -512,6 +512,19 @@ public class UploadResource { ); private void createBundle(Path extractDir, String exePath, List cdImages, Path bundlePath) throws IOException { + // Write .jsdos config directly into the extract directory + Path jsdos = extractDir.resolve(".jsdos"); + Files.createDirectories(jsdos); + if (exePath != null) { + String relExe = extractDir.relativize(Path.of(exePath)).toString(); + Files.writeString(jsdos.resolve("dosbox.conf"), buildDosboxConf(relExe, cdImages)); + Files.write(jsdos.resolve("jsdos.json"), buildJsdosJson(relExe)); + } else { + // CD-only game — no executable, mount CD and show a DOS prompt + Files.writeString(jsdos.resolve("dosbox.conf"), buildCdOnlyDosboxConf(cdImages)); + Files.write(jsdos.resolve("jsdos.json"), buildCdOnlyJsdosJson()); + } + // ZIP it up directly from extractDir (no temp copy) try (var zos = new java.util.zip.ZipOutputStream(Files.newOutputStream(bundlePath))) { @@ -537,9 +550,26 @@ public class UploadResource { zos.closeEntry(); } - // ── Phase 3: All game files ── + // ── Phase 3: .jsdos config files (must come before game files) ── + try (var walk = Files.walk(jsdos)) { + walk.filter(Files::isRegularFile) + .sorted() + .forEach(f -> { + try { + String entryName = extractDir.relativize(f).toString().replace('\\', '/'); + zos.putNextEntry(new java.util.zip.ZipEntry(entryName)); + Files.copy(f, zos); + zos.closeEntry(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + + // ── Phase 4: All other game files ── try (var walk = Files.walk(extractDir)) { walk.filter(Files::isRegularFile) + .filter(f -> !f.startsWith(jsdos)) .filter(f -> { String n = f.getFileName().toString().toLowerCase(); int dot = n.lastIndexOf('.'); @@ -558,6 +588,11 @@ public class UploadResource { }); } } + + // Clean up .jsdos config files from the extract dir + Files.walk(jsdos).sorted(Comparator.reverseOrder()).forEach(p -> { + try { Files.deleteIfExists(p); } catch (IOException ignored) {} + }); } // ─── Configuration Helpers ──────────────────────────────────