Skip to content

Deno JSR packages are never found in a real Deno project: the crawler only probes $DENO_DIR/npm/jsr.io, and the matching ./vendor/jsr.io layout from "vendor": true is ignored #374

Description

[agent] Found by the scheduled Deno bug-hunt routine (ledger #308).

Summary

DenoCrawler::get_jsr_cache_paths (local mode, with no --global-prefix) returns only $DENO_DIR/npm/jsr.io. No Deno release creates that directory. Deno 1.46.3 and 2.9.6 were both checked: JSR modules are cached content-addressed under $DENO_DIR/remote/https/jsr.io/…, and $DENO_DIR/npm/jsr.io never exists.

Deno does have a stable <scope>/<name>/<version>/ layout that matches the crawler's expected shape exactly: a project with "vendor": true in deno.json (supported since Deno 1.37) gets ./vendor/jsr.io/@std/path/1.0.8/join.ts. Deno loads the code from there and allows edits to it. The crawler never looks there, though, so every pkg:jsr/... patch in a real project reports package_not_installed. Pointing --global-prefix at ./vendor/jsr.io by hand applies the same patch correctly, and Deno then runs the patched code.

The module doc (deno_crawler.rs:24-32) says the expected layout exists so that "any future Deno that adopts a stable scope/name/version layout … gets picked up automatically". Deno's vendor directory is that layout, and it isn't picked up.

Impact

For Deno, docs/ecosystems.md lists agent mode as the only supported mode ("✅ apply-only"; vendored and hosted are refused), and README says Deno patches attest via agent mode plus setup.manual. In practice, with no hand-supplied --global-prefix, a JSR patch can't be discovered or applied in any real Deno project. scan reports scannedPackages: 0 and apply reports package_not_installed. The run does fail loudly (partialFailure), so this is a missing-coverage bug, not a silent one. But the one layout that could work out of the box (vendor: true) doesn't.

Repro (Linux; Deno 2.9.6; no API needed)

set -u
SP=/path/to/socket-patch      # main f6b7fb9
mkdir jsr-vendor && cd jsr-vendor; export DENO_DIR=$PWD/.dd
echo '{"vendor":true,"imports":{"@std/path":"jsr:@std/[email protected]"}}' > deno.json
echo 'import {join} from "@std/path"; join("a","b"); console.log("loaded-patched="+JSON.stringify((globalThis as any).__SP||[]));' > probe.ts
deno cache probe.ts
ls vendor/jsr.io/@std/path/1.0.8/join.ts          # exists
ls "$DENO_DIR/npm/jsr.io"                          # No such file or directory
# local manifest + blobs: a patch for pkg:jsr/@std/[email protected] file package/join.ts that prepends
#   globalThis.__SP=(globalThis.__SP||[]).concat(["path"]);
python3 mkman.py . "pkg:jsr/@std/[email protected]=vendor/jsr.io/@std/path/1.0.8:join.ts"
$SP apply --offline --json                          # partialFailure, package_not_installed
deno run probe.ts                                   # loaded-patched=[]
$SP apply --offline --json --global-prefix "$PWD/vendor/jsr.io"   # success, applied
deno run probe.ts                                   # loaded-patched=["path"]

SOCKET_PROXY_URL=<mock> socket-patch scan --json in the same project reports scannedPackages: 0.

Expected vs actual

  • Expected: local agent-mode discovery in a Deno project (is_deno_project already gates on deno.json / deno.jsonc / deno.lock) also probes the project's vendor directory: ./vendor/jsr.io, or the vendor directory Deno uses for that config. That way JSR patches apply without a hand-written --global-prefix, matching the Deno row in docs/ecosystems.md and the crawler's own "picked up automatically" promise.
  • Actual: only the never-created $DENO_DIR/npm/jsr.io is probed, so JSR patches are package_not_installed.

Matrix (Linux sandbox, real Deno, runtime-checked)

Deno $DENO_DIR/npm/jsr.io created? local apply (vendor: true) apply --global-prefix vendor/jsr.io
1.46.3 no fail (package_not_installed) pass, patched code runs
2.0.6 – fail pass
2.2.15 – fail pass
2.9.6 no fail (reproduced twice) pass

macOS and Windows weren't probed for this one; the path logic isn't OS-specific. Releases 3.3.0 and 4.0.0 weren't bisected, since the crawler hasn't changed this path.

Suspect code

  • crates/socket-patch-core/src/crawlers/deno_crawler.rs:65-81: get_jsr_cache_paths returns only deno_dir().join("npm").join("jsr.io").
  • The same function feeds both find_by_purls (apply / rollback) and crawl_all (scan).

Related: #26 (added --global-prefix support for Deno).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions