Skip to content

chore: upgrade deno to 2.7.14#14504

Open
cderv wants to merge 6 commits into
mainfrom
fix/issue-14291
Open

chore: upgrade deno to 2.7.14#14504
cderv wants to merge 6 commits into
mainfrom
fix/issue-14291

Conversation

@cderv
Copy link
Copy Markdown
Member

@cderv cderv commented May 11, 2026

Summary

Bumps bundled Deno from v2.4.5 to v2.7.14, fixing #14291 (silent crash on Windows builds older than 16299).

Why

Deno v2.4.5 transitively depends on quinn-udp 0.5.8, which calls the Windows API IsWow64Process2. That API is absent on Windows builds older than 16299 (Windows Server 2016 = build 14393, early Windows 10). On those systems Quarto exits silently before any code runs.

quinn-udp 0.5.9 (shipped in Deno v2.6.9 onward, per the denoland/deno Cargo.lock) removed the call. v2.7.14 is the latest stable as of this PR.

Verification

Deno tag quinn-udp
v2.4.5 (current) 0.5.8 (broken)
v2.6.9 0.5.9 (fixed)
v2.7.14 (target) 0.5.9 (fixed)

Verified via gh api repos/denoland/deno/contents/Cargo.lock?ref=<tag>.

Cannot be reproduced locally (no Server 2016 / pre-16299 Windows hardware on hand). Reporter to confirm against the prerelease build.

Notable changes beyond the version bump

  • TypeScript typing fallout from Deno 2.5–2.7: TS 5.9 tightened Uint8Array<ArrayBuffer> vs <ArrayBufferLike> and Deno resolves the bare path specifier's types via node:path compat instead of the import map. Fixed in src/deno_ral/path.ts (new @std/path alias for named imports of SEPARATOR/fromFileUrl/etc.) and src/core/{deno-dom,hash,http,path}.ts (targeted casts at Response/crypto.subtle.digest call sites).
  • conda-forge hash in .github/workflows/create-release.yml updated to h6046fbb_0 (linux-64 build for 2.7.14). The make-tarball-rhel job stays if: false per existing project decision; hash updated for forward consistency.
  • dev-docs/upgrade-dependencies.md had several stale instructions (S3-upload step that no longer applies, deno.land/std@x example that predated the JSR migration, missing check.ts sync step). Fixed in this PR alongside the actual upgrade.

.bat/.cmd spawn audit

Audited Deno.Command call sites under src/ for direct .bat/.cmd invocation (Deno 2.5.2 briefly rejected these; 2.5.6+ re-allowed). Findings:

  • safeWindowsExec — routes via cmd /c
  • devconfig.ts — explicit ["cmd", "/c", ...] wrapper ✓
  • dart-sass.ts — bypasses sass.bat, invokes dart.exe + sass.snapshot directly ✓
  • texlive.ts tlmgrCommand — routes via safeWindowsExec on Windows ✓
  • verapdf.ts — string references for path-building only; no direct spawn ✓
  • serve.ts/preview-server.ts (npm.cmd for external preview): verified direct Deno.Command("npm.cmd", ...) works under Deno 2.7.14 — no wrapper needed.

