You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A plugin whose dependency graph contains a CommonJS module that requires punycode/ fails to load on dsh 0.1.7-rc.2 with failed to import, while the identical plugin activates normally on dsh 0.1.5-rc.2. The fault is in @deepseek-ai/dsh-app-boot's new ResolutionRouter, which was rewritten for 0.1.7 and no longer guards createRequire(...).resolve.paths().
(Issues are disabled on this repo, so I'm reporting here — apologies if Q&A isn't the right category; happy to repost wherever you prefer.)
Reproduction
Plugin: dsh-web-search-pro@0.1.14-alpha.1 (plain npm tarball), which imports jsdom.
resolve.paths() returns null for a builtin-shadowed name, so for...of null throws:
TypeError: createRequire.resolve.paths is not a function or its return value is not iterable
at ResolutionRouter.routeScoped (.../dsh-app-boot/lib/index.js:1422)
at ResolutionRouter.routePath (...:1554)
at Function.wrappedFilename [as _resolveFilename] (...:1771)
at Object.<anonymous> (.../node_modules/tr46/index.js:3:18)
Note the CJS hook routePath forwards the raw request to routeScoped with no builtin filter, unlike barePackageName(), which does call isBuiltin().
So native Node resolves it fine, but the router intercepts the require and cannot route it — because it derives search paths from resolve.paths() (which treats punycode as a builtin and yields nothing) instead of the actual resolution.
Impact
Any plugin that pulls in a CJS dependency requiring a builtin-shadowed name (punycode and similar) cannot load on 0.1.7-rc.2. jsdom → whatwg-url → tr46 is a very common chain, so this may affect a broad set of plugins.
Suggested fix
Guard every resolve.paths() call with ?? [] (restore 0.1.5 behavior).
Apply the same builtin filter in the CJS routePath hook that barePackageName() already applies, so builtin-shadowed specifiers delegate to native resolution or skip routing.
Add a regression test that loads a plugin whose dependency graph requires punycode/ (anything depending on tr46/jsdom).
Workaround for plugin authors (until this is fixed)
Removing jsdom from the dependency graph is enough — the failure only needs some CJS module on the plugin's resolution scope to require('punycode/'), and jsdom → whatwg-url → tr46 is the usual route. I replaced jsdom with node-html-parser (deps: entities, css-select — no tr46/punycode/whatwg-url anywhere), and the same plugin then activates normally on 0.1.7-rc.2.
To check whether your own dependency tree is exposed:
A null result is exactly the value the router fails to iterate. You can also just grep the installed tree for tr46, whatwg-url, or punycode.
One caveat if you migrate off jsdom: node-html-parser parses <pre>/<code> bodies as raw text, so textContent returns inner markup where a real DOM flattens it (<pre><code>x</code></pre> yields "<code>x</code>" instead of "x"). Re-parsing the element's rawText (the original escaped source) restores DOM semantics for nested elements, entities, and escaped tag lookalikes alike. Switching to linkedom, cheerio, or node-html-parser all avoid the bug; pick whichever fits your parsing needs.
Verification of the workaround
Differential harness over 20 HTML cases (headings, lists, tables, JSON-LD, entities, nested <pre><code>, fragments without <body>, invalid selectors): the old jsdom-backed extractor and the new node-html-parser-backed one produce identical output.
End-to-end on an isolated 0.1.7-rc.2 profile: the plugin goes from failed to import to activating fully (11 tools registered, browser service injected) — identical to its behavior on 0.1.5-rc.2.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
A plugin whose dependency graph contains a CommonJS module that requires
punycode/fails to load on dsh 0.1.7-rc.2 withfailed to import, while the identical plugin activates normally on dsh 0.1.5-rc.2. The fault is in@deepseek-ai/dsh-app-boot's newResolutionRouter, which was rewritten for 0.1.7 and no longer guardscreateRequire(...).resolve.paths().(Issues are disabled on this repo, so I'm reporting here — apologies if Q&A isn't the right category; happy to repost wherever you prefer.)
Reproduction
dsh-web-search-pro@0.1.14-alpha.1(plain npm tarball), which importsjsdom.jsdom→whatwg-url→tr46→require("punycode/").browser: injectedweb-search-pro (dsh-web-search-pro): failed to importBoth runs used an isolated
DSH_HOMEand a profile with the webserver moved off the default port.Defect 1 — unguarded
resolve.paths()throws and masks the real errorResolutionRouter.routeScoped(0.1.7-rc.2,lib/index.js:1422):resolve.paths()returnsnullfor a builtin-shadowed name, sofor...of nullthrows:Note the CJS hook
routePathforwards the raw request torouteScopedwith no builtin filter, unlikebarePackageName(), which does callisBuiltin().The 0.1.5 equivalent site was guarded:
0.1.7-rc.2 has six
resolve.pathscall sites; five are unguarded (lines 1247, 1422, 1475, 2019, 3263 — only 883 keeps?? []).Defect 2 — the underlying resolution failure:
Cannot find module 'punycode/'Adding
?? []to all five sites removes the TypeError and exposes the real error:punycodeis installed in the profile and resolves/loads natively:So native Node resolves it fine, but the router intercepts the require and cannot route it — because it derives search paths from
resolve.paths()(which treatspunycodeas a builtin and yields nothing) instead of the actual resolution.Impact
Any plugin that pulls in a CJS dependency requiring a builtin-shadowed name (
punycodeand similar) cannot load on 0.1.7-rc.2.jsdom→whatwg-url→tr46is a very common chain, so this may affect a broad set of plugins.Suggested fix
resolve.paths()call with?? [](restore 0.1.5 behavior).routePathhook thatbarePackageName()already applies, so builtin-shadowed specifiers delegate to native resolution or skip routing.punycode/(anything depending ontr46/jsdom).Workaround for plugin authors (until this is fixed)
Removing
jsdomfrom the dependency graph is enough — the failure only needs some CJS module on the plugin's resolution scope torequire('punycode/'), andjsdom → whatwg-url → tr46is the usual route. I replacedjsdomwithnode-html-parser(deps:entities,css-select— notr46/punycode/whatwg-urlanywhere), and the same plugin then activates normally on 0.1.7-rc.2.To check whether your own dependency tree is exposed:
A
nullresult is exactly the value the router fails to iterate. You can also just grep the installed tree fortr46,whatwg-url, orpunycode.One caveat if you migrate off
jsdom:node-html-parserparses<pre>/<code>bodies as raw text, sotextContentreturns inner markup where a real DOM flattens it (<pre><code>x</code></pre>yields"<code>x</code>"instead of"x"). Re-parsing the element'srawText(the original escaped source) restores DOM semantics for nested elements, entities, and escaped tag lookalikes alike. Switching tolinkedom,cheerio, ornode-html-parserall avoid the bug; pick whichever fits your parsing needs.Verification of the workaround
<pre><code>, fragments without<body>, invalid selectors): the old jsdom-backed extractor and the new node-html-parser-backed one produce identical output.failed to importto activating fully (11 tools registered, browser service injected) — identical to its behavior on 0.1.5-rc.2.Environment
@deepseek-ai/dsh@0.1.7-rc.2,@deepseek-ai/dsh-app-boot@0.1.7-rc.2@deepseek-ai/dsh@0.1.5-rc.2,@deepseek-ai/dsh-app-boot@0.1.5-rc.3All reactions