Repository navigation
Releases: ejfkdev/dj
Release list
v0.6.4
v0.6.4 RSC 路由探测并发化 + 无产出预算(真实站点 4~7 倍提速)
主要变更
-
RSC(Next.js Flight)路由探测改为按波并发派发
原先探测在 processResults 内同步内联执行(fetch → 插件分发 → 递归
processResults → 下一层探测),而主循环每轮末尾的 jsWg.Wait() 会连带等待
整条探测链,于是同一批任务中的探测被迫全部串行。实测某 Next.js 站点:
112 次探测耗掉 95s,占整次扫描 107s 的 89%;-c 8 时探测速率 1.15 次/秒,
提到 -c 32 也只到 2.11 次/秒——提高并发只能重叠不同 worker 各自的探测链。
现在按 8 个一波并发派发(rscWaveSize),生命周期纳入 probeWg/inflight
(收尾等待机制不变,结果不丢),并发上限仍由 Fetcher 全局信号量 =
--concurrency 统一管控。 -
探测预算:同一 host 连续无产出就停止继续探测
按 host 记账:一波探测若没带来任何新入队 URL(tryEnqueue 成功计数
newDiscoveries 的增量)就累加 missStreak,达到 rscMissBudget(16) 且该 host
已派发 >= rscMinProbesPerHost(16) 后停止探测该 host。
针对 catch-all 型站点:它们对任意编造路径都返回 200 + 应用外壳,于是
payload 里被误认成路由的 token(如一批 commit SHA)"探测有效"却带不回任何
chunk——实测这类 100 次探测贡献 0 个 JS。真实 MPA 的每个路由都会带来新 URL,
产出会不断把计数清零。参数集中在 pipeline.go 的 RSC 段落顶部,便于调整。
实测(同一时刻、同一站点对照,旧二进制 vs 新二进制)
- 79.4s → 20.4s;网络状况较好时 107s → 14.8s
- 实际派发探测数 112 → 28
44(跳过 6884) - 提取结果一致:jsURLs 与 summary 逐字节相同(21 条),仅 1 条 provenance 因
发现顺序不同换了记录方
其他
- CI 的 gh release create 现在带 --title "${{ github.ref_name }}":release 列表
显示纯版本号(此前 name 为空时 GitHub 会回退显示正文首行,也就是中文 tag 标题) - 补齐 app.go / main.go 缺失的行尾换行,gofmt -l 现在干净
测试台(570 夹具全量复测:428 PASS / 119 WARN / 23 FAIL,与基线逐夹具判定
完全一致,0 处变化)
- 23 个 FAIL 均为此前已证明静态不可达的既有项(webpack-mf 运行时切片、snowpack 上下文块(目录列表探测已按约定移除)、turbopack 15.5.23、d2admin、vue-pure-admin)
- 覆盖规模:74 类框架 / 572 个实测版本
v0.6.3
v0.6.3 浏览器身份一致性、CDN 主机正则修复、JS 响应内容校验
主要变更
-
浏览器身份改为同源自洽(提取量大幅提升的关键修复)
此前默认「随机 TLS 指纹 + 固定 Chrome UA」,两者互相矛盾:随机指纹会被
CDN/WAF 按 JA3 拦截,而 UA 又声称是 Chrome。现在默认使用固定 Chrome
指纹(uTLS HelloChrome_Auto),且 UA、Sec-Ch-Ua/Sec-Ch-Ua-Mobile/
Sec-Ch-Ua-Platform 全部取自同一浏览器画像;HEAD 探测(source map、
Content-Type 预检)也走同一画像(旧实现用 client.Head,完全不带 uTLS)。
实测某反爬站点:随机指纹 11 个 JS → 固定 Chrome 画像 476 个。
--random-tls 可显式开启逐请求轮换(Chrome/Firefox/Safari/Edge/iOS),
--no-random-tls 保留为无效果的兼容参数。 -
CDN 主机前缀正则修复(此前该通道近乎失效)
旧的//host.tld/模式只允许两级域名且必须以 / 结尾,
cdn.static.example.co.uk、g.alicdn.com 这类真实 CDN 主机全部失配,
裸文件名补全通道等于没启用。现改为支持多级域名(对齐 pydj/jsdj 的写法),
路径段仍不含 . 以排除文件后缀。 -
JS 响应内容校验:只统计真正的 JS
真实站点上以 .js 结尾的追踪端点会返回 image/gif(1px 像素)、
application/xml 或 0 字节空响应,此前只要 URL 以 .js 结尾就计入结果,
提取数量被虚高(某站点 117 个结果里 43 个是 GIF、11 个是 XML、13 个是空响应)。
新增三层判定:Content-Type 明确非 JS(图片/字体/音视频/CSS/XML/XHTML)直接拒绝;
魔数嗅探(GIF8/PNG/JPEG/<?xml/<!DOCTYPE/<html);类型含糊时用 JS 词法特征
兜底(前 8KB 内 function/=>/var/let/const/import/export 等)。
同时移除「空响应体 HTML 例外」与通配符 URL 入队。 -
探测生命周期管理 + 确定性输出
source map 探测纳入在飞任务计数:主循环在计数归零时零开销继续,
非零时最多等 5s,取代此前不分情况固定 sleep 500ms——既消除了
「探测未回队就退出」导致的计数抖动,也让夹具扫描提速 2~5x。
最终输出的 jsURLs / jsDetails / htmlEntries 按 URL 排序,同一站点
多次运行结果字节一致(此前顺序随机)。
文档
- README(中英)实测站点计数全部按「响应体确为 JavaScript」重新核验后更新
其他
- 取消跟踪 .zcode/ 规划文件(agent 工作区状态,不属于仓库内容)
测试台(570 夹具全量复测:428 PASS / 119 WARN / 23 FAIL,与改动前基线完全一致,无回归)
- 23 个 FAIL 均为此前已证明静态不可达的既有项(webpack-mf 运行时切片、snowpack 上下文块(目录列表探测已按约定移除)、turbopack 15.5.23、d2admin、vue-pure-admin)
- 覆盖规模:74 类框架 / 572 个实测版本
v0.6.2
v0.6.2 Vite+(vite-plus)支持与 rspack 2.x 运行时标记
主要变更
- VitePlugin 新增 .vite/manifest.json 构建清单探测:vite 风格页面(含 module script / modulepreload)按固定文件名约定探测站点根清单,解析全部入口与产物 JS(与 EmpPlugin 的 emp.json 探测同模式,非目录列表);Vite MPA/SSR 与开启 build.manifest 的项目受益
- 支持 Vite+(VoidZero vite-plus,
vp build= 标准 Vite 8/Rolldown 产物):无需新插件,实测夹具一次通过 - WebpackPlugin Precheck 增加 rspackChunk / _rspack 标记:rspack 2.0 起运行时全局由 webpackChunk* 改名 rspackChunk*
测试台(570 夹具全量复测:428 PASS / 119 WARN / 23 FAIL,与改动前基线完全一致,无回归)
- 新增夹具全部通过:vite-plus 0.3.1、rspack 2.2.3、vite 8.3.0、webpack 5.110.3、rollup 4.63.2、rolldown 1.2.8、rsbuild 2.0.15/2.1.13/2.2.5(2.x 默认基于 Rspack)、turbopack(next) 16.3.5
- 23 个 FAIL 均为此前已证明静态不可达的既有项(webpack-mf 运行时切片、snowpack 上下文块(目录列表探测已按约定移除)、turbopack 15.5.23、d2admin、vue-pure-admin)
- 覆盖规模:74 类框架 / 572 个实测版本(README 矩阵同步更新)
v0.6.1
v0.6.1 帮助、版本与 xyz-go 依赖升级
帮助与版本体验
- 帮助信息全面改版:标题行含程序名 + 版本 + 描述,紧随 GitHub 仓库地址与 MPL-2.0 许可证;扫描全部 flag(含 --cache 旧语法与 --json 全局 flag)逐条列出;新增 xyz-go 命令区(serve/mcp/completion 及其参数);Notes 补充环境代理变量与退出码说明
- 使用示例扩展:增加 dj serve + curl 调用 /scan、dj mcp http --stateless、shell completion 示例
- 新增
dj version命令:与 -v/--version 等价 - 版本号回退机制:未通过 ldflags 注入时从 Go 构建信息读取主模块版本(go install @ 显示真实标签版本)
依赖升级
- xyz-go v0.2.3 → v0.3.2:界面语言 i18n(固定 zh-CN,--xyz.lang 仍可覆盖);scan -h 中整数/切片字段显示 integer / strings (repeatable);CliHints.After 让 scan -h 末尾附带说明块(URL 位置参数、--headers 重复覆盖、环境代理、旧拼写兼容、退出码)
- v0.3.2 新增 Daemon 标记与 serve/mcp 的裸 --key=v 通道默认透传,dj 暂不采用
修复
- 全面审计非法输入不再 panic:无协议输入(如 dj 0h)返回干净的 invalid URL 用法错误(退出码 1);管线内 URL 切片点均有前缀/长度防护
v0.6.0
v0.6.0 集成 xyz-go:一次定义,CLI + HTTP API + MCP 三种使用方式
主要变更
- 引入 xyz-go v0.2.3,扫描功能以一条 spec.Define("scan") 同时生成三个前端
- scan 注册为默认子命令:
dj <url> [flags]由库原生整串转发(URL 为第一段时);flag 前置(dj -f json <url>)仍走兼容壳自动补 scan - CLI:新增规范写法
dj scan <url>;旧写法dj [flags] <url>保留为兼容壳,全部 flag、旧别名(--ua、-debug)、--cache 旧语法与退出码行为(用法错误=1)不变 - HTTP:
dj serve在同一端口提供 POST /scan、/healthz、/openapi.json、/mcp(--addr/--bearer/--tls-cert/--tls-key/--cors 可配置) - MCP:
dj mcp stdio|sse|http三种传输,scan 即 MCP 工具,structuredContent 返回结构化结果、textContent 返回 Markdown 报告(xyz-go v0.2.3 起 textContent 不再带尾随换行) - 输出兼容:md/json/text 三种输出与旧版逐字节一致(仅 CLI 末尾多一个换行)
修复
- 无协议 URL(如
dj abc)此前会触发管线 panic,HTTP/MCP 服务模式下会打崩整个进程;现在 handler 前置校验绝对 URL,缓存路径计算增加长度防护 dj scan缺 URL 时输出清晰用法错误而不是崩溃- CI release 步骤重新拉取 annotated tag(checkout 会用裸 commit SHA 覆盖 tag ref,导致 --notes-from-tag 回退到 commit 消息)
其他
- CI ldflags 同时注入 main.version 与 xyz-go 版本号
- README(中英)新增 HTTP API 与 MCP 章节及使用示例
v0.5.21
ci: checkout tags in release job so --notes-from-tag resolves
v0.5.20
Changes
feat: markdown as default output + HTML entry discovery in results
- default output format changed to markdown (md); -f text now emits a
bare one-URL-per-line JS list (summary sections live in md/json) - md output gains a trailing '## HTML Entries' section listing the
standalone HTML pages discovered during multi-page/iframe recursion
(with discovering plugin and source URL); json gains htmlEntries - Intermediate now carries FromURL so HTML entry provenance shows the
page that referenced each entry (HTMLPivot/MF/EMP/Next/Trunk populate it) - help text and READMEs updated (md default, text = bare list)
docs: add supported frameworks/loaders matrix with verified versions
Lists 73 frameworks / loading models across 562 verified versions,
grouped into bundlers, microfrontends, meta frameworks/SSR,
Rust/WASM frontends, admin templates, and spec/polyfills. Each entry
shows the verified version range (first ~ last, with count).
v0.5.19
Changes
feat: -v/--version + --concurrency, Next sortedPages probes; harness judge fix
CLI:
- -v/--version prints version and exits; help header includes GitHub URL
- -c/--concurrency N controls fetch concurrency (default 8, was hardcoded
48); range 1-256
Pipeline: - concurrency semaphore now reads Pipeline.fetchConcurrency (default 8)
NextJSPlugin: - when _buildManifest carries sortedPages, issue fixed-name probes per
page (RSC flight + plain HTML) — for SSR deployments where the page
provider script is server-injected and absent from static refs
(turbopack 15.5 provider shape)
Harness (dj_demo): - compare.py literal_ref: bare-basename variant only for single-dir
bundle paths (assets/, static/js/) so import("./X.js") same-dir
literals count as referenced; earlier whole-dir variant overcounted
unreachable page-scoped workers and was reverted - full regression: PASS 419 / WARN 117 / FAIL 23 (same FAIL set as
before; the turbopack /_app provider files remain provably
unreachable in static export)
v0.5.18
Changes
fix: scoped chunk maps, transient fetch retries, bounded concurrency, MF root probes
Deep analysis of remaining FAIL clusters (sub-agent reads of bundle
sources + server logs) found the misses were mostly not missing regexes
but three systemic gaps:
- scoped map extraction (W1): webpack4 dual-map runtimes (JS hash map +
CSS twin map in one file) were parsed via whole-content scan, so the
CSS map overwrote JS hashes -> every probe 404. requireU branch now
captures the two maps from the matched block and parses only them. - transient fetch retries (V1): connection timeouts against low-backlog
static servers silently dropped URLs and their whole lazy-import
sub-chains. processJSContent now retries up to 3x with backoff and
retries 429/5xx once. Bounded fetch concurrency (48) prevents the
connect-storm that caused the timeouts. - MF remote entry root derivation: generalize /index.html
convention probing to any layout (also covers the root-level
remoteEntry.js of vite-plugin-federation 0.0.3, plus webpack-layout
remotes with their own entry page).
Harness (80 frameworks / 560 versions):
PASS 414 -> 419, FAIL 30 -> 23, WARN 116 -> 118
flipped: vue-element-admin 2v PASS (72+73 chunks), amis 4v PASS,
tdesign-starter 2v PASS, pig-ui WARN (expected all found),
vite-plugin-federation 6v PASS (incl 0.0.3), vue-pure-admin v7 PASS
still FAIL after proof-of-unreachability: webpack-mf 10v (remote
runtime chunk zero references; even a real browser 404s the remote),
snowpack 10v (no-listing policy), turbopack 15.5.23 (provider file
zero references in the whole tree), d2admin (UEditor chain + mobile
subpage static-unreachable), vue-pure-admin v6 (wasm worker runtime-
assembled name)
v0.5.17
Changes
feat: unquoted prefetch/modulepreload links, config path literals, umi quoted-key maps
- HTMLScriptPlugin: prefetch/modulepreload link extraction accepts
unquoted attribute values (),
mass prefetch lists in compressed admin templates (jeecg 205 links) - UniversalURLPlugin: config/manifest path literals
("/cdn/font-icon/x.js", "assets/xxx.js", tinymce language_url);
monaco/amis resource arrays etc. - WebpackPlugin: federation branch gains quoted-numeric map keys
("185":"58b15d06" / "185":"p__Welcome" — umi3 async layout)
and dynamic suffix ((.async).js)
Harness (80 frameworks, 560 versions):
PASS 414 / FAIL 30 / WARN 116
flipped: ant-design-pro 5v FAIL->PASS, jeecg 2v FAIL->WARN
(expected all found), umi/ng-alain stable
remaining FAIL clusters: snowpack 10 (no-listing policy), webpack-mf
10 (runtime-slice statically unreachable), plus single-version
leftovers: amis 6.13, d2admin, pig-ui, tdesign-starter, turbopack
15.5.23, vite-plugin-federation 0.0.3, vue-element-admin x2,
vue-pure-admin x2 (next round)