Test plan

  • configure.cmd succeeds against new binary (verified locally on Windows)
  • quarto check reports Deno 2.7.14 with no version mismatch and clean TS typecheck
  • Local smokes pass on Windows: unit/preview-initial-path.test.ts, smoke/render/render-html|reveal|pdf|docx|typst-package-staging.test.ts, smoke/engine/* (29/0/0)
  • CI matrix green (Linux + macOS + Windows)

cderv added 6 commits May 11, 2026 19:02
Deno 2.7.14 bundles TypeScript 5.9.2 with tightened generics
(Uint8Array<ArrayBuffer> vs <ArrayBufferLike>) and resolves the bare
'path' specifier's types via node:path compat instead of the import-map
target. Add a non-colliding '@std/path' alias for named imports of
SEPARATOR/fromFileUrl/etc., and cast Uint8Array at Response/digest call
sites where the new BufferSource/BodyInit signatures require an
ArrayBuffer-backed view.
Prose said the hash appears in three places (echo, curl, tar) but the
example block only showed it on curl + tar, contradicting the prose.
@posit-snyk-bot
Copy link
Copy Markdown
Collaborator

posit-snyk-bot commented May 11, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cderv
Copy link
Copy Markdown
Member Author

cderv commented May 12, 2026

Some notes from a follow-up investigation on the @std/path alias added in fix(types): adjust for deno 2.7.14 TS stricter typing, both to document the root cause and to capture why a fuller migration was deliberately not done in this PR.

What changed in Deno

The trigger is denoland/deno#31502 (commit a49fdb5), shipped in Deno 2.6.0: feat: include @types/node type declarations out of the box. It bundles a full cli/tsc/dts/node/ directory into the Deno binary and adds "node" to the default TS lib array. The bundled node/path.d.cts contains an ambient declare module "path" { ... } (the Node PlatformPath interface).

At type-check time, that ambient declaration shadows anything the import map says for the bare specifier "path". Runtime resolution is unaffected — the import map still wins there, so "path" still loads jsr:@std/path@1.0.8. The result is a runtime/type mismatch only for the std-only members (SEPARATOR, SEPARATOR_PATTERN, fromFileUrl, toFileUrl, globToRegExp, isGlob) — exactly the symbols this PR routes through the new "@std/path" key.

The TS bundle bump (5.9.2 via #30601, Deno 2.5.0) is incidental — the proximate cause is the ambient declare module from #31502 in 2.6.0.

Two documented opt-outs exist:

  1. Remove "node" from lib in the Deno config.
  2. Use a specifier that does not collide with a Node built-in name (e.g., "@std/path").

This PR takes route (2), scoped to the minimum required.

Why our import map uses bare specifiers in the first place

The bare-specifier convention ("path", "fs/", "http/", "crypto/", …) predates JSR. Earliest src/import_map.json (commit fc4b86716) used "path/": "https://deno.land/std/path/" — the standard Deno std-lib directory-alias idiom from the deno.land/std era. Commit 740829733 ("upgrade to deno 1.46.3") migrated those to JSR and dropped the trailing slash because jsr:@std/path is a module, not a directory. The collision with Node built-in module names is incidental — it was historically the same short name Deno's std lib used.

The pattern is also load-bearing in two adjacent places that should not be churned without thought:

  1. Vendoring / dev mode. src/dev_import_map.json maps "path"./vendor/jsr.io/@std/path/0.224.0/mod.ts (the vendored copy produced by configure.sh). Any rename has to land there too.
  2. quarto run user scripts. These resolve through a separate map: src/resources/deno_std/run_import_map.json, which already uses a distinct "stdlib/path" namespace (see src/core/run/deno.ts lines 37–47). User scripts via quarto run <script.ts> are not affected by the bare-"path" collision unless the user passes --dev, which intentionally routes through the main import_map.json.

The release-time bundling (./quarto-bld prepare-dist) goes through tools/deno-esbuild-bundle.ts with the same src/import_map.json and runs with --no-check, so the alias addition costs nothing at bundle time — esbuild dedupes by resolved URL.

Why the fix is minimal here

  • Only the 6 symbols that don't exist on Node's PlatformPath are routed through "@std/path". The rest (basename, dirname, extname, isAbsolute, join, normalize, relative, resolve) type-check fine via Node's path types because the signatures happen to be compatible. Both specifiers resolve to the same JSR module at runtime, so behavior is identical.
  • A broader sweep (moving every "path" usage to "@std/path", updating dev_import_map.json, possibly dropping the bare key) is the conceptually cleanest fix, but it touches the vendoring path and the --dev-mode quarto run plumbing. Doing that on top of a Deno major-version-step bump expands the blast radius unnecessarily for this PR.

Other collisions to watch

The same Deno-side mechanism (ambient declare module in the bundled node lib) applies to every bare key in src/import_map.json that matches a Node built-in name. Today that's "fs/", "http/", "crypto/", "events/", plus the "path" already handled. Trailing-slash directory keys may behave differently from a bare module key for ambient-declaration matching, so they may or may not currently bite us — none of them surfaced in this Deno bump. Worth keeping in mind for the next upgrade.

Suggested follow-up (separate PR)

Migrate src/deno_ral/path.ts to import everything from "@std/path" (and "@std/path/posix"), update src/dev_import_map.json accordingly, and audit the one remaining from "path" site (src/resources/extension-subtrees/julia-engine/src/julia-engine.ts). That removes the second specifier, makes types and runtime agree end-to-end, and pre-empts the same regression on other node:*-named keys.

How to reproduce locally

With Deno 2.7.14 cached under package/dist/bin/:

$deno = "package/dist/bin/tools/x86_64/deno.exe"
$env:DENO_DIR = "$PWD/package/dist/bin/deno_cache"
& $deno check --unstable-kv --unstable-ffi --no-config --no-lock `
    --allow-import --importmap="src/import_map.json" src/quarto.ts

Revert just src/deno_ral/path.ts + src/import_map.json to pre-fix versions and the run produces 6 TS2339 errors on PlatformPath. Restore the fix and it exits 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants