fix: pin js-dos to v8.3.14 (emulators 8.3.3) — the last working CDN version
Build & Deploy / build-and-deploy (push) Successful in 1m0s

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.
This commit is contained in:
Hermes Agent
2026-06-03 19:06:44 +02:00
parent 79a0af86ad
commit 840777d289
2 changed files with 39 additions and 4 deletions
@@ -512,6 +512,19 @@ public class UploadResource {
);
private void createBundle(Path extractDir, String exePath, List<String> 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 ──────────────────────────────────