v1.1.0
Added
- 管理器
/_forge/manager(仅app_debug=true):参考 laravel 版实现的可视化面板——层级总览、路由搜索与详情、levels 与全局设置的编辑落盘。- 两层访问控制:非 debug 环境根本不注册管理器路由(判定走
App::isDebug()——think 只认APP_DEBUG=0/1,读原始 env 会把生产当开发),再叠加manager_allowed_ips来源 IP 白名单。白名单读取处(array)归一,并区分「键缺失」(默认仅回环)与「显式 null」(不限制)——think 的Config::get点号路径按isset()判定,显式 null 会被误读成缺失。 - 只读 API:
GET api/routes(含别名条目、剔 HEAD)、GET api/config(展示值与守卫生效值同源)。路由名统一带forge.manager.前缀,由 common 的排除规则兜住,不进任何元信息输出。 - 页面零依赖:包内自包含模板 +
ManagerPageRenderer直出,不依赖topthink/think-view(think\View只是 Manager 壳)。注入数据带JSON_HEX_TAG,层级 description 里的</script>无法截断脚本块;占位符未替换完即抛错,不交付半个页面。 - 写盘比 laravel 版更严三处:复用 common 生成器后由
ThinkConfigFileStyler只重排外壳为 think 风格,写前做值不变性校验(分别回读适配前后产物,严格相等才落盘);覆盖前按本包纪律备份.bak-{Ymd-His};成功后清runtime/config.php与路由元信息缓存两级,改完下一个请求即生效。classifier是闭包无法序列化,配置了它时拒存 422 而非静默抹平。 - 生成物的值是字面量,不再包
Env::get:页面上改了就该立即生效,包回去会被.env旧值遮蔽成「改了没生效」;该取舍写进生成文件头部注释,需要.env驱动的手工改回。 - 新增配置项
manager_allowed_ips(默认['127.0.0.1', '::1'])。此前已发布过配置的项目没有该键,落到仅本机默认,不会因升级而放开访问。
- 两层访问控制:非 debug 环境根本不注册管理器路由(判定走
Fixed
- 层级
endpoint_middleware传单值字符串时被静默忽略(端点裸奔):ForgeService注册层级元信息端点时用裸值is_array()守卫,配置写'endpoint_middleware' => 'auth'(与 think 的->middleware()同形的合法写法)会判false直接跳过注册——不报错、不崩溃,该层级元信息端点连中间件都没挂,开发者却以为它受保护,属危险方向的静默失效。现与摘要端点侧、laravel 版同口径在入口(array)归一(null→[],保持「不限制」语义)。该配置项不经route-forge/common任何读取路径(common 1.1.1 的归一化只覆盖match.prefix/match.middleware/middleware_match),故归一只能落在适配层。- 回归测试:层级 / 摘要端点各补一条「单值字符串写法仍被拦截」用例;反向验证过还原旧写法时层级端点返回 200 且正常吐出数据。
- 文档:README 配置表与
config/forge.php注释把endpoint_middleware写明为「数组或单个字符串都接受」。
- 依赖下限
route-forge/common^1.1.1→^1.1.2:管理器的配置保存路径需要 1.1.2 的生成侧单值归一。页面里把match.prefix/match.middleware写成单值字符串(与 think 的->middleware()同形的直觉写法)时,1.1.1 会在exportInlineArray(array)的类型声明上TypeError,表现为保存返回 500「配置写入失败」,真因只出现在应用日志里。已补端到端回归用例锁住该写法能保存成功并落盘为单元素数组。
完整记录见 CHANGELOG.md。