Compare commits

...

49 Commits

Author SHA1 Message Date
xiaojunnuo 9ffea32176 chore: 批量升级各包依赖版本并统一代码工具链
本次提交统一升级了多个包的依赖版本,包括:
1. 升级prettier到3.3.3、eslint及其相关插件到最新兼容版本
2. 更新rollup、typescript、typeorm等构建和运行时依赖
3. 调整部分包的依赖移除冗余依赖项,统一项目开发构建工具版本
2026-06-22 00:13:13 +08:00
xiaojunnuo f32c99d4a1 refactor(plugins): 部分插件改用运行时导入依赖替代静态导入
将所有插件内的静态依赖导入改为通过access.importRuntime动态导入,并调整package.json依赖顺序
2026-06-21 23:43:19 +08:00
xiaojunnuo 1f1b1858c7 chore: 增加清理依赖缓存提示 2026-06-21 22:32:51 +08:00
xiaojunnuo 42fcb91f2e chore: 完善第三方依赖动态加载 2026-06-20 00:35:13 +08:00
xiaojunnuo 01568ca148 feat: 通过插件配置懒加载依赖,动态加载第三方依赖包,精简安装镜像大小 2026-06-19 17:44:57 +08:00
xiaojunnuo 0d97ad67c5 chore: 1 2026-06-17 00:39:04 +08:00
xiaojunnuo c94a5537a3 chore: 1 2026-06-17 00:26:50 +08:00
xiaojunnuo d88dfc197e chore: 1 2026-06-17 00:04:24 +08:00
xiaojunnuo f709c05c0d build(ui): 重构Dockerfile支持多架构 2026-06-16 23:41:40 +08:00
xiaojunnuo 2c609da7a1 build: release 2026-06-16 23:15:03 +08:00
xiaojunnuo d770c7bd08 chore: 1 2026-06-16 23:09:33 +08:00
xiaojunnuo b9ccd4a8a0 chore: 1 2026-06-16 22:30:21 +08:00
xiaojunnuo 8875e8059f chore: ncurses-base 退格键 ^H的问题 2026-06-16 00:27:32 +08:00
xiaojunnuo 6490366c68 chore: 1 2026-06-16 00:21:24 +08:00
xiaojunnuo c278946771 chore(nettest): 修复跨平台端口测试匹配逻辑 2026-06-16 00:15:42 +08:00
xiaojunnuo 1562d9de36 chore: 1 2026-06-15 23:39:47 +08:00
xiaojunnuo 5bb0990abb chore: 1 2026-06-15 23:32:32 +08:00
xiaojunnuo bfd3cacc68 perf: 优化ACME账号字段的选择提示 2026-06-15 23:30:13 +08:00
xiaojunnuo c7e1163d59 chore: 改回dnsResultOrder不使用默认ipv4 2026-06-15 23:26:20 +08:00
xiaojunnuo fba7aeb71b Merge branch 'v2-dev' of https://github.com/certd/certd into v2-dev 2026-06-15 23:24:46 +08:00
xiaojunnuo c66a2bd77a perf: 基础镜像改成node:22-trixie-slim,对网络兼容性更好 2026-06-15 23:24:06 +08:00
xiaojunnuo ed58ae3c53 perf: 优化阿里云API网关增加翻页查询 2026-06-15 10:02:02 +08:00
xiaojunnuo 194463bea9 perf: dns默认ipv4first 2026-06-14 23:18:37 +08:00
xiaojunnuo 260f5ae777 fix: 修复jdk证书格式的问题 2026-06-14 23:18:17 +08:00
xiaojunnuo e85d824337 chore:1 2026-06-14 22:21:07 +08:00
xiaojunnuo e17fc39709 chore: 1 2026-06-14 22:14:59 +08:00
xiaojunnuo da9b297b12 chore: 1 2026-06-14 21:46:06 +08:00
xiaojunnuo 807dfcd57a chore: 尝试使用 node:22.22-trixie-slim 2026-06-14 21:43:18 +08:00
xiaojunnuo 0a410db52a build: publish 2026-06-14 21:30:16 +08:00
xiaojunnuo 4501095106 build: trigger build image 2026-06-14 21:30:05 +08:00
xiaojunnuo bc731e4fb1 v1.41.4 2026-06-14 21:29:12 +08:00
xiaojunnuo 53561d2755 build: prepare to build 2026-06-14 21:25:11 +08:00
xiaojunnuo e913fe509c chore: 优化代码格式 2026-06-14 20:59:38 +08:00
xiaojunnuo a3a215b7ae perf(plugin): 增加 Dynadot DNS and access 插件
新增Dynadot域名解析提供商插件,包含API授权配置和DNS记录增删查功能
2026-06-14 17:23:24 +08:00
xiaojunnuo 56f2949ac5 chore: 1 2026-06-14 15:07:38 +08:00
xiaojunnuo c1b5a35f90 fix: 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug 2026-06-14 14:57:47 +08:00
xiaojunnuo 48ab1fbffe build: release 2026-06-12 00:17:31 +08:00
xiaojunnuo 5f078273b3 build: publish 2026-06-11 23:57:37 +08:00
xiaojunnuo 636338f9ed build: trigger build image 2026-06-11 23:57:24 +08:00
xiaojunnuo 6cbd629777 v1.41.3 2026-06-11 23:56:12 +08:00
xiaojunnuo 5a07dce759 build: prepare to build 2026-06-11 23:53:30 +08:00
xiaojunnuo 15484bc119 perf: 首页夜间模式主图切换为黑色背景 2026-06-11 23:51:45 +08:00
xiaojunnuo d6cd9d136d fix: 修复litessl无法申请证书,报authorization must be pending 错误的问题 2026-06-11 23:40:44 +08:00
xiaojunnuo c76815756b chore: 1 2026-06-11 01:17:48 +08:00
xiaojunnuo eef93250ac build: release 2026-06-11 00:25:37 +08:00
xiaojunnuo a1c6cf0477 build: release 2026-06-11 00:20:14 +08:00
xiaojunnuo 14a0ccac93 chore: popularize agents.md 2026-06-11 00:07:02 +08:00
xiaojunnuo 9439743b7e build: publish 2026-06-10 23:39:06 +08:00
xiaojunnuo acbac6a9c3 build: trigger build image 2026-06-10 23:38:54 +08:00
187 changed files with 3503 additions and 982 deletions
-36
View File
@@ -1,36 +0,0 @@
# 后端规则
主包:`packages/ui/certd-server`。后端使用 Node.js、ESM、TypeScript、MidwayJS 3、Koa、TypeORM,默认 better-sqlite3,同时支持 PostgreSQL 和 MySQL,并通过 `@certd/midway-flyway-js` 使用类似 Flyway 的 SQL 迁移机制。
详细入口、模块和验证命令见 `.codex/repo-map.md`
## 默认开发配置
- HTTP 端口:`7001`
- HTTPS 端口:`7002`
- 默认 SQLite 数据库:`./data/db.sqlite`
- 默认文件根目录:`./data/files`
## 数据与迁移
- 后端使用 TypeORM 实体加 SQL 迁移。
- 重点查看 `packages/ui/certd-server/src/modules/**/entity/*.ts``packages/ui/certd-server/db/migration/*.sql`
- 默认配置中 `synchronize: false`,涉及表结构变更时应添加或更新迁移脚本,不要依赖 TypeORM 自动同步。
## 文件上传
使用 `/basic/file/upload` 上传文件后,接口返回的是临时缓存 key。业务保存表单或设置时,后端必须调用 `FileService.saveFile(userId, key, "public" | "private")` 转成永久文件 key 后再入库/入设置;不要直接保存 `tmpfile_key_...`,否则后续回显或下载会失效。
## Service 与事务
- 后端方法参数超过 3 个时,尽量改为对象参数传入。
- 需要传入 `manager` / `EntityManager` 做事务传播的方法,必须使用对象参数,不要把 `manager` 作为位置参数藏在参数列表末尾。
- 后端 service 层只有存在事务链路传播需求时才定义 `ctx`,不要为了将来可能需要而提前给普通方法加 `ctx`
- 事务链路方法统一采用 `method(ctx, req)` 形式,`ctx` 放第一位并承载 `manager?: EntityManager` 等横切上下文,业务参数放在 `req` 对象里,例如 `settleCommission({ manager }, { tradeId, userId, amount })`
- 无事务链路需求的普通查询、纯函数和简单私有方法继续使用明确参数。
- service 内部需要根据事务上下文选择 Repository 时,优先使用 `BaseService.getRepo(ctx, EntityClass)`;不要在业务方法里反复写 `ctx.manager?.getRepository(Entity) || this.xxxRepository`
- 拿到 repo 后 save/update/delete/find 都能做,不需要再包一层 `saveEntity` 之类的单一用途方法。
- service 拼接用户与项目范围查询条件时,优先使用 `BaseService.buildUserProjectQuery(userId, projectId)`;不要直接写 `{ userId, projectId }`,否则 `projectId` 为空时可能把 `null`/`undefined` 带入 TypeORM 条件,导致查询或 update 不符合预期。
- `ctx` 类型统一从 `BaseService` 导出的 `ServiceContext` 复用,不要在每个 service 里重复定义。
- 需要“有事务则复用、无事务则开启”时,使用 `BaseService.transactionWithCtx(ctx, callback)``ctx.manager` 存在则直接执行 callback,否则自动 `this.transaction()`。不要在业务代码里手写 `if (ctx.manager) { ... } else { await this.transaction(...) }`
- 新增方法注意不要与 `BaseService` 基类方法签名冲突,例如 `delete(id)` vs `BaseService.delete(ids, where?)`ts-node 下会直接 TS2416 编译报错。冲突时改用具体名称如 `deleteById`
-26
View File
@@ -1,26 +0,0 @@
# 代码风格规则
## 基本原则
- 中文 README 在部分 PowerShell 环境中可能显示乱码;`README_en.md` 可读性更好,且包含同样的高层项目说明。
- 根包管理器是 pnpm,不要引入 npm/yarn lockfile。
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象。
- 注意本地数据和配置里可能包含凭据、证书材料等敏感信息。
## 注释
本仓库代码注释优先使用中文,尤其是解释业务规则、兼容逻辑、协议细节和隐藏风险时;除非文件已有明确英文注释风格或引用外部英文术语,否则不要新增英文说明性注释。
## 可读性
代码可读性优先于短写法。遇到包含业务分支的复杂三元表达式、内联对象、链式调用或条件组合时,优先拆成命名清晰的中间变量、独立分支或小函数,让读代码的人能一眼看出业务意图;不要为了少写几行把逻辑压成难读的一坨。
在对象字面量、查询条件或函数参数里不要内联调用多层 helper,例如 `{ domain, ...this.buildUserProjectQuery(userId, projectId) }`。应先用命名变量承接结果,例如 `const userProjectQuery = this.buildUserProjectQuery(userId, projectId)`,再在对象里展开 `...userProjectQuery`,让条件构造和业务字段都更容易阅读。
## DRY
遵守 DRY 原则:同一业务规则、字段转换、权限判断、Repository 选择、事务传播、金额计算等逻辑不要在多个地方复制粘贴。第二次出现时可以先保持清晰,第三次出现前应优先抽成局部 helper、service 方法或已有公共工具;抽象要服务于减少真实重复和降低修改风险,不要为了形式上的“复用”制造过度设计。
## 单一职责
遵守单一职责原则:一个方法只负责一个清晰的业务步骤或技术步骤。流程编排方法可以串联多个步骤,但具体的校验、计算、持久化、状态变更、展示数据组装应尽量拆到命名明确的小方法中;不要让一个方法同时承担查询、校验、计算、写库、格式化返回等过多职责。
-31
View File
@@ -1,31 +0,0 @@
# 前端规则
主包:`packages/ui/certd-client`。前端使用 Vue 3、Vite、TypeScript、Ant Design Vue、Fast Crud、Pinia、vue-router、vue-i18n、Tailwind/Windi 相关样式工具。
详细入口、路由、状态、API、视图、locale 和验证命令见 `.codex/repo-map.md`
## 禁跑命令
- 不要运行前端 `pnpm tsc` / `vue-tsc`:当前依赖组合中 `vue-tsc@1.8.27` 会直接抛内部错误 `Search string not found: "/supportedTSExtensions = .*(?=;)/"`,不是有效的项目类型检查结果。
- 前端暂不跑单元测试;当前 `test:unit` 只是占位脚本。
## 格式化与校验
前端 TS/Vue/locale 等文件改动后,优先只对本次改动文件运行项目现有自动格式化/修复:
- Prettier`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`
- ESLint`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
不要为了格式化无关文件而扩大 diff。项目保留了 `tslint` 依赖,但当前主要使用 ESLint + Prettier。
## Fast Crud 页面
- 列表管理、后台管理、记录查询、CRUD 表格类页面,默认优先使用 Fast Crud(`@fast-crud/fast-crud``fs-crud``useFs``createCrudOptions`)实现。
- 只有轻量只读展示、强交互自定义界面或已有页面模式明确不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明原因。
- 开发或重构这类页面前,先读取 `.trae/skills/fast-crud-page-dev/SKILL.md`,按仓库内 Fast Crud 页面拆分与验证方式实现。
- 页面内嵌 Fast Crud 表格时,要显式给外层容器稳定高度或 `flex: 1; min-height: 0` 的撑满链路;Fast Crud 依赖外部元素高度,不能只依赖表格默认高度。
- 后台管理列表里展示或筛选用户字段时,优先参考 `packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx``userId` 字段模式:前端使用 `table-select` + `/sys/authority/user/getSimpleUserByIds` 字典回显和搜索;不要为了展示用户名让后端列表接口额外 `fillSimpleUser` / `userDisplay`,除非该接口本身就是用户端业务列表且已有明确模式。
## 对话框
前端对话框里只做纯确认时可以使用 `Modal.confirm`;只要对话框里有字段输入、表单校验或提交字段,统一使用 `useFormDialog` / `openFormDialog`,不要在 `Modal.confirm``content` 里手写输入框。
-42
View File
@@ -1,42 +0,0 @@
# 流水线与插件规则
项目最关键的架构概念是证书流水线。核心导出、关键抽象、插件目录和共享 helper 位置见 `.codex/repo-map.md`
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
## 改动归属
修改证书申请、验证、部署或通知行为时,先判断改动属于哪里:
- ACME client 代码
- pipeline 核心抽象
- 后端 module/service/entity/controller
- 某个具体插件实现
- 前端 view/form/schema
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
## ACME / EAB
- 公共 EAB(尤其是 Google EAB)可能只能创建一次 ACME 账号。要跨用户复用公共 EAB,应保存并复用同一个 ACME account private key`accountUrl` 如果存到 `userContext` 里,只能视为当前用户缓存,因为 `userContext` 跟用户 id 走。
- ACME 协议的 `newAccount` 支持 `onlyReturnExisting`。使用同一个 account private key 调用 `newAccount({ onlyReturnExisting: true })` 可以取回已创建账号的 URL,且不会再次消费 EAB。
- 修改 EAB 的 `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示用户刷新账号私钥。
## 插件开发技能
仓库内置了 Certd 插件开发技能,供 Trae 和 Codex 共用:
- Trae 入口:`.trae/skills`
- Codex 入口:`.codex/skills`
其中 `.codex/skills` 是指向 `.trae/skills` 的目录链接,不要复制出第二份技能内容。更新技能时只维护 `.trae/skills` 下的原始文件,Codex 会通过 `.codex/skills` 读取同一份内容。
当前技能包括:
- `access-plugin-dev`:开发 Access 授权插件
- `dns-provider-dev`:开发 DNS Provider 插件
- `fast-crud-page-dev`:开发或重构前端 Fast Crud 列表管理页面
- `task-plugin-dev`:开发 Task 部署任务插件
- `plugin-converter`:将插件转换为 YAML 配置
做插件相关任务时,先读取对应技能目录下的 `SKILL.md`,再进入具体实现。若用户在插件开发中指出更好的做法,应总结并更新对应技能。
-26
View File
@@ -1,26 +0,0 @@
# 测试与验证规则
实现新功能或修复行为缺陷前,先补对应单元测试,并先运行测试确认它处于失败状态;再实现功能或修复代码,反复运行聚焦单元测试直到通过。若某项改动确实不适合先写单元测试,应在回复中说明原因和替代验证方式。
后补单元测试时,应先基于对正确行为的实际预期编写测试,而不是为了迎合现有实现改写预期;如果运行后出现红灯,且通过测试需要修改已有实现,应先向用户确认这是确实的 bug,还是原本需求/既有行为就是如此;确认后再修改原始实现,避免把测试补充变成未经确认的行为改动。
## 后端单测
- 后端纯单元测试用例放在 `src` 目录内,并尽量与被测文件相邻,例如 `src/utils/random.test.ts`
- 对应 `test:unit` 只跑 `src/**/*.test.ts`,构建/打包配置应排除这些 `*.test.ts` 文件。
- 单元测试需要 mock ESM 静态 import 时,优先使用 `esmock`,不要为了测试把业务代码改成构造函数注入或把逻辑挪到调用方。
- 各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`
## 运行方式
单个 monorepo 包运行单元测试时,优先使用 `corepack pnpm --dir <包目录> test:unit`,例如:
- `corepack pnpm --dir packages\ui\certd-server test:unit`
- `corepack pnpm --dir packages\core\basic test:unit`
- `corepack pnpm --dir packages\plugins\plugin-lib test:unit`
也可以用包名过滤,例如 `corepack pnpm --filter @certd/ui-server test:unit`
前端 `packages\ui\certd-client` 暂时不跑单元测试。前端改动优先使用 Prettier/ESLint 做改动文件验证。
优先对改动包运行聚焦测试;只有跨包影响明显时再考虑全 monorepo 构建。
-106
View File
@@ -1,106 +0,0 @@
# Certd 仓库地图
本文档由 Codex 子智能体只读探索后整理,用于后续开发时快速定位代码。进入仓库仍应先读取根目录 `AGENTS.md`,本文件只作为导航补充。
## 顶层结构
Certd 是 pnpm + lerna-lite monorepo。
- `package.json`:根脚本与 workspace 元信息
- `pnpm-workspace.yaml`workspace 匹配规则,包含 `packages/**``packages/ui/**`
- `lerna.json`lerna-lite 配置
- `docs`VitePress 文档站
- `docker`Docker 安装和运行相关文件
- `packages/core/acme-client`ACME 协议客户端
- `packages/core/basic`:共享基础工具
- `packages/core/pipeline`:流水线核心抽象、插件模型、执行上下文
- `packages/libs`:共享集成库
- `packages/plugins/plugin-lib`:证书、DNS Provider、格式转换等插件共享能力
- `packages/plugins/plugin-cert`:证书插件包入口
- `packages/ui/certd-server`:后端 Midway 服务
- `packages/ui/certd-client`:前端 Vue/Vite 管理台
- `packages/pro`:商业版独立 Git 工作区,需在该目录内单独检查状态
运行时或生成产物通常包括根目录 `node_modules``logs``output``lerna-debug.log``tmp-certd-client-vite*.log`,以及后端 `packages/ui/certd-server/data``packages/ui/certd-server/logs`、各包 `dist`、插件 metadata/yaml 导出结果。
## 常用验证
- 根目录启动后端生产模式:`pnpm run start:server`
- 后端开发服务:`corepack pnpm --dir packages\ui\certd-server dev`
- 后端聚焦单测:`corepack pnpm --dir packages\ui\certd-server test:unit`
- 后端完整测试:`corepack pnpm --dir packages\ui\certd-server test`
- 后端构建:`corepack pnpm --dir packages\ui\certd-server build`
- 前端开发服务:`corepack pnpm --dir packages\ui\certd-client dev`
- 前端构建:`corepack pnpm --dir packages\ui\certd-client build`
- 前端改动文件格式化:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`
- 前端改动文件 ESLint 修复:`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
不要主动运行 `pnpm install`。前端不要运行 `pnpm tsc` / `vue-tsc`,当前依赖组合中 `vue-tsc@1.8.27` 会抛无效内部错误;前端 `test:unit` 也只是占位。
## 后端地图
主包:`packages/ui/certd-server`
- `bootstrap.js`Midway 启动入口,使用 `@midwayjs/bootstrap`
- `src/configuration.ts`:Midway 主配置,注册组件和全局中间件
- `src/config/config.default.ts`:端口、HTTPS、静态文件、cron、TypeORM、Flyway、上传、JWT、Swagger 默认配置
- `src/config/loader.ts`:读取 `.env``.env.<env>.yaml`,支持 `certd_` 前缀环境变量覆盖嵌套配置
- `src/modules`:业务模块根目录,例如 `basic``cert``cname``cron``login``monitor``open``pipeline``plugin``suite``sys`
- `src/controller`API 入口,按 `basic``user``sys``openapi` 分组
- `db/migration`SQL 迁移目录,TypeORM `synchronize: false`,表结构变更应配套迁移 SQL
测试使用 Mocha + Node `assert/strict`,纯单测放在 `src/**/*.test.ts`,尽量与被测文件相邻。可参考 `src/utils/random.test.ts``src/controller/basic/app-controller.test.ts``src/modules/pipeline/service/pipeline-service.test.ts`
## 前端地图
主包:`packages/ui/certd-client`
- `vite.config.ts`Vite 配置,dev 端口 `3008``/api``/certd/api` 代理到后端 `127.0.0.1:7001`
- `src/main.ts`:Vue 启动入口,注册 AntDV、Vben、router、全局组件、插件和偏好设置
- `src/App.vue`:根组件,包含 `AConfigProvider``FsFormProvider``router-view`
- `src/router/index.ts``src/router/resolve.ts`:路由入口,使用 `createWebHashHistory`
- `src/router/source/modules/certd.ts`Certd 主业务路由
- `src/store`Pinia store,主要有 `user``project``settings``plugin`
- `src/api/service.ts`Axios 封装
- `src/api/tools.ts`:错误与响应工具
- `src/views/certd`:核心业务视图,例如 `pipeline``cert``monitor``access``notification``open``project``suite``wallet`
- `src/locales`:国际化入口与语言包
列表管理、后台管理、记录查询、CRUD 表格页面优先使用 Fast Crud。开发前读取 `.trae/skills/fast-crud-page-dev/SKILL.md`。常见拆分是 `api.ts``crud.tsx``index.vue`。可参考 `src/views/certd/access``src/views/sys/suite/user-suite/crud.tsx``src/views/certd/wallet/index.vue`。内嵌 `fs-crud` 时要给外层稳定高度或完整 `flex: 1; min-height: 0` 链路。
## 流水线与插件地图
核心入口:`packages/core/pipeline/src/index.ts`,导出 `core``dt``access``registry``plugin``context``decorator``service``notification`
- `packages/core/pipeline/src/plugin`:任务插件抽象,例如 `AbstractTaskPlugin``IsTaskPlugin``TaskInput``pluginRegistry`
- `packages/core/pipeline/src/access`:授权插件抽象,例如 `BaseAccess``IsAccess``AccessInput``accessRegistry`
- `packages/core/pipeline/src/dt/pipeline.ts``Pipeline``Stage``Task``RunStrategy` 等流水线数据结构
- `packages/core/pipeline/src/core`:执行器、上下文、运行历史、文件存储等
- `packages/core/pipeline/src/service`:CNAME、事件、配置、邮件、URL 等 pipeline service 接口
- `packages/ui/certd-server/src/plugins`:后端内置服务商、DNS、部署、通知等插件
- `packages/ui/certd-server/src/plugins/plugin-cert`:证书申请核心插件
- `packages/ui/certd-server/src/plugins/plugin-lib`:后端插件 helper/access
- `packages/plugins/plugin-lib/src/cert``CertReader``CertConverter`、DNS Provider 公共能力
- `packages/plugins/plugin-lib/src/cert/dns-provider``AbstractDnsProvider``dnsProviderRegistry``DomainParser`
插件开发技能入口:
- `.trae/skills/dns-provider-dev/SKILL.md`DNS Provider 插件
- `.trae/skills/task-plugin-dev/SKILL.md`Task 部署任务插件
- `.trae/skills/access-plugin-dev/SKILL.md`Access 授权插件
- `.trae/skills/plugin-converter/SKILL.md`:插件转 YAML 配置
改动归属判断:
- ACME 协议、EAB、账号、订单、挑战流程:优先看 `packages/core/acme-client``packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts`
- 流水线执行、任务生命周期、输入输出、注册机制:看 `packages/core/pipeline`
- 单个云厂商 DNS 验证、证书部署、API 调用失败:改对应 `packages/ui/certd-server/src/plugins/plugin-xxx`
- 通用证书读取、DNS Provider 公共能力、格式转换:改 `packages/plugins/plugin-lib`
- 后端业务数据、接口、实体、权限、迁移:改 `packages/ui/certd-server/src/modules``src/controller`
- 表单、列表、插件配置 UI:改 `packages/ui/certd-client/src/views/certd` 及对应 `src/api`
原则:如果只是单个服务商或部署目标的问题,不动共享 pipeline/core;只有可复用的公共语义或跨插件一致行为,才考虑上移到 `packages/core/pipeline``packages/plugins/plugin-lib`
## Git 注意事项
子智能体探索时根仓库 `git status --short` 为空。`packages/pro` 也是独立仓库且当时未显示未提交改动,但曾出现无法删除 `packages/pro/.git/index.lock` 的警告;后续操作 pro 仓库前应先检查该锁文件或占用状态。
+3 -2
View File
@@ -37,5 +37,6 @@ pnpm-lock.yaml
.studio/
# Certd 推广报告,仅本地使用
/popularize/
/popularize/reports/
output/
.uploads/
@@ -0,0 +1,412 @@
# 插件依赖按需加载方案
## 背景与目标
### 当前问题
- `packages/ui/certd-server/node_modules` 包含 50+ 个插件的所有依赖,体积庞大
- 大量云厂商 SDK(AWS、阿里云、腾讯云、华为云等)只在特定插件中使用
- 用户通常只使用少数几个插件,但必须安装所有依赖
### 目标
实现依赖的按需下载和加载:
1. 插件依赖独立管理,不占用主 `node_modules` 空间
2. 只有当用户首次使用某插件时,才动态下载该插件需要的依赖
3. 依赖安装完成后,通过 `await import()` 从独立路径加载
4. 保持现有插件代码的最小改动
## 当前架构分析
### 插件加载机制
- 插件位于 `packages/ui/certd-server/src/plugins/` 下(50+ 个插件目录)
- `AutoLoadPlugins` 类在启动时扫描 `dist/plugins` 目录并动态导入
- 插件注册到不同的 registry`accessRegistry`, `pluginRegistry`, `dnsProviderRegistry`
- 插件代码已经使用 `await import()` 进行懒加载(如 `await import("@aws-sdk/client-acm")`
### 重型依赖分布
`packages/ui/certd-server/package.json` 分析,以下依赖体积大且仅特定插件使用:
**云厂商 SDK(按插件分组):**
- **AWS 插件**`@aws-sdk/client-acm`, `@aws-sdk/client-cloudfront`, `@aws-sdk/client-iam`, `@aws-sdk/client-route-53`, `@aws-sdk/client-s3`, `@aws-sdk/client-sts`
- **阿里云插件**`@alicloud/openapi-client`, `@alicloud/pop-core`, `@alicloud/tea-typescript`, `@alicloud/fc20230330`
- **腾讯云插件**`tencentcloud-sdk-nodejs`, `cos-nodejs-sdk-v5`
- **华为云插件**`@huaweicloud/huaweicloud-sdk-cdn`, `@huaweicloud/huaweicloud-sdk-core`
- **Azure 插件**`@azure/arm-dns`, `@azure/identity`
- **Google Cloud 插件**`@google-cloud/dns`, `@google-cloud/publicca`
- **火山引擎插件**`@volcengine/openapi`, `@volcengine/tos-sdk`
**网络/工具库:**
- `ssh2`, `socks`, `socks-proxy-agent`SSH 相关插件)
- `ali-oss`, `qiniu`, `basic-ftp`(存储/传输插件)
- `nodemailer`(邮件通知插件)
**通用依赖(保留在主 package.json):**
- `@midwayjs/*` 系列(框架核心)
- `@certd/*` 系列(项目内部包)
- `axios`, `lodash-es`, `dayjs`, `js-yaml` 等基础工具
## 设计方案
### 架构概览
```
packages/ui/certd-server/
├── package.json # 主依赖(框架、通用工具)
├── node_modules/ # 主依赖安装目录
├── optional-deps/ # 新增:可选依赖管理目录
│ ├── package.json # 可选依赖总配置(用于 pnpm install
│ ├── pnpm-lock.yaml # 可选依赖锁文件
│ └── node_modules/ # 可选依赖安装目录
├── src/
│ └── modules/
│ └── dependency/ # 新增:依赖管理模块
│ ├── dependency-manager.ts # 核心:依赖管理器
│ ├── dependency-registry.ts # 依赖注册表(插件 -> 依赖映射)
│ └── types.ts # 类型定义
```
### 核心组件
#### 1. 依赖管理器(DependencyManager
**职责:**
- 检查依赖是否已安装
- 动态执行 `pnpm install` 安装缺失依赖
- 提供从 `optional-deps/node_modules` 加载依赖的方法
- 并发控制:避免多个插件同时触发安装
**关键方法:**
```typescript
class DependencyManager {
// 确保依赖已安装,返回依赖模块
async ensureAndImport<T>(packageName: string): Promise<T>
// 检查依赖是否已安装
async isInstalled(packageName: string): Promise<boolean>
// 安装依赖(带锁,避免并发)
async installDependencies(packages: string[]): Promise<void>
// 从 optional-deps/node_modules 加载依赖
async loadModule<T>(packageName: string): Promise<T>
}
```
**实现要点:**
- 使用文件锁(如 `proper-lockfile`)防止并发安装
- 安装前检查 `optional-deps/node_modules/{packageName}` 是否存在
- 安装命令:`pnpm install --dir optional-deps --ignore-workspace`
- 加载时使用绝对路径:`import('file:///absolute/path/to/optional-deps/node_modules/package')`
#### 2. 依赖注册表(DependencyRegistry
**职责:**
- 维护插件名称到依赖列表的映射
- 提供依赖查询接口
**数据结构:**
```typescript
interface PluginDependencyConfig {
pluginName: string;
dependencies: {
packageName: string;
version: string;
optional?: boolean; // 是否可选(安装失败不阻塞)
}[];
}
// 示例注册
dependencyRegistry.register('plugin-aws', [
{ packageName: '@aws-sdk/client-acm', version: '^3.964.0' },
{ packageName: '@aws-sdk/client-cloudfront', version: '^3.964.0' },
{ packageName: '@aws-sdk/client-route-53', version: '^3.964.0' },
]);
```
#### 3. 插件集成
**改造现有插件代码:**
改造前(`plugin-aws/libs/aws-client.ts`):
```typescript
const { ACMClient, ImportCertificateCommand } = await import("@aws-sdk/client-acm");
```
改造后:
```typescript
import { DependencyManager } from "../../../modules/dependency/dependency-manager.js";
const depManager = new DependencyManager();
const { ACMClient, ImportCertificateCommand } = await depManager.ensureAndImport("@aws-sdk/client-acm");
```
**简化方案(推荐):**
创建辅助函数,减少改动量:
```typescript
// src/modules/dependency/import-helper.ts
export async function importOptionalDep<T>(packageName: string): Promise<T> {
const depManager = new DependencyManager();
return await depManager.ensureAndImport<T>(packageName);
}
// 插件中使用
import { importOptionalDep } from "../../../modules/dependency/import-helper.js";
const { ACMClient } = await importOptionalDep("@aws-sdk/client-acm");
```
### 实施步骤
#### 阶段一:基础设施搭建
1. 创建 `optional-deps/` 目录结构
2. 生成 `optional-deps/package.json`(包含所有可选依赖)
3. 实现 `DependencyManager` 核心逻辑
4. 实现依赖安装锁机制
5. 编写单元测试
#### 阶段二:依赖迁移
6. 从主 `package.json` 移除可选依赖
7. 将依赖添加到 `optional-deps/package.json`
8. 创建依赖注册表,映射插件到依赖
#### 阶段三:插件改造
9. 创建 `import-helper.ts` 辅助函数
10. 逐步改造插件代码,使用 `importOptionalDep` 加载依赖
11. 优先改造重型依赖(AWS、阿里云、腾讯云等)
#### 阶段四:测试与优化
12. 端到端测试:验证依赖按需安装和加载
13. 性能优化:缓存已加载的模块
14. 错误处理:安装失败时的降级策略
15. 文档:编写使用说明和迁移指南
## 关键技术决策
### 1. 依赖分组策略
**选择:按插件分组**
- 每个插件声明自己需要的依赖
- 优点:职责清晰,易于维护
- 缺点:可能有重复依赖(但 pnpm 会去重)
**备选:按功能分组**
- 将依赖按功能分组(如 "aws-deps", "aliyun-deps"
- 优点:更细粒度控制
- 缺点:增加复杂度
### 2. 安装触发时机
**选择:首次使用时触发**
- 在插件的 `execute()``getClient()` 方法中触发安装
- 优点:真正的按需加载
- 缺点:首次使用有延迟
**备选:启动时预检查**
- 启动时扫描启用的插件,预安装依赖
- 优点:避免运行时延迟
- 缺点:可能安装不需要的依赖
### 3. 依赖路径解析
**选择:使用绝对路径 + `file://` 协议**
```typescript
const modulePath = path.resolve(__dirname, '../../optional-deps/node_modules', packageName);
return await import(`file://${modulePath}/index.js`);
```
**原因:**
- Node.js ESM 要求明确的 URL 格式
- 避免模块解析冲突
### 4. 并发控制
**选择:文件锁 + 内存锁双重保护**
- 使用 `proper-lockfile` 锁定 `optional-deps/` 目录
- 内存中使用 `Map` 记录正在安装的依赖
- 避免多个插件同时触发安装
### 5. 错误处理
**策略:**
- 安装失败时记录日志,抛出明确的错误信息
- 提供手动安装命令提示:`请运行: cd optional-deps && pnpm install`
- 支持降级:某些非核心依赖安装失败时,插件可以部分功能可用
## 验证方案
### 单元测试
1. 测试 `DependencyManager.isInstalled()` 正确检测依赖状态
2. 测试 `DependencyManager.installDependencies()` 成功安装依赖
3. 测试并发安装时的锁机制
4. 测试从 `optional-deps/node_modules` 加载模块
### 集成测试
1. 清空 `optional-deps/node_modules`
2. 启动服务,验证不触发安装
3. 调用 AWS 插件,验证触发安装并成功加载
4. 再次调用,验证不重复安装
5. 验证主 `node_modules` 体积减少
### 性能测试
1. 测量首次安装依赖的耗时
2. 测量后续加载的耗时(应该与正常 import 相近)
3. 对比改造前后的 `node_modules` 大小
## 风险与挑战
### 1. 首次使用延迟
**风险:** 用户首次使用插件时需要等待依赖安装(可能几十秒)
**缓解:**
- 在 UI 上显示安装进度
- 提供预安装命令:`pnpm run install-optional-deps`
- 文档说明首次使用会有延迟
### 2. 离线环境
**风险:** 离线环境无法下载依赖
**缓解:**
- 提供完整安装包(包含所有可选依赖)
- 支持手动复制 `node_modules`
### 3. 版本冲突
**风险:** 可选依赖与主依赖版本冲突
**缓解:**
- 使用 `--ignore-workspace` 隔离安装
- 定期同步主依赖版本
### 4. TypeScript 类型
**风险:** 动态导入的类型推断
**缓解:**
- 保留 `@types/*` 在主 `devDependencies`
- 使用泛型和类型断言
## 预期收益
1. **空间节省:**`node_modules` 体积减少 60-70%(估算)
2. **安装速度:** 初始 `pnpm install` 速度提升 3-5 倍
3. **用户体验:** 不使用的插件不占用空间,按需加载
4. **维护性:** 依赖分组清晰,易于管理
## 后续优化
1. **依赖预热:** 在后台预安装常用插件依赖
2. **依赖缓存:** 支持从 CDN 或本地缓存安装
3. **依赖更新:** 提供命令批量更新可选依赖
4. **插件市场:** 支持从远程下载插件及其依赖配置
## 附录:依赖分类清单
### 可选依赖(迁移到 optional-deps/package.json
**AWS 相关(plugin-aws, plugin-aws-cn):**
```json
{
"@aws-sdk/client-acm": "^3.964.0",
"@aws-sdk/client-cloudfront": "^3.964.0",
"@aws-sdk/client-iam": "^3.964.0",
"@aws-sdk/client-route-53": "^3.964.0",
"@aws-sdk/client-s3": "^3.964.0",
"@aws-sdk/client-sts": "^3.990.0"
}
```
**阿里云相关(plugin-aliyun, plugin-lib/aliyun):**
```json
{
"@alicloud/fc20230330": "^4.1.7",
"@alicloud/openapi-client": "^0.4.12",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/pop-core": "^1.7.10",
"@alicloud/sts-sdk": "^1.0.2",
"@alicloud/tea-typescript": "^1.8.0",
"@alicloud/tea-util": "^1.4.10",
"ali-oss": "^6.21.0"
}
```
**腾讯云相关(plugin-tencent, plugin-lib/tencent):**
```json
{
"tencentcloud-sdk-nodejs": "^4.1.112",
"cos-nodejs-sdk-v5": "^2.14.6"
}
```
**华为云相关(plugin-huawei):**
```json
{
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
"@huaweicloud/huaweicloud-sdk-core": "3.1.185",
"@huaweicloud/huaweicloud-sdk-elb": "3.1.185",
"@huaweicloud/huaweicloud-sdk-iam": "3.1.185",
"esdk-obs-nodejs": "^3.25.6"
}
```
**Azure 相关(plugin-azure):**
```json
{
"@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1"
}
```
**Google Cloud 相关(plugin-google, plugin-cert/google):**
```json
{
"@google-cloud/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0"
}
```
**火山引擎相关(plugin-volcengine):**
```json
{
"@volcengine/openapi": "^1.28.1",
"@volcengine/tos-sdk": "^2.9.1"
}
```
**SSH/网络相关(plugin-host, plugin-lib/ssh):**
```json
{
"ssh2": "^1.17.0",
"socks": "^2.8.3",
"socks-proxy-agent": "^8.0.4",
"basic-ftp": "^5.0.5"
}
```
**其他存储/传输(plugin-qiniu, plugin-lib/qiniu):**
```json
{
"qiniu": "^7.12.0"
}
```
**邮件通知(plugin-notification/email):**
```json
{
"nodemailer": "^6.9.16"
}
```
### 主依赖(保留在主 package.json
**框架核心:**
- `@midwayjs/*` 系列
- `@koa/cors`
- `typeorm`, `better-sqlite3`, `mysql2`, `pg`
**项目内部包:**
- `@certd/*` 系列
**通用工具:**
- `axios`, `lodash-es`, `dayjs`, `js-yaml`
- `crypto-js`, `jsonwebtoken`, `bcryptjs`
- `reflect-metadata`, `uuid`, `nanoid`
- 等等
## 总结
本方案通过引入独立的可选依赖管理机制,实现了插件依赖的按需下载和加载。核心思路是:
1. **隔离管理:**`optional-deps/` 目录下维护独立的 `package.json``node_modules`
2. **动态安装:** 通过 `DependencyManager` 在首次使用时触发 `pnpm install`
3. **路径加载:** 使用绝对路径从独立目录加载依赖模块
4. **最小改动:** 通过辅助函数 `importOptionalDep` 简化插件代码改造
该方案可以显著减少主 `node_modules` 体积,提升初始安装速度,同时保持现有架构的兼容性和可维护性。
-13
View File
@@ -1,13 +0,0 @@
你是一名资深nodejs工程师,擅长开发Certd开源系统的任务插件。
certd是一款全自动证书申请部署管理工具,基于流水线的方式,通过里面申请证书插件申请证书,然后将证书传递给下一个部署任务插件,不同的部署任务插件将证书部署到用户的各个应用系统当中。
certd插件分成以下几种类型:
Access:存储用户的第三放应用的授权数据,比如用户名密码,accessSecret 或 accessToken等。同时它里面的方法还负责对接第三方的api接口
Task 部署任务插件,它继承AbstractTaskPlugin类,被流水线调用execute方法,将证书部署到对应的应用上
DnsProvider: DNS提供商插件,它用于在ACME申请证书时给域名添加txt解析记录。
注意事项:
1、使用技能:在开始工作前,请阅读并加载.trae/skills下面的技能,根据skills进行相应的插件开发
2、迭代技能:当开发过程用户提醒你更好的做法时,你需要总结经验,更新相应的skills,让skills越来越完善,能够在以后得新插件开发中具备指导意义。
3、一般调用的api接口文档会比较复杂,你不知道接口是什么时,请务必询问用户,让用户提供API接口文档
4、完成开发后无需测试,通知用户自己去测试
+193 -54
View File
@@ -1,71 +1,210 @@
# Certd 开发 Agent 上下文
这个文件是给在本仓库工作的开发 agent 看的常驻项目说明。进入仓库后先读本文,再按任务读取对应导航或规则文件,避免每次重新全量扫描项目
仓库代码导航、目录地图、常用入口和参考文件见 `.codex/repo-map.md`。更细的开发规则拆在 `.codex/agent-rules/` 下;本文只保留最高优先级的规则、架构边界和工作方式。
进入仓库后先读本文。本文同时包含常驻规则、仓库地图、常用入口和验证命令;不要依赖分散规则文件
## 项目定位
Certd 是支持私有化部署的 SSL/TLS 证书自动化管理平台,提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
Certd 是私有化部署的 SSL/TLS 证书自动化管理平台,提供 Web 管理台和后端服务,用于证书申请、续期、部署、监控、通知和开放 API 集成。
核心产品模型是“证书流水线”:
核心模型是“证书流水线”:
- 通过 ACME 申请证书
- 使用 DNS-01、HTTP-01、CNAME 代理或服务商集成完成域名验证
- 将证书转换或导出 pem、pfx、der、jks、p7b 等格式
- 部署证书到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标
- 通知用户,并监控站点证书过期时间
- 通过 ACME 申请证书
- 完成 DNS-01、HTTP-01、CNAME 代理或服务商验证
- 导出 pem、pfx、der、jks、p7b 等证书格式
- 部署到主机、Nginx、Kubernetes、CDN、云厂商、面板等目标
- 通知用户,并监控站点证书过期时间
系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据始终按私有化/本地部署产品处理,避免泄露本地数据和配置。
## 必读索引
- `.codex/repo-map.md`:仓库结构、后端/前端入口、流水线与插件地图、验证命令
- `.codex/agent-rules/backend.md`:后端、数据库迁移、文件上传、service/事务约定
- `.codex/agent-rules/frontend.md`:前端、Fast Crud、弹窗表单、格式化和禁跑命令
- `.codex/agent-rules/plugins.md`:流水线、插件归属、ACME/EAB、插件开发技能
- `.codex/agent-rules/testing.md`:测试优先策略、单测位置、ESM mock、聚焦验证
- `.codex/agent-rules/coding-style.md`:注释、可读性、DRY、单一职责等通用代码风格
系统会保存证书、云厂商凭据、SSH 信息、API Key 等敏感数据始终按私有化/本地部署产品处理,避免泄露本地数据和配置。
## 仓库边界
这是一个 pnpm + lerna monorepo。核心定位:
- `packages/ui/certd-server`:后端服务
- `packages/ui/certd-client`:前端 Web 管理台
- `packages/core/pipeline`:流水线核心
- `packages/core/acme-client`ACME 协议客户端
- `packages/plugins/plugin-lib`:通用插件辅助能力和证书相关共享代码
`packages/pro/` 是独立 Git 工作区,使用 `packages/pro/.git` 管理。根仓库的 `git status` / `git diff` 默认看不到这里的实际改动;修改商业版代码后,要在 `packages/pro` 目录内单独执行 `git status` / `git diff` 检查。
## 硬性规则
- 根包管理器是 pnpm,不要引入 npm/yarn lockfile。
- 不要主动运行 `pnpm install`;用户会事先准备好 `node_modules`。如果 `pnpm install` 或测试因缺少依赖、TTY、网络问题失败,停止尝试并告知用户环境问题。
- 前端不要运行 `pnpm tsc` / `vue-tsc`;当前依赖组合中 `vue-tsc@1.8.27` 会抛无效内部错误。前端 `test:unit` 只是占位脚本。
- 根仓库是 pnpm + lerna monorepo;不要引入 npm/yarn lockfile
- `packages/pro/` 是独立 Git 工作区;修改商业版代码后,必须在 `packages/pro` 内单独执行 `git status` / `git diff`
- 不要把 `packages/ui/certd-server/data/``logs/`、生成的 metadata/dist 等运行时或构建产物纳入改动,除非任务明确要求。
- 做数据库结构变更时,添加或更新迁移脚本,不要依赖 TypeORM 自动同步
- 做插件相关任务时,先读取对应 `.trae/skills/<skill>/SKILL.md`,再进入具体实现。
- 后端 service 拼接可选 `projectId` 查询条件时,不要直接写 `{ userId, projectId }`;应使用 `BaseService.buildUserProjectQuery(userId, projectId)`,只有 `projectId != null` 时才加入查询条件。
- 例外:分析插件动态依赖时,可以只读查看后端数据目录下的 `./data/.runtime-deps`;该目录用于 runtime-deps 动态安装第三方 SDK,不应纳入提交
## 工作方式
核心包:
- 先读本文;需要代码导航、目录入口、参考文件或验证命令时读 `.codex/repo-map.md`
- 任务涉及后端、前端、插件、测试或代码风格时,先读取 `.codex/agent-rules/` 下对应规则文件,再查看具体代码
- 在 PowerShell 中读取中文、Markdown、locale、文档类文件时,显式使用 `Get-Content -Encoding utf8`;如果仍乱码,再执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()` 后重试
- `packages/ui/certd-server`:后端服务
- `packages/ui/certd-client`:前端 Web 管理台
- `packages/core/pipeline`:流水线核心
- `packages/core/acme-client`ACME 客户端。
- `packages/plugins/plugin-lib`:插件共享能力。
## 仓库地图
- `package.json`:根脚本与 workspace 元信息。
- `pnpm-workspace.yaml`workspace 匹配规则,包含 `packages/**``packages/ui/**`
- `lerna.json`lerna-lite 配置。
- `docs`VitePress 文档站。
- `docker`Docker 安装和运行相关文件。
- `packages/core/acme-client`ACME 协议客户端。
- `packages/core/basic`:共享基础工具。
- `packages/core/pipeline`:流水线核心抽象、插件模型、执行上下文。
- `packages/libs`:共享集成库。
- `packages/plugins/plugin-lib`:证书、DNS Provider、格式转换等插件共享能力。
- `packages/plugins/plugin-cert`:证书插件包入口。
- `packages/ui/certd-server`:后端 Midway 服务。
- `packages/ui/certd-client`:前端 Vue/Vite 管理台。
- `packages/pro`:商业版独立 Git 工作区,需在该目录内单独检查状态。
常见运行时或生成产物:
- 根目录:`node_modules``logs``output``lerna-debug.log``tmp-certd-client-vite*.log`
- 后端:`packages/ui/certd-server/data``packages/ui/certd-server/logs`
- 后端动态依赖:`./data/.runtime-deps`,常见于阿里云 SDK、腾讯云 SDK 等插件第三方依赖。
- 各包:`dist`
- 插件:metadata/yaml 导出结果。
## 常用验证
- 后端聚焦单测:`corepack pnpm --dir packages\ui\certd-server test:unit`
- 后端完整测试:`corepack pnpm --dir packages\ui\certd-server test`
- 前端构建:`corepack pnpm --dir packages\ui\certd-client build`
- 前端改动文件格式化:`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>`
- 前端改动文件 ESLint 修复:`packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
- 后端改动文件 lint fix`corepack pnpm --dir packages\ui\certd-server run lint`
- 其他package lint fix`corepack pnpm --dir packages\xxx\xxxx run lint`
## 通用工作规则
- 先读本文,再按任务读取具体代码或技能文件。
- PowerShell 读取中文、Markdown、locale、文档类文件时使用 `Get-Content -Raw -Encoding UTF8`;仍乱码时先执行 `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()`
- PowerShell 中用 `rg` 搜索含引号、括号、反斜杠的 pattern 时,优先用单引号包裹整个 pattern,例如 `rg 'await import\("tencentcloud-sdk-nodejs' packages/ui/certd-server/src -g '*.ts'`
- 不要主动运行 `pnpm install`;缺依赖、TTY、网络导致安装或测试失败时,停止尝试并说明环境问题。
- 优先沿用现有模块、插件、service、页面模式;不要为形式上的复用制造过度抽象。
- 代码可读性优先于短写法。复杂条件、三元表达式、链式调用、内联对象和多层 helper 调用要拆成命名清晰的中间变量或小方法。
- 方法调用链不要直接塞进另一个方法参数;先用有意义的局部变量承接返回值,再传入下一步。
- 注释优先使用中文,尤其是业务规则、兼容逻辑、协议细节和隐藏风险;文件已有英文风格或引用外部术语时可保持一致。
- 遵守 DRY 和单一职责;第三次出现的业务规则、字段转换、权限判断、Repository 选择、事务传播、金额计算等逻辑,应优先抽成合适 helper 或 service 方法。
## 后端规则
- 后端主包是 `packages/ui/certd-server`,使用 Node.js、ESM、TypeScript、MidwayJS 3、Koa、TypeORM 和 SQL 迁移。
- 做后端任务时,先定位 `packages/ui/certd-server/src/modules` 下的模块,以及相关 entity/service/controller。
- 表结构变更必须添加或更新 `packages/ui/certd-server/db/migration/*.sql`;不要依赖 TypeORM 自动同步。
- 文件上传接口 `/basic/file/upload` 返回临时 key;业务保存前必须调用 `FileService.saveFile(userId, key, "public" | "private")` 转成永久 key,不能直接保存 `tmpfile_key_...`
- 方法参数超过 3 个时,优先改为对象参数。
- 事务链路方法统一用 `method(ctx, req)``ctx` 放第一位并承载 `manager?: EntityManager`,业务参数放 `req` 对象。
- 只有需要事务传播时才定义 `ctx`;普通查询、纯函数和简单私有方法继续使用明确参数。
- 需要按事务上下文取 Repository 时,用 `BaseService.getRepo(ctx, EntityClass)`
- 需要“有事务则复用、无事务则开启”时,用 `BaseService.transactionWithCtx(ctx, callback)`
- 拼接可选 `projectId` 查询条件时,用 `BaseService.buildUserProjectQuery(userId, projectId)`;不要直接写 `{ userId, projectId }`
- `ctx` 类型复用 `BaseService` 导出的 `ServiceContext`
- 新增 service 方法避免与 `BaseService` 方法签名冲突,例如不要用 `delete(id)` 覆盖 `delete(ids, where?)`;改用 `deleteById` 等具体名称。
### 后端地图
- `packages/ui/certd-server/bootstrap.js`Midway 启动入口,使用 `@midwayjs/bootstrap`
- `packages/ui/certd-server/src/configuration.ts`:Midway 主配置,注册组件和全局中间件。
- `packages/ui/certd-server/src/config/config.default.ts`:端口、HTTPS、静态文件、cron、TypeORM、Flyway、上传、JWT、Swagger 默认配置。
- `packages/ui/certd-server/src/config/loader.ts`:读取 `.env``.env.<env>.yaml`,支持 `certd_` 前缀环境变量覆盖嵌套配置。
- `packages/ui/certd-server/src/modules`:业务模块根目录,常见模块包括:
- `basic`
- `cert`
- `cname`
- `cron`
- `login`
- `monitor`
- `open`
- `pipeline`
- `plugin`
- `suite`
- `sys`
- `packages/ui/certd-server/src/controller`API 入口,按 `basic``user``sys``openapi` 分组。
- `packages/ui/certd-server/db/migration`SQL 迁移目录;TypeORM `synchronize: false`,表结构变更必须配套迁移 SQL。
- 后端测试使用 Mocha + Node `assert/strict`;纯单测放在 `src/**/*.test.ts`,可参考 `src/utils/random.test.ts``src/controller/basic/app-controller.test.ts``src/modules/pipeline/service/pipeline-service.test.ts`
## 前端规则
- 前端主包是 `packages/ui/certd-client`,使用 Vue 3、Vite、TypeScript、Ant Design Vue、Fast Crud、Pinia、vue-router、vue-i18n。
- 做前端任务时,先定位 `packages/ui/certd-client/src/views/certd` 下的页面,再找对应 `src/api`
- 做服务商、DNS、部署、通知相关任务时,先看 `packages/ui/certd-server/src/plugins`,再看 `packages/plugins/plugin-lib` 里的共享辅助能力
- 优先沿用现有模块、插件、服务模式,再考虑新增抽象;避免为了形式上的“复用”制造过度设计
- 实现新功能或修复行为缺陷前,优先补对应单元测试并确认红灯,再实现代码并跑聚焦验证。确实不适合先写测试时,在回复中说明原因和替代验证方式
- 后补单元测试时,先按正确行为写预期;如果红灯需要修改既有实现,先向用户确认这是 bug 还是既有需求,避免未经确认改变行为
- 不要运行前端 `pnpm tsc` / `vue-tsc`;当前 `vue-tsc@1.8.27` 会抛无效内部错误。前端 `test:unit` 只是占位脚本,也不要跑
- 前端 TS/Vue/locale 改动后,只对本次改动文件运行现有 Prettier / ESLint`packages\ui\certd-client\node_modules\.bin\prettier.cmd --write <files>``packages\ui\certd-client\node_modules\.bin\eslint.cmd --fix <files>`
- 列表管理、后台管理、记录查询、CRUD 表格页面优先使用 Fast Crud;开发或重构前读 `.trae/skills/fast-crud-page-dev/SKILL.md`
- 只有轻量只读展示、强交互自定义界面或既有页面模式明显不适合 Fast Crud 时,才手写 `a-table` / 自定义列表,并在回复中说明
- 内嵌 Fast Crud 时,外层必须有稳定高度或完整 `flex: 1; min-height: 0` 链路。
- 后台管理列表展示或筛选用户字段时,优先参考 `packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx``userId` 字段模式,用 `table-select` + `/sys/authority/user/getSimpleUserByIds` 字典回显和搜索。
- 对话框里只做确认可用 `Modal.confirm`;有字段输入、表单校验或提交字段时,必须用 `useFormDialog` / `openFormDialog`
### 前端地图
- `packages/ui/certd-client/vite.config.ts`Vite 配置。
- dev 端口:`3008`
- 代理路径:`/api``/certd/api`
- 代理目标:`127.0.0.1:7001`
- `packages/ui/certd-client/src/main.ts`:Vue 启动入口,注册 AntDV、Vben、router、全局组件、插件和偏好设置。
- `packages/ui/certd-client/src/App.vue`:根组件,包含 `AConfigProvider``FsFormProvider``router-view`
- `packages/ui/certd-client/src/router/index.ts``src/router/resolve.ts`:路由入口,使用 `createWebHashHistory`
- `packages/ui/certd-client/src/router/source/modules/certd.ts`Certd 主业务路由。
- `packages/ui/certd-client/src/store`Pinia store,主要包括:
- `user`
- `project`
- `settings`
- `plugin`
- `packages/ui/certd-client/src/api/service.ts`Axios 封装。
- `packages/ui/certd-client/src/api/tools.ts`:错误与响应工具。
- `packages/ui/certd-client/src/views/certd`:核心业务视图,常见目录包括:
- `pipeline`
- `cert`
- `monitor`
- `access`
- `notification`
- `open`
- `project`
- `suite`
- `wallet`
- `packages/ui/certd-client/src/locales`:国际化入口与语言包。
- Fast Crud 页面常见拆分是 `api.ts``crud.tsx``index.vue`;可参考 `src/views/certd/access``src/views/sys/suite/user-suite/crud.tsx``src/views/certd/wallet/index.vue`
## 流水线与插件规则
- 插件是核心能力。新增服务商、DNS 验证、证书部署、通知方式,通常放到插件包或 `packages/ui/certd-server/src/plugins/<plugin-name>/`
- 做服务商、DNS、部署、通知相关任务时,先看 `packages/ui/certd-server/src/plugins`,再看 `packages/plugins/plugin-lib`
- 插件依赖的第三方 SDK 可能通过 runtime-deps 动态安装到后端运行目录 `./data/.runtime-deps`。分析阿里云、腾讯云等 SDK 行为时,需要进入该目录阅读实际安装版本代码。
- 修改证书申请、验证、部署或通知行为时,先判断归属:ACME client、pipeline 核心、后端 module/service/entity/controller、具体插件、前端 view/form/schema。
- 单个服务商或部署目标的问题,不要轻易修改共享 pipeline/core;只有可复用公共语义或跨插件一致行为才上移到 `packages/core/pipeline``packages/plugins/plugin-lib`
- ACME / EAB:公共 EAB 可能只能创建一次账号;跨用户复用公共 EAB 时,应保存并复用同一个 ACME account private key。
- `newAccount({ onlyReturnExisting: true })` 可用同一个 account private key 取回已创建账号 URL,且不会再次消费 EAB。
- 修改 EAB `kid` 后,应重新生成绑定该 `kid` 的 account private key;否则应阻止继续申请并提示刷新账号私钥。
- 插件开发前先读对应技能:`.trae/skills/dns-provider-dev/SKILL.md``.trae/skills/task-plugin-dev/SKILL.md``.trae/skills/access-plugin-dev/SKILL.md``.trae/skills/plugin-converter/SKILL.md`
- `.codex/skills` 是指向 `.trae/skills` 的目录链接;更新技能只维护 `.trae/skills`,不要复制第二份。
### 流水线与插件地图
- `packages/core/pipeline/src/index.ts`:核心导出入口,导出 `core``dt``access``registry``plugin``context``decorator``service``notification`
- `packages/core/pipeline/src/plugin`:任务插件抽象,主要包括:
- `AbstractTaskPlugin`
- `IsTaskPlugin`
- `TaskInput`
- `pluginRegistry`
- `packages/core/pipeline/src/access`:授权插件抽象,主要包括:
- `BaseAccess`
- `IsAccess`
- `AccessInput`
- `accessRegistry`
- `packages/core/pipeline/src/dt/pipeline.ts``Pipeline``Stage``Task``RunStrategy` 等流水线数据结构。
- `packages/core/pipeline/src/core`:执行器、上下文、运行历史、文件存储等。
- `packages/core/pipeline/src/service`:CNAME、事件、配置、邮件、URL 等 pipeline service 接口。
- `packages/ui/certd-server/src/plugins`:后端内置服务商、DNS、部署、通知等插件。
- `packages/ui/certd-server/src/plugins/plugin-cert`:证书申请核心插件。
- `packages/ui/certd-server/src/plugins/plugin-lib`:后端插件 helper/access。
- `packages/plugins/plugin-lib/src/cert``CertReader``CertConverter`、DNS Provider 公共能力。
- `packages/plugins/plugin-lib/src/cert/dns-provider``AbstractDnsProvider``dnsProviderRegistry``DomainParser`
- ACME 协议、EAB、账号、订单、挑战流程:优先看 `packages/core/acme-client``packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/acme.ts`
- 流水线执行、任务生命周期、输入输出、注册机制:看 `packages/core/pipeline`
- 单个云厂商 DNS 验证、证书部署、API 调用失败:改对应 `packages/ui/certd-server/src/plugins/plugin-xxx`
- 通用证书读取、DNS Provider 公共能力、格式转换:改 `packages/plugins/plugin-lib`
- 后端业务数据、接口、实体、权限、迁移:改 `packages/ui/certd-server/src/modules``src/controller`
- 表单、列表、插件配置 UI:改 `packages/ui/certd-client/src/views/certd` 及对应 `src/api`
## 测试与验证
- 实现新功能或修复行为缺陷前,优先补单元测试并先确认红灯,再实现并跑聚焦验证。
- 确实不适合先写测试时,在回复中说明原因和替代验证方式。
- 后补单元测试时,按正确行为写预期;若红灯需要修改既有实现,先向用户确认这是 bug 还是既有需求,避免未经确认改变行为。
- 后端纯单测放在 `src/**/*.test.ts`,尽量与被测文件相邻;`test:unit` 只跑这些文件,构建/打包应排除 `*.test.ts`
- 单测需要 mock ESM 静态 import 时,优先使用 `esmock`,不要为了测试改业务代码结构。
- 各包 `test:unit` 脚本应显式设置 `NODE_ENV=unittest`
- 单包单测优先用 `corepack pnpm --dir <包目录> test:unit`,例如 `corepack pnpm --dir packages\ui\certd-server test:unit`
- 优先对改动包运行聚焦测试或格式化/ESLint;只有跨包影响明显时再考虑更大范围构建。
## 架构边界
插件是核心能力,不是边缘功能。新增服务商、DNS 验证、证书部署、通知方式等能力,通常应该放在插件包里,或放在 `packages/ui/certd-server/src/plugins/<plugin-name>/` 下。
修改证书申请、验证、部署或通知行为时,先判断改动属于 ACME client、pipeline 核心抽象、后端 module/service/entity/controller、具体插件实现,还是前端 view/form/schema。
如果只是某个服务商或部署目标的问题,不要轻易修改共享 pipeline/core 行为,除非确实是可复用的公共能力。
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
### Performance Improvements
* **plugin:** 增加 Dynadot DNS and access 插件 ([a3a215b](https://github.com/certd/certd/commit/a3a215b7ae2b90efcde91270ce4165bbfe77dc64))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
### Bug Fixes
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/certd/certd/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
### Performance Improvements
* 首页夜间模式主图切换为黑色背景 ([15484bc](https://github.com/certd/certd/commit/15484bc119fef7a0ca7f3fdab01d665fde47e688))
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes
+1 -1
View File
@@ -181,7 +181,7 @@ https://certd.handfree.work/
> [50元专业版优惠券限时领取](https://app.handfree.work/subject/#/app/certd/product) https://app.handfree.work/subject/#/app/certd/product
> handfree.work是Certd官方激活码购买平台
> app.handfree.work是Certd官方激活码购买平台
专业版、商业版特权对比
+37
View File
@@ -3,6 +3,43 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
### Performance Improvements
* **plugin:** 增加 Dynadot DNS and access 插件 ([a3a215b](https://github.com/certd/certd/commit/a3a215b7ae2b90efcde91270ce4165bbfe77dc64))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
### Bug Fixes
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/certd/certd/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
### Performance Improvements
* 首页夜间模式主图切换为黑色背景 ([15484bc](https://github.com/certd/certd/commit/15484bc119fef7a0ca7f3fdab01d665fde47e688))
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes
* **cert-plugin:** 修复DNS提供商授权无法回显的bug ([016ae86](https://github.com/certd/certd/commit/016ae865b1d914fe5792e77a08e3ab5358df5f89))
* Parse PEM chain and import certificate chain ([#747](https://github.com/certd/certd/issues/747)) ([454912d](https://github.com/certd/certd/commit/454912d31407d350cbd170953ccbd0564e74fd6c))
### Performance Improvements
* 添加AWS Rate Limit应对措施 ([#748](https://github.com/certd/certd/issues/748)) ([56b8c68](https://github.com/certd/certd/commit/56b8c689ec2b5cff49010a8c765483dd36803e9d))
* 新增站点证书监控从DNS解析记录批量导入功能 ([f9541fa](https://github.com/certd/certd/commit/f9541fab701e01ba57af061da322204c894adfb8))
* 优化 HiPM DNSMgr 插件,添加域名查询双层策略 ([#744](https://github.com/certd/certd/issues/744)) @WUHINS ([0f3f851](https://github.com/certd/certd/commit/0f3f8519e04d95cb848e28b98a3d4fcbed481fce))
### Reverts
* Revert "perf: 添加AWS Rate Limit应对措施 (#748)" (#749) ([5e8bdac](https://github.com/certd/certd/commit/5e8bdac00850bed4f5f2a272bee42c490730ec21)), closes [#748](https://github.com/certd/certd/issues/748) [#749](https://github.com/certd/certd/issues/749)
## [1.41.1](https://github.com/certd/certd/compare/v1.41.0...v1.41.1) (2026-06-05)
### Performance Improvements
+1 -1
View File
@@ -6,7 +6,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
| 官方开源地址: | |
| &nbsp;|官方开源地址: |
| ---- | ---- |
| [Github](https://github.com/certd/certd)| ![](https://img.shields.io/github/stars/certd/certd?logo=github) |
| [Gitee](https://gitee.com/certd/certd) | ![](https://gitee.com/certd/certd/badge/star.svg?theme=dark) |
+48 -47
View File
@@ -33,53 +33,54 @@
| 29.| **彩虹DNS** | 彩虹DNS管理系统授权 |
| 30.| **多吉云** | |
| 31.| **Dokploy授权** | |
| 32.| **farcdn授权** | |
| 33.| **FlexCDN授权** | |
| 34.| **Gcore** | Gcore |
| 35.| **Github授权** | |
| 36.| **godaddy授权** | |
| 37.| **HiPM DNSMgr** | HiPM DNSMgr API Token 授权 |
| 38.| **金山云授权** | |
| 39.| **FTP授权** | |
| 40.| **七牛OSS授权** | |
| 41.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 |
| 42.| **s3/minio授权** | S3/minio oss授权 |
| 43.| **namesilo授权** | |
| 44.| **Next Terminal 授权** | 用于访问 Next Terminal API 的授权配置 |
| 45.| **Nginx Proxy Manager 授权** | 用于登录 Nginx Proxy Manager,并为代理主机证书部署提供授权。 |
| 46.| **1panel授权** | 账号和密码 |
| 47.| **支付宝** | |
| 48.| **白山云授权** | |
| 49.| **宝塔云WAF授权** | 用于连接和管理宝塔云WAF服务的授权配置 |
| 50.| **cdnfly授权** | |
| 51.| **k8s授权** | |
| 52.| **括彩云cdn授权** | 括彩云CDN,每月免费30G[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
| 53.| **LeCDN授权** | |
| 54.| **lucky** | |
| 55.| **猫云授权** | |
| 56.| **plesk授权** | |
| 57.| **长亭雷池授权** | |
| 58.| **群晖登录授权** | |
| 59.| **uniCloud** | unicloud授权 |
| 60.| **微信支付** | |
| 61.| **易盾rcdn授权** | 易盾CDN,每月免费30G[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
| 62.| **易发云短信** | sms.yfyidc.cn/ |
| 63.| **易盾DCDN授权** | https://user.yiduncdn.com |
| 64.| **易支付** | |
| 65.| **proxmox** | |
| 66.| **Spaceship.com 授权** | Spaceship.com API 授权插件 |
| 67.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器授权 |
| 68.| **UCloud授权** | 优刻得授权 |
| 69.| **又拍云** | |
| 70.| **网宿授权** | |
| 71.| **西部数码授权** | |
| 72.| **我爱云授权** | 我爱云CDN |
| 73.| **新网授权(代理方式)** | |
| 74.| **新网授权** | |
| 75.| **新网互联授权** | 仅支持代理账号,ip需要加入白名单 |
| 76.| **Zenlayer授权** | Zenlayer授权 |
| 77.| **GoEdge授权** | |
| 78.| **雨云授权** | https://app.rainyun.com/ |
| 32.| **Dynadot授权** | |
| 33.| **farcdn授权** | |
| 34.| **FlexCDN授权** | |
| 35.| **Gcore** | Gcore |
| 36.| **Github授权** | |
| 37.| **godaddy授权** | |
| 38.| **HiPM DNSMgr** | HiPM DNSMgr API Token 授权 |
| 39.| **金山云授权** | |
| 40.| **FTP授权** | |
| 41.| **七牛OSS授权** | |
| 42.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 |
| 43.| **s3/minio授权** | S3/minio oss授权 |
| 44.| **namesilo授权** | |
| 45.| **Next Terminal 授权** | 用于访问 Next Terminal API 的授权配置 |
| 46.| **Nginx Proxy Manager 授权** | 用于登录 Nginx Proxy Manager,并为代理主机证书部署提供授权。 |
| 47.| **1panel授权** | 账号和密码 |
| 48.| **支付宝** | |
| 49.| **白山云授权** | |
| 50.| **宝塔云WAF授权** | 用于连接和管理宝塔云WAF服务的授权配置 |
| 51.| **cdnfly授权** | |
| 52.| **k8s授权** | |
| 53.| **括彩云cdn授权** | 括彩云CDN,每月免费30G[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
| 54.| **LeCDN授权** | |
| 55.| **lucky** | |
| 56.| **猫云授权** | |
| 57.| **plesk授权** | |
| 58.| **长亭雷池授权** | |
| 59.| **群晖登录授权** | |
| 60.| **uniCloud** | unicloud授权 |
| 61.| **微信支付** | |
| 62.| **易盾rcdn授权** | 易盾CDN,每月免费30G[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
| 63.| **易发云短信** | sms.yfyidc.cn/ |
| 64.| **易盾DCDN授权** | https://user.yiduncdn.com |
| 65.| **易支付** | |
| 66.| **proxmox** | |
| 67.| **Spaceship.com 授权** | Spaceship.com API 授权插件 |
| 68.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器授权 |
| 69.| **UCloud授权** | 优刻得授权 |
| 70.| **又拍云** | |
| 71.| **网宿授权** | |
| 72.| **西部数码授权** | |
| 73.| **我爱云授权** | 我爱云CDN |
| 74.| **新网授权(代理方式)** | |
| 75.| **新网授权** | |
| 76.| **新网互联授权** | 仅支持代理账号,ip需要加入白名单 |
| 77.| **Zenlayer授权** | Zenlayer授权 |
| 78.| **GoEdge授权** | |
| 79.| **雨云授权** | https://app.rainyun.com/ |
<style module>
table th:first-of-type {
+16 -15
View File
@@ -13,21 +13,22 @@
| 9.| **BIND9 DNS** | 通过 SSH 连接到 BIND9 服务器,使用 nsupdate 命令管理 DNS 记录 |
| 10.| **cloudflare** | cloudflare dns provider |
| 11.| **dns.la** | dns.la |
| 12.| **godaddy** | GoDaddy |
| 13.| **HiPM DNSMgr** | HiPM DNSMgr DNS 解析提供商 |
| 14.| **华为云** | 华为云DNS解析提供商 |
| 15.| **namesilo** | namesilo dns provider |
| 16.| **雨云** | 雨云DNS解析提供商 |
| 17.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器 |
| 18.| **腾讯云** | 腾讯云域名DNS解析提供者 |
| 19.| **腾讯云EO DNS** | 腾讯云EO DNS解析提供者 |
| 20.| **西部数码** | west dns provider |
| 21.| **Google Cloud DNS** | Google Cloud DNS提供商 |
| 22.| **Dns提供商Demo** | dns provider示例 |
| 23.| **彩虹DNS** | 彩虹DNS管理系统 |
| 24.| **Spaceship** | Spaceship 域名解析 |
| 25.| **51dns** | 51DNS |
| 26.| **新网互联** | 新网互联 |
| 12.| **Dynadot** | Dynadot DNS提供商 |
| 13.| **godaddy** | GoDaddy |
| 14.| **HiPM DNSMgr** | HiPM DNSMgr DNS 解析提供商 |
| 15.| **华为云** | 华为云DNS解析提供商 |
| 16.| **namesilo** | namesilo dns provider |
| 17.| **雨云** | 雨云DNS解析提供商 |
| 18.| **Technitium DNS Server** | Technitium DNS Server 自建DNS服务器 |
| 19.| **腾讯云** | 腾讯云域名DNS解析提供者 |
| 20.| **腾讯云EO DNS** | 腾讯云EO DNS解析提供者 |
| 21.| **西部数码** | west dns provider |
| 22.| **Google Cloud DNS** | Google Cloud DNS提供商 |
| 23.| **Dns提供商Demo** | dns provider示例 |
| 24.| **彩虹DNS** | 彩虹DNS管理系统 |
| 25.| **Spaceship** | Spaceship 域名解析 |
| 26.| **51dns** | 51DNS |
| 27.| **新网互联** | 新网互联 |
<style module>
table th:first-of-type {
+1 -1
View File
@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.41.2"
"version": "1.41.4"
}
+1 -2
View File
@@ -15,8 +15,7 @@
"vitepress-plugin-lightbox": "^1.0.2"
},
"scripts": {
"start": "lerna bootstrap --hoist",
"start:server": "cd ./packages/ui/certd-server && pnpm start",
"start": "cd ./packages/ui/certd-server && pnpm start",
"devb": "lerna run dev-build",
"i-all": "lerna link && lerna exec npm install ",
"publish": "pnpm run prepublishOnly2 && lerna publish --force-publish=pro/plus-core --conventional-commits && pnpm run afterpublishOnly ",
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/publishlab/node-acme-client/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/acme-client
## [1.41.3](https://github.com/publishlab/node-acme-client/compare/v1.41.2...v1.41.3) (2026-06-11)
### Bug Fixes
* 修复litessl无法申请证书,报authorization must be pending 错误的问题 ([d6cd9d1](https://github.com/publishlab/node-acme-client/commit/d6cd9d136d2812b2335917305f36d6d9414507ad))
## [1.41.2](https://github.com/publishlab/node-acme-client/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/acme-client
+9 -8
View File
@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"module": "./dist/index.js",
"main": "./dist/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.41.2",
"@certd/basic": "^1.41.4",
"@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5",
"axios": "^1.9.0",
@@ -33,18 +33,18 @@
"@types/node": "^20.14.10",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "^4.4.1",
"chai": "^5.1.0",
"chai-as-promised": "^7.1.2",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"jsdoc-to-markdown": "^8.0.1",
"mocha": "^10.6.0",
"nock": "^13.5.4",
"prettier": "^2.8.8",
"prettier": "3.3.3",
"tsd": "^0.31.1",
"typescript": "^5.4.2"
},
@@ -59,7 +59,8 @@
"before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"",
"test:unit": "cross-env NODE_ENV=unittest npm run before-test:unit && cross-env NODE_ENV=unittest tsc -p tsconfig.test.json --skipLibCheck && cross-env NODE_ENV=unittest mocha -t 60000 \"dist-test/**/*.test.js\"",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src"
},
"repository": {
"type": "git",
@@ -76,5 +77,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
@@ -0,0 +1,69 @@
import assert from "node:assert/strict";
import auto from "./auto.js";
import { createCsr, createPrivateRsaKey } from "./crypto/index.js";
declare const describe: any;
declare const it: any;
describe("auto challenge status polling", () => {
it("polls the authorization URL after completing a challenge", async () => {
const [, csr] = await createCsr({ commonName: "example.com" }, await createPrivateRsaKey());
const challenge = {
type: "dns-01",
url: "https://ca.example/chall/1",
token: "token",
};
const authz = {
status: "pending",
identifier: { type: "dns", value: "example.com" },
url: "https://ca.example/authz/1",
challenges: [challenge],
};
const order = {
status: "pending",
url: "https://ca.example/order/1",
finalize: "https://ca.example/order/1/finalize",
authorizations: [authz.url],
};
const polledUrls: string[] = [];
const originalSetTimeout = globalThis.setTimeout;
(globalThis as any).setTimeout = (fn: (...args: any[]) => void) => originalSetTimeout(fn, 0);
try {
const certificate = await auto(
{
logger: { info: () => {} },
sslProvider: "litessl",
getAccountUrl: () => "https://ca.example/acct/1",
createOrder: async () => order,
getAuthorizations: async () => [authz],
getChallengeKeyAuthorization: async () => "key-authorization",
verifyChallenge: async () => {},
completeChallenge: async () => ({ ...challenge, status: "processing" }),
waitForValidStatus: async (item: { url: string }) => {
polledUrls.push(item.url);
return { ...item, status: "valid" };
},
finalizeOrder: async () => ({ ...order, status: "valid", certificate: "https://ca.example/cert/1" }),
getCertificate: async () => "CERTIFICATE",
} as any,
{
csr,
termsOfServiceAgreed: true,
waitDnsDiffuseTime: 0,
challengeCreateFn: async (_authz: any, keyAuthorizationGetter: (challenge: any) => Promise<string>) => ({
challenge,
keyAuthorization: await keyAuthorizationGetter(challenge),
}),
challengeRemoveFn: async () => {},
}
);
assert.equal(certificate, "CERTIFICATE");
assert.deepEqual(polledUrls, [authz.url]);
} finally {
(globalThis as any).setTimeout = originalSetTimeout;
}
});
});
+1 -1
View File
@@ -172,7 +172,7 @@ export default async (client, userOpts) => {
}
challengeCompleted = true;
log(`[auto] [${d}] 等待返回valid状态`);
await client.waitForValidStatus(challenge,d);
await client.waitForValidStatus(authz,d);
});
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/basic
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements
+1 -1
View File
@@ -1 +1 @@
23:34
21:25
+15 -13
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -15,7 +15,9 @@
"test": "mocha --loader=ts-node/esm",
"test:unit": "cross-env NODE_ENV=unittest mocha --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"async-lock": "^1.4.1",
@@ -26,31 +28,31 @@
"iconv-lite": "^0.6.3",
"lodash-es": "^4.17.21",
"log4js": "^6.9.1",
"lru-cache": "^10.0.0",
"lru-cache": "^11.0.1",
"mitt": "^3.0.1",
"nanoid": "^5.0.7",
"node-forge": "^1.3.1",
"nodemailer": "^6.9.3"
"nodemailer": "^6.9.16"
},
"devDependencies": {
"@types/chai": "^4.3.10",
"@types/chai": "^4.3.12",
"@types/lodash-es": "^4.17.12",
"@types/mocha": "^10.0.1",
"@types/mocha": "^10.0.6",
"@types/node-forge": "^1.3.2",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "4.3.10",
"chai": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/pipeline
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/pipeline
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements
+16 -14
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,14 +16,16 @@
"test": "mocha --loader=ts-node/esm",
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"@certd/basic": "^1.41.2",
"@certd/plus-core": "^1.41.2",
"@certd/basic": "^1.41.4",
"@certd/plus-core": "^1.41.4",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"reflect-metadata": "^0.1.13"
"reflect-metadata": "^0.2.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^23.0.4",
@@ -31,23 +33,23 @@
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-terser": "^0.4.3",
"@rollup/plugin-typescript": "^11.0.0",
"@types/chai": "^4.3.10",
"@types/chai": "^4.3.12",
"@types/lodash-es": "^4.17.12",
"@types/mocha": "^10.0.1",
"@types/mocha": "^10.0.6",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "4.3.10",
"chai": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+20 -1
View File
@@ -3,6 +3,7 @@ import { FormItemProps } from "../dt/index.js";
import { HttpClient, ILogger, utils } from "@certd/basic";
import * as _ from "lodash-es";
import { PluginRequestHandleReq } from "../plugin/index.js";
import { IRuntimeDepsService, IServiceGetter } from "../service/index.js";
// export type AccessRequestHandleReqInput<T = any> = {
// id?: number;
@@ -20,6 +21,8 @@ export type AccessInputDefine = FormItemProps & {
export type AccessDefine = Registrable & {
icon?: string;
subtype?: string;
dependPlugins?: Record<string, string>;
dependPackages?: Record<string, string>;
input?: {
[key: string]: AccessInputDefine;
};
@@ -39,13 +42,29 @@ export type AccessContext = {
logger: ILogger;
utils: typeof utils;
accessService: IAccessService;
serviceGetter?: IServiceGetter;
define?: AccessDefine;
};
export abstract class BaseAccess implements IAccess {
ctx!: AccessContext;
runtimeDepsService?: IRuntimeDepsService;
setCtx(ctx: AccessContext) {
async importRuntime(specifier: string) {
if (!this.runtimeDepsService) {
throw new Error("runtimeDepsService 未初始化");
}
return await this.runtimeDepsService.importRuntime(specifier, this.ctx.logger);
}
async setCtx(ctx: AccessContext) {
this.ctx = ctx;
if (!this.runtimeDepsService && this.ctx.serviceGetter) {
this.runtimeDepsService = await this.ctx.serviceGetter.get("runtimeDepsService");
}
if (this.runtimeDepsService && this.ctx.define?.name) {
await this.runtimeDepsService.ensureRuntimeDependencies({ pluginKeys: `access:${this.ctx.define.name}`, logger: this.ctx.logger });
}
}
async onRequest(req: AccessRequestHandleReq) {
@@ -67,7 +67,9 @@ export async function newAccess(type: string, input: any, accessService: IAccess
accessService,
};
}
access.setCtx(ctx);
ctx.define = ctx.define || register.define;
access.runtimeDepsService = (accessService as any).runtimeDepsService;
await access.setCtx(ctx);
access._type = type;
return access;
}
+1 -1
View File
@@ -387,7 +387,7 @@ export class Executor {
}),
serviceGetter: this.options.serviceGetter,
};
instance.setCtx(taskCtx);
await instance.setCtx(taskCtx);
await instance.onInstance();
const result = await instance.execute();
+20 -2
View File
@@ -3,7 +3,7 @@ import { Registrable } from "../registry/index.js";
import { FormItemProps, HistoryResult, Pipeline } from "../dt/index.js";
import { HttpClient, ILogger, utils } from "@certd/basic";
import * as _ from "lodash-es";
import { IEmailService } from "../service/index.js";
import { IEmailService, IRuntimeDepsService, IServiceGetter } from "../service/index.js";
export type NotificationBody = {
userId?: number;
@@ -39,6 +39,8 @@ export type NotificationInputDefine = FormItemProps & {
};
export type NotificationDefine = Registrable & {
needPlus?: boolean;
dependPlugins?: Record<string, string>;
dependPackages?: Record<string, string>;
input?: {
[key: string]: NotificationInputDefine;
};
@@ -78,6 +80,8 @@ export type NotificationContext = {
logger: ILogger;
utils: typeof utils;
emailService: IEmailService;
serviceGetter?: IServiceGetter;
define?: NotificationDefine;
};
export abstract class BaseNotification implements INotification {
@@ -85,6 +89,14 @@ export abstract class BaseNotification implements INotification {
ctx!: NotificationContext;
http!: HttpClient;
logger!: ILogger;
runtimeDepsService?: IRuntimeDepsService;
async importRuntime(specifier: string) {
if (!this.runtimeDepsService) {
return await import(specifier);
}
return await this.runtimeDepsService.importRuntime(specifier, this.logger);
}
async doSend(body: NotificationBody) {
return await this.send(body);
@@ -93,10 +105,16 @@ export abstract class BaseNotification implements INotification {
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
setCtx(ctx: NotificationContext) {
async setCtx(ctx: NotificationContext) {
this.ctx = ctx;
this.http = ctx.http;
this.logger = ctx.logger;
if (!this.runtimeDepsService && this.ctx.serviceGetter) {
this.runtimeDepsService = await this.ctx.serviceGetter.get("runtimeDepsService");
}
if (this.runtimeDepsService && this.ctx.define?.name) {
await this.runtimeDepsService.ensureRuntimeDependencies({ pluginKeys: `notification:${this.ctx.define.name}`, logger: this.logger });
}
}
setDefine = (define: NotificationDefine) => {
this.define = define;
@@ -61,7 +61,8 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
throw new Error("ctx is required");
}
plugin.setDefine(register.define);
plugin.setCtx(ctx);
ctx.define = ctx.define || register.define;
await plugin.setCtx(ctx);
await plugin.onInstance();
return plugin;
}
+20 -2
View File
@@ -10,7 +10,7 @@ import { INotificationService } from "../notification/index.js";
import { Registrable } from "../registry/index.js";
import { IPluginConfigService } from "../service/config.js";
import { TaskEmitter } from "../service/emit.js";
import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
import { ICnameProxyService, IEmailService, IRuntimeDepsService, IServiceGetter, IUrlService } from "../service/index.js";
export type PluginRequestHandleReq<T = any> = {
typeName: string;
@@ -46,6 +46,8 @@ export type PluginDefine = Registrable & {
default?: any;
group?: string;
icon?: string;
dependPlugins?: Record<string, string>;
dependPackages?: Record<string, string>;
input?: {
[key: string]: TaskInputDefine;
};
@@ -73,6 +75,8 @@ export type ITaskPlugin = {
onInstance(): Promise<void>;
execute(): Promise<void | string>;
onRequest(req: PluginRequestHandleReq<any>): Promise<any>;
setCtx(ctx: TaskInstanceContext): Promise<void>;
importRuntime?(specifier: string): Promise<any>;
[key: string]: any;
};
@@ -146,6 +150,14 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
logger!: ILogger;
http!: HttpClient;
accessService!: IAccessService;
runtimeDepsService!: IRuntimeDepsService;
async importRuntime(specifier: string) {
if (!this.runtimeDepsService) {
throw new Error("runtimeDepsService 未初始化");
}
return await this.runtimeDepsService.importRuntime(specifier, this.logger);
}
clearLastStatus() {
this._result.clearLastStatus = true;
@@ -161,11 +173,17 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
}
}
setCtx(ctx: TaskInstanceContext) {
async setCtx(ctx: TaskInstanceContext) {
this.ctx = ctx;
this.logger = ctx.logger;
this.accessService = ctx.accessService;
this.http = ctx.http;
if (!this.runtimeDepsService && this.ctx.serviceGetter) {
this.runtimeDepsService = await this.ctx.serviceGetter.get("runtimeDepsService");
}
if (this.runtimeDepsService && this.ctx.define?.name) {
await this.runtimeDepsService.ensureRuntimeDependencies({ pluginKeys: `plugin:${this.ctx.define.name}`, logger: this.logger });
}
// 将证书加入secret
// @ts-ignore
if (this.cert && this.cert.crt && this.cert.key) {
+1 -1
View File
@@ -32,7 +32,7 @@ export class PipelineEmitter {
}
off(event: string, listener: PipelineEventListener) {
if (this.events[event]) {
this.events[event] = this.events[event].filter((l) => l !== listener);
this.events[event] = this.events[event].filter(l => l !== listener);
}
}
once(event: string, listener: PipelineEventListener) {
@@ -3,6 +3,7 @@ export * from "./cname.js";
export * from "./config.js";
export * from "./url.js";
export * from "./emit.js";
export * from "./runtime.js";
export type IServiceGetter = {
get: <T>(name: string) => Promise<T>;
};
@@ -0,0 +1,27 @@
/**
*
*/
export type ImportRuntime = (specifier: string, logger?: ILogger) => Promise<any>;
/**
*
*/
export type ILogger = {
info: (message: string) => void;
};
/**
*
*/
export type EnsureRuntimeDepsOptions = {
pluginKeys: string | string[];
logger?: ILogger;
};
/**
*
*/
export interface IRuntimeDepsService {
ensureRuntimeDependencies(options: EnsureRuntimeDepsOptions): Promise<any>;
importRuntime: ImportRuntime;
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/lib-huawei
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/lib-huawei
+8 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts",
@@ -12,20 +12,23 @@
"dev-build": "npm run build",
"preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish"
"pub": "npm publish",
"compile": "npm run build",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"axios": "^1.9.0",
"rimraf": "^5.0.5",
"rollup": "^3.7.4"
"rollup": "4.50.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"cross-env": "^7.0.3",
"esmock": "^2.7.5",
"prettier": "^2.8.8",
"prettier": "3.3.3",
"tslib": "^2.8.1"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/lib-iframe
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/lib-iframe
+12 -9
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -15,24 +15,27 @@
"build2": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish"
"pub": "npm publish",
"compile": "npm run build",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"nanoid": "^4.0.0"
"nanoid": "^5.0.7"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.12",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"prettier": "^2.8.8",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/jdcloud
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/jdcloud
+10 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.41.2",
"version": "1.41.4",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
@@ -10,7 +10,10 @@
"build": "npm run before-build && rollup -c ",
"dev-build": "npm run build",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish"
"pub": "npm publish",
"compile": "npm run build",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"author": "",
"license": "Apache",
@@ -21,7 +24,7 @@
"debug": "^3.1.0",
"node-fetch": "^2.1.2",
"querystring": "^0.2.0",
"rollup": "^3.7.4",
"rollup": "4.50.0",
"url": "^0.11.0",
"uuid": "^3.1.0"
},
@@ -29,13 +32,13 @@
"@rollup/plugin-typescript": "^11.0.0",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "^4.1.2",
"chai": "^5.1.0",
"config": "^1.30.0",
"cross-env": "^7.0.3",
"esmock": "^2.7.5",
"js-yaml": "^3.11.0",
"mocha": "^5.0.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"tslib": "^2.8.1"
},
"engines": {
@@ -59,5 +62,5 @@
"fetch"
]
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/lib-k8s
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/lib-k8s
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/lib-k8s
+11 -9
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -16,25 +16,27 @@
"preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"@certd/basic": "^1.41.2",
"@certd/basic": "^1.41.4",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.12",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"prettier": "^2.8.8",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+18 -3
View File
@@ -1,7 +1,22 @@
{
"extends": "./node_modules/mwts/",
"ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"env": {
"jest": true
"mocha": true
},
"rules": {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/lib-server
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/lib-server
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/lib-server
+20 -20
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.41.2",
"version": "1.41.4",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -15,11 +15,11 @@
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
"cov": "midway-bin cov --ts",
"lint": "mwts check",
"lint:fix": "mwts fix",
"prepublish": "npm run build",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"keywords": [],
"author": "greper",
@@ -29,11 +29,11 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.41.2",
"@certd/basic": "^1.41.2",
"@certd/pipeline": "^1.41.2",
"@certd/plugin-lib": "^1.41.2",
"@certd/plus-core": "^1.41.2",
"@certd/acme-client": "^1.41.4",
"@certd/basic": "^1.41.4",
"@certd/pipeline": "^1.41.4",
"@certd/plugin-lib": "^1.41.4",
"@certd/plus-core": "^1.41.4",
"@midwayjs/cache": "3.14.0",
"@midwayjs/core": "3.20.11",
"@midwayjs/i18n": "3.20.13",
@@ -46,28 +46,28 @@
"better-sqlite3": "^11.1.2",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"mwts": "^1.3.0",
"mwtsc": "^1.4.0",
"typeorm": "^0.3.20"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/mocha": "^10.0.1",
"mwts": "^1.3.0",
"mwtsc": "^1.4.0",
"@types/chai": "^4.3.12",
"@types/mocha": "^10.0.6",
"@types/node": "^18",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typeorm": "^0.3.11",
"typeorm": "^0.3.20",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
@@ -169,11 +169,10 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
};
setGlobalProxy(opts);
setGlobalHeaders(this.parseKeyValueText(privateSetting.commonHeaders));
if (privateSetting.dnsResultOrder) {
dns.setDefaultResultOrder(privateSetting.dnsResultOrder as any);
}
if (privateSetting.pipelineMaxRunningCount) {
executorQueue.setMaxRunningCount(privateSetting.pipelineMaxRunningCount);
}
@@ -1,20 +1,29 @@
import { IAccessService } from "@certd/pipeline";
import { IAccessService, IRuntimeDepsService } from "@certd/pipeline";
export type AccessRuntimeDepsService = IRuntimeDepsService;
export class AccessGetter implements IAccessService {
userId: number;
projectId?: number;
getter: <T>(id: any, userId?: number, projectId?: number, ignorePermission?: boolean) => Promise<T>;
constructor(userId: number, projectId: number, getter: (id: any, userId: number, projectId?: number, ignorePermission?: boolean) => Promise<any>) {
runtimeDepsService?: AccessRuntimeDepsService;
getter: <T>(id: any, userId?: number, projectId?: number, ignorePermission?: boolean, runtimeDepsService?: AccessRuntimeDepsService) => Promise<T>;
constructor(
userId: number,
projectId: number,
getter: (id: any, userId: number, projectId?: number, ignorePermission?: boolean, runtimeDepsService?: AccessRuntimeDepsService) => Promise<any>,
runtimeDepsService?: AccessRuntimeDepsService
) {
this.userId = userId;
this.projectId = projectId;
this.getter = getter;
this.runtimeDepsService = runtimeDepsService;
}
async getById<T = any>(id: any) {
return await this.getter<T>(id, this.userId, this.projectId);
return await this.getter<T>(id, this.userId, this.projectId, false, this.runtimeDepsService);
}
async getCommonById<T = any>(id: any) {
return await this.getter<T>(id, 0, null);
return await this.getter<T>(id, 0, null, false, this.runtimeDepsService);
}
}
@@ -2,10 +2,11 @@ import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { In, Repository } from "typeorm";
import { AccessGetter, BaseService, PageReq, PermissionException, ValidateException } from "../../../index.js";
import type { AccessRuntimeDepsService } from "./access-getter.js";
import { AccessEntity } from "../entity/access.js";
import { AccessDefine, accessRegistry, newAccess } from "@certd/pipeline";
import { EncryptService } from "./encrypt-service.js";
import { logger, utils } from "@certd/basic";
import { http, logger, utils } from "@certd/basic";
/**
*
@@ -160,7 +161,7 @@ export class AccessService extends BaseService<AccessEntity> {
};
}
async getAccessById(id: any, checkUserId: boolean, userId?: number, projectId?: number): Promise<any> {
async getAccessById(id: any, checkUserId: boolean, userId?: number, projectId?: number, runtimeDepsService?: AccessRuntimeDepsService): Promise<any> {
const entity = await this.info(id);
if (entity == null) {
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${id}`);
@@ -183,12 +184,20 @@ export class AccessService extends BaseService<AccessEntity> {
id: entity.id,
...setting,
};
const accessGetter = new AccessGetter(userId, projectId, this.getById.bind(this));
return await newAccess(entity.type, input, accessGetter);
const getAccessById = this.getById.bind(this);
const accessGetter = new AccessGetter(userId, projectId, getAccessById, runtimeDepsService);
const accessContext = {
logger,
http,
utils,
accessService: accessGetter,
} as any;
const access = await newAccess(entity.type, input, accessGetter, accessContext);
return access;
}
async getById(id: any, userId: number, projectId?: number): Promise<any> {
return await this.getAccessById(id, true, userId, projectId);
async getById(id: any, userId: number, projectId?: number, _ignorePermission?: boolean, runtimeDepsService?: AccessRuntimeDepsService): Promise<any> {
return await this.getAccessById(id, true, userId, projectId, runtimeDepsService);
}
decryptAccessEntity(entity: AccessEntity): any {
@@ -4,6 +4,7 @@ import {
accessRegistry,
FormItemProps,
IAccessService,
IRuntimeDepsService,
IServiceGetter,
PluginRequestHandleReq,
Registrable
@@ -27,6 +28,8 @@ export type AddonInputDefine = FormItemProps & {
export type AddonDefine = Registrable & {
addonType: string;
needPlus?: boolean;
dependPlugins?: Record<string, string>;
dependPackages?: Record<string, string>;
input?: {
[key: string]: AddonInputDefine;
};
@@ -64,15 +67,20 @@ export abstract class BaseAddon implements IAddon {
ctx!: AddonContext;
http!: HttpClient;
logger!: ILogger;
runtimeDepsService?: IRuntimeDepsService;
async importRuntime(specifier: string) {
if (!this.runtimeDepsService) {
return await import(specifier);
}
return await this.runtimeDepsService.importRuntime(specifier, this.logger);
}
title!: string;
// eslint-disable-next-line @typescript-eslint/no-empty-function
async onInstance() {}
async getAccess<T = any>(accessId: string | number, isCommon = false) {
if (accessId == null) {
throw new Error("您还没有配置授权");
@@ -106,11 +114,16 @@ export abstract class BaseAddon implements IAddon {
return res as T;
}
setCtx(ctx: AddonContext) {
async setCtx(ctx: AddonContext) {
this.ctx = ctx;
this.http = ctx.http;
this.logger = ctx.logger;
if (!this.runtimeDepsService && this.ctx.serviceGetter) {
this.runtimeDepsService = await this.ctx.serviceGetter.get("runtimeDepsService");
}
if (this.runtimeDepsService && this.define?.addonType && this.define?.name) {
await this.runtimeDepsService.ensureRuntimeDependencies({ pluginKeys: `addon:${this.define.addonType}:${this.define.name}`, logger: this.logger });
}
}
setDefine = (define:AddonDefine) => {
this.define = define;
@@ -63,9 +63,7 @@ export async function newAddon(addonType:string,type: string, input: any, ctx: A
throw new Error("ctx is required");
}
plugin.setDefine(register.define);
plugin.setCtx(ctx);
await plugin.setCtx(ctx);
await plugin.onInstance();
return plugin;
}
+18 -3
View File
@@ -1,7 +1,22 @@
{
"extends": "./node_modules/mwts/",
"ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"env": {
"jest": true
"mocha": true
},
"rules": {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/midway-flyway-js
+12 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.41.2",
"version": "1.41.4",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -16,7 +16,10 @@
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"cov": "midway-bin cov --ts",
"prepublish": "npm run build",
"pub": "npm publish"
"pub": "npm publish",
"compile": "npm run build",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"keywords": [],
"author": "greper",
@@ -32,22 +35,22 @@
"better-sqlite3": "^11.1.2"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.12",
"@types/node": "^18",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"prettier": "^2.8.8",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"tslib": "^2.8.1",
"typeorm": "^0.3.11",
"typeorm": "^0.3.20",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/plugin-cert
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/plugin-cert
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
**Note:** Version bump only for package @certd/plugin-cert
+14 -17
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -15,31 +15,28 @@
"preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"@certd/acme-client": "^1.41.2",
"@certd/basic": "^1.41.2",
"@certd/pipeline": "^1.41.2",
"@certd/plugin-lib": "^1.41.2",
"psl": "^1.9.0",
"punycode.js": "^2.3.1"
"@certd/plugin-lib": "^1.41.4"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/mocha": "^10.0.0",
"@types/chai": "^4.3.12",
"@types/mocha": "^10.0.6",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "^4.3.6",
"chai": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"mocha": "^10.1.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
**Note:** Version bump only for package @certd/plugin-lib
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/plugin-lib
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements
+18 -34
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.41.2",
"version": "1.41.4",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -15,51 +15,35 @@
"preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "tsc --skipLibCheck --watch",
"format": "prettier --write src",
"lint": "eslint --fix"
},
"dependencies": {
"@alicloud/openapi-client": "^0.4.15",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/pop-core": "^1.7.10",
"@alicloud/tea-util": "^1.4.11",
"@aws-sdk/client-s3": "^3.964.0",
"@certd/acme-client": "^1.41.2",
"@certd/basic": "^1.41.2",
"@certd/pipeline": "^1.41.2",
"@certd/plus-core": "^1.41.2",
"@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5",
"cos-nodejs-sdk-v5": "^2.15.4",
"@certd/acme-client": "^1.41.4",
"@certd/basic": "^1.41.4",
"@certd/pipeline": "^1.41.4",
"dayjs": "^1.11.7",
"iconv-lite": "^0.6.3",
"lodash-es": "^4.17.21",
"psl": "^1.15.0",
"punycode.js": "^2.3.1",
"qiniu": "^7.12.0",
"rimraf": "^5.0.5",
"socks": "^2.8.3",
"socks-proxy-agent": "^8.0.4",
"ssh2": "1.17.0",
"strip-ansi": "^7.1.0",
"tencentcloud-sdk-nodejs": "^4.1.166"
"psl": "^1.15.0"
},
"devDependencies": {
"@types/chai": "^4.3.3",
"@types/mocha": "^10.0.0",
"rimraf": "^5.0.5",
"@types/chai": "^4.3.12",
"@types/mocha": "^10.0.6",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"chai": "^4.3.6",
"chai": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"esmock": "^2.7.5",
"mocha": "^10.1.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
"typescript": "^5.4.2"
},
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f"
"gitHead": "bc731e4fb119787930e816a7d57c808b1b5cd66a"
}
@@ -132,7 +132,7 @@ export class CertConverter {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
await this.exec(`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype PKCS12 -deststorepass "${jksPassword}" `);
await this.exec(`keytool -importkeystore -srckeystore ${p12Path} -srcstoretype PKCS12 -srcstorepass "${jksPassword}" -destkeystore ${jksPath} -deststoretype JKS -deststorepass "${jksPassword}" `);
fs.unlinkSync(p12Path);
const fileBuffer = fs.readFileSync(jksPath);
@@ -4,6 +4,8 @@ import { IAccess, IAccessService, IServiceGetter, PageRes, PageSearch, Registrab
export type DnsProviderDefine = Registrable & {
accessType: string;
icon?: string;
dependPlugins?: Record<string, string>;
dependPackages?: Record<string, string>;
};
export type CreateRecordOptions = {
@@ -27,6 +29,7 @@ export type DnsProviderContext = {
domainParser: IDomainParser;
serviceGetter: IServiceGetter;
accessGetter?: IAccessService;
define?: DnsProviderDefine;
};
export type DomainRecord = {
@@ -61,7 +64,7 @@ export interface IDnsProvider<T = any> {
removeRecord(options: RemoveRecordOptions<T>): Promise<void>;
setCtx(ctx: DnsProviderContext): void;
setCtx(ctx: DnsProviderContext): Promise<void>;
//中文域名是否需要punycode转码,如果返回True,则使用punycode来添加解析记录,否则使用中文域名添加解析记录
usePunyCode(): boolean;
@@ -1,5 +1,5 @@
import { HttpClient, ILogger } from "@certd/basic";
import { IAccessService, PageRes, PageSearch } from "@certd/pipeline";
import { IAccessService, IRuntimeDepsService, PageRes, PageSearch } from "@certd/pipeline";
import punycode from "punycode.js";
import { CreateRecordOptions, DnsProviderContext, DnsProviderDefine, DnsResolveRecord, DomainRecord, IDnsProvider, RemoveRecordOptions } from "./api.js";
import { dnsProviderRegistry } from "./registry.js";
@@ -7,6 +7,14 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
ctx!: DnsProviderContext;
http!: HttpClient;
logger!: ILogger;
runtimeDepsService?: IRuntimeDepsService;
async importRuntime(specifier: string) {
if (!this.runtimeDepsService) {
throw new Error("runtimeDepsService 未初始化");
}
return await this.runtimeDepsService.importRuntime(specifier, this.logger);
}
usePunyCode(): boolean {
//是否使用punycode来添加解析记录
@@ -30,10 +38,16 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
return punycode.toUnicode(domain);
}
setCtx(ctx: DnsProviderContext) {
async setCtx(ctx: DnsProviderContext) {
this.ctx = ctx;
this.logger = ctx.logger;
this.http = ctx.http;
if (!this.runtimeDepsService && this.ctx.serviceGetter) {
this.runtimeDepsService = await this.ctx.serviceGetter.get("runtimeDepsService");
}
if (this.runtimeDepsService && this.ctx.define?.name) {
await this.runtimeDepsService.ensureRuntimeDependencies({ pluginKeys: `dnsProvider:${this.ctx.define.name}`, logger: this.logger });
}
}
async parseDomain(fullDomain: string) {
@@ -68,9 +82,10 @@ export async function createDnsProvider(opts: { dnsProviderType: string; context
const accessGetter: IAccessService = await context.serviceGetter.get("accessService");
context.accessGetter = accessGetter;
}
context.define = dnsProviderDefine;
// @ts-ignore
const dnsProvider: IDnsProvider = new DnsProviderClass();
dnsProvider.setCtx(context);
await dnsProvider.setCtx(context);
await dnsProvider.onInstance();
return dnsProvider;
}
+37 -30
View File
@@ -1,12 +1,9 @@
FROM node:22-alpine3.21 AS builder
# RUN apk add build-base
# RUN wget -O - https://github.com/jemalloc/jemalloc/releases/download/5.3.0/jemalloc-5.3.0.tar.bz2 | tar -xj && \
# cd jemalloc-5.3.0 && \
# ./configure && \
# make && \
# make install
# 根据目标平台选择基础镜像:amd64/arm64 用 trixie-slimarm/v7 没有 trixie-slim 发布,回退到 alpine
FROM --platform=linux/amd64 node:22-trixie-slim AS base-amd64
FROM --platform=linux/arm64 node:22-trixie-slim AS base-arm64
FROM --platform=linux/arm/v7 node:22-alpine AS base-arm-v7
FROM base-${TARGETARCH}${TARGETVARIANT:+-}${TARGETVARIANT} AS builder
WORKDIR /workspace/
COPY . /workspace/
@@ -14,34 +11,44 @@ COPY . /workspace/
# https://pnpm.io/zh/migration
RUN npm install -g pnpm@10.33.4
#RUN cd /workspace/certd-client && pnpm install && npm run build
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
# RUN cd /workspace/certd-server && \
# pnpm install --ignore-scripts && \
# yes | pnpm approve-builds && \
# pnpm rebuild && \
# npm run build-on-docker
FROM node:22-alpine3.21
FROM base-${TARGETARCH}${TARGETVARIANT:+-}${TARGETVARIANT}
EXPOSE 7001
EXPOSE 7002
# 安装jemalloc内存分配器,优化内存占用 -- 基本没用,反而更高了
# COPY --from=builder /usr/local/lib/libjemalloc.so.2 /usr/local/lib/
# ENV LD_PRELOAD=/usr/local/lib/libjemalloc.so.2
# 根据基础镜像发行版选择包管理器
# trixie-slim -> apt-get, alpine -> apk
RUN if [ -f /etc/debian_version ]; then \
apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
gnupg \
wget \
openssl \
netcat-openbsd \
iputils-ping \
dnsutils \
iproute2 \
&& wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /usr/share/keyrings/adoptium.gpg > /dev/null \
&& echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main" | tee /etc/apt/sources.list.d/adoptium.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends temurin-8-jre \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*; \
elif [ -f /etc/alpine-release ]; then \
apk add --no-cache \
openssl \
openjdk8-jre; \
else \
echo "Unsupported base image"; exit 1; \
fi
RUN apk add --no-cache openssl
RUN apk add --no-cache openjdk8
RUN apk add --no-cache gcompat
WORKDIR /app/
COPY --from=builder /workspace/certd-server/ /app/
COPY ./patch/ssh2/*.js /app/node_modules/.pnpm/node_modules/ssh2/lib/protocol/
ENV TERM=xterm
ENV LEGO_VERSION=4.30.1
ENV LEGO_DOWNLOAD_DIR=/app/tools/lego
@@ -57,14 +64,14 @@ RUN ARCH=$(uname -m) && \
elif [ "$ARCH" = "aarch64" ]; then \
wget -O $LEGO_DOWNLOAD_DIR/lego_v${LEGO_VERSION}_linux_arm64.tar.gz https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_arm64.tar.gz; \
else \
# armv7 不支持lego 不要再尝试了
echo "Unsupported architecture: $ARCH"; \
fi
ENV TZ=Asia/Shanghai
ENV NODE_ENV=production
ENV MIDWAY_SERVER_ENV=production
COPY --from=builder /workspace/certd-server/ /app/
COPY ./patch/ssh2/*.js /app/node_modules/.pnpm/node_modules/ssh2/lib/protocol/
CMD ["node", "--optimize-for-size", "./bootstrap.js"]
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
### Performance Improvements
* 首页夜间模式主图切换为黑色背景 ([15484bc](https://github.com/certd/certd/commit/15484bc119fef7a0ca7f3fdab01d665fde47e688))
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes
+7 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.41.2",
"version": "1.41.4",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -74,7 +74,7 @@
"mitt": "^3.0.1",
"monaco-editor": "^0.52.2",
"monaco-yaml": "^5.3.1",
"nanoid": "^4.0.0",
"nanoid": "^5.0.7",
"node-forge": "^1.3.1",
"nprogress": "^0.2.0",
"object-assign": "^4.1.1",
@@ -93,7 +93,6 @@
"tailwindcss-animate": "^1.0.7",
"theme-colors": "^0.1.0",
"vee-validate": "^4.15.0",
"vitest": "^0.34.6",
"vue": "^3.4.21",
"vue-cropperjs": "^5.0.0",
"vue-echarts": "^7.0.3",
@@ -106,8 +105,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.41.2",
"@certd/pipeline": "^1.41.2",
"@certd/lib-iframe": "^1.41.4",
"@certd/pipeline": "^1.41.4",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
@@ -115,8 +114,8 @@
"@types/mocha": "^10.0.6",
"@types/node": "^18",
"@types/nprogress": "^0.2.3",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"@vitejs/plugin-legacy": "^5.3.2",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
@@ -129,7 +128,7 @@
"cross-env": "^7.0.3",
"dependency-cruiser": "^16.2.3",
"dot": "^1.1.3",
"eslint": "8.57.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-node": "^11.1.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

@@ -40,4 +40,8 @@ export default {
pluginManagement: "Plugin Management",
pluginBetaWarning: "Custom plugins are in BETA and may have breaking changes in future",
pleaseSelectRecord: "Please select records first",
clearRuntimeDeps: "Clear Runtime Deps Cache",
clearRuntimeDepsTooltip: "Restart the certd container after clearing, otherwise cached modules will not be reloaded",
clearRuntimeDepsConfirm: "Are you sure to clear the runtime dependencies cache? Please restart the certd container afterwards to ensure dependencies are reloaded.",
clearRuntimeDepsSuccess: "Runtime dependencies cache cleared successfully, please restart the certd container",
};
@@ -40,4 +40,8 @@ export default {
pluginManagement: "插件管理",
pluginBetaWarning: "自定义插件处于BETA测试版,后续可能会有破坏性变更",
pleaseSelectRecord: "请先勾选记录",
clearRuntimeDeps: "清理第三方依赖缓存",
clearRuntimeDepsTooltip: "清除后需重启 certd 容器,否则已缓存模块不会重新读取",
clearRuntimeDepsConfirm: "确定要清理第三方依赖缓存吗?清理后请重启 certd 容器以确保重新加载依赖。",
clearRuntimeDepsSuccess: "第三方依赖缓存清理成功,请重启 certd 容器",
};
@@ -11,9 +11,9 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({
name: "DnsPersistRecord",
@@ -24,10 +24,8 @@ const context: any = {
};
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
//
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -19,13 +19,14 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -21,13 +21,14 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -149,7 +149,7 @@
</template>
<script lang="ts" setup>
import { computed, nextTick, onActivated, onMounted, reactive, ref } from "vue";
import { computed, nextTick, reactive, ref } from "vue";
import { FsIcon, useFs } from "@fast-crud/fast-crud";
import { notification } from "ant-design-vue";
import { useRouter } from "vue-router";
@@ -158,6 +158,7 @@ import createInviteesCrudOptions from "./crud-invitees";
import createLogsCrudOptions from "./crud-logs";
import { useSettingStore } from "/@/store/settings";
import { util } from "/@/utils";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ name: "InviteCommission" });
@@ -314,16 +315,10 @@ async function refreshInvitePage(autoOpenAgreement = true) {
await refreshActiveList();
}
onMounted(async () => {
//
useMounted(async () => {
await refreshInvitePage(true);
});
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshInvitePage();
});
</script>
<style lang="less">
@@ -55,7 +55,7 @@
</template>
<script lang="ts" setup>
import { computed, onActivated, onMounted, provide, ref } from "vue";
import { computed, provide, ref } from "vue";
import { dict, useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import ChangeGroup from "./components/change-group.vue";
@@ -67,7 +67,7 @@ import BatchRerun from "./components/batch-rerun.vue";
import { Modal, notification } from "ant-design-vue";
import * as api from "./api";
import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue";
import { useSettingStore } from "/@/store/settings";
@@ -128,11 +128,7 @@ context.hasActionPermission = hasActionPermission;
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await groupDictRef.reloadDict();
await crudExpose.doRefresh();
});
@@ -26,13 +26,13 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
@@ -67,10 +67,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -27,7 +27,7 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted, Ref, ref } from "vue";
import { onMounted, ref } from "vue";
import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
@@ -18,12 +18,12 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
@@ -52,10 +52,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -8,9 +8,9 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({
name: "MyTrade",
@@ -18,10 +18,7 @@ defineOptions({
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -27,7 +27,7 @@
</template>
<script lang="ts" setup>
import { computed, h, onActivated, onMounted, reactive, ref } from "vue";
import { computed, h, reactive, ref } from "vue";
import { compute, dict, useFs } from "@fast-crud/fast-crud";
import { Button, notification } from "ant-design-vue";
import * as api from "./api";
@@ -36,6 +36,7 @@ import createWithdrawCrudOptions from "./crud-withdraw";
import { util } from "/@/utils";
import { useFormDialog } from "/@/use/use-dialog";
import { useUserStore } from "/@/store/user";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ name: "MyWallet" });
@@ -257,14 +258,8 @@ async function refreshWalletPage() {
loaded.value = true;
}
onMounted(refreshWalletPage);
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshWalletPage();
});
//
useMounted(refreshWalletPage);
</script>
<style lang="less">
@@ -41,7 +41,7 @@
</div>
</div>
<div class="hero-image-wrapper">
<img src="/static/images/certd-intro.png" alt="Certd Intro" class="hero-image" />
<img :src="isDark ? '/static/images/certd-intro-dark.png' : '/static/images/certd-intro.png'" alt="Certd Intro" class="hero-image" />
</div>
</div>
</section>
@@ -121,7 +121,8 @@ import { useAccessStore } from "/@/vben/stores";
import { SiteInfo, SysPublicSetting } from "/@/store/settings/api.basic";
import ThemeToggle from "/@/vben/layouts/widgets/theme-toggle/theme-toggle.vue";
import { useRouter } from "vue-router";
import { usePreferences } from "/@/vben/preferences";
const { isDark } = usePreferences();
const envRef = ref(env);
const settingStore = useSettingStore();
const userStore = useUserStore();
@@ -381,7 +382,7 @@ onMounted(() => {
padding: 0 24px;
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 60px;
gap: 10px;
align-items: center;
}
@@ -440,7 +441,7 @@ onMounted(() => {
.hero-image {
width: 100%;
height: auto;
max-width: 550px;
max-width: 600px;
}
.section-header {
@@ -14,27 +14,25 @@
</template>
<script lang="ts">
import { defineComponent, onActivated, onMounted, ref } from "vue";
import { defineComponent, ref} from "vue";
import createCrudOptions from "./crud.js";
import FsPermissionTree from "./fs-permission-tree.vue";
import { usePermission } from "/src/plugin/permission";
import { useFs, useUi } from "@fast-crud/fast-crud";
import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
export default defineComponent({
name: "PermissionManager",
components: { FsPermissionTree },
setup() {
// permissioncommonOptionsactionbarrowHandleshow
// ./src/plugin/fast-crud/index.js 75-77
// ./src/plugin/fast-crud/index.js 75-77
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { permission: "sys:auth:per" } });
const { t } = useI18n();
//
onMounted(async () => {
// await crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
@@ -22,12 +22,13 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
const { t } = useI18n();
@@ -55,10 +56,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -22,12 +22,13 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
const { t } = useI18n();
@@ -55,10 +56,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -19,12 +19,13 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
import { useRoute } from "vue-router";
const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -17,14 +17,16 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useProjectStore } from "/@/store/project";
import { useCrudPermission } from "/@/plugin/permission";
import AdminModeIntro from "./intro.vue";
import { useProjectStore } from "/@/store/project";
const { t } = useI18n();
defineOptions({
@@ -52,10 +54,7 @@ const handleBatchDelete = () => {
};
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -143,3 +143,10 @@ export async function GetPluginByName(name: string): Promise<PluginConfigBean> {
data: { name },
});
}
export async function ClearRuntimeDeps(): Promise<void> {
return await request({
url: "/sys/settings/clearRuntimeDeps",
method: "post",
});
}
@@ -3,7 +3,7 @@ import { useI18n } from "/src/locales";
import { Ref, ref, computed } from "vue";
import { useRouter } from "vue-router";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { Modal } from "ant-design-vue";
import { Modal, message } from "ant-design-vue";
//@ts-ignore
import yaml from "js-yaml";
import { usePluginImport } from "./use-import";
@@ -83,6 +83,24 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
await openImportDialog({ crudExpose });
},
},
clearRuntimeDeps: {
show: true,
icon: "ion:trash-outline",
text: t("certd.clearRuntimeDeps"),
tooltip: { title: t("certd.clearRuntimeDepsTooltip") },
type: "primary",
danger: true,
async click() {
Modal.confirm({
title: t("certd.confirm"),
content: t("certd.clearRuntimeDepsConfirm"),
async onOk() {
await api.ClearRuntimeDeps();
message.success(t("certd.clearRuntimeDepsSuccess"));
},
});
},
},
},
},
table: {
@@ -17,12 +17,12 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n();
@@ -31,15 +31,11 @@ defineOptions({
});
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
onActivated(async () => {
await crudExpose.doRefresh();
});
const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: t("certd.confirm"),
title: t("certd.pluginManagement"),
content: t("certd.batchDeleteConfirm", { count: selectedRowKeys.value.length }),
async onOk() {
await DeleteBatch(selectedRowKeys.value);
@@ -49,13 +45,13 @@ const handleBatchDelete = () => {
},
});
} else {
message.error(t("certd.pleaseSelectRecord"));
message.error(t("certd.selectRecordFirst"));
}
};
//
onMounted(() => {
crudExpose.doRefresh();
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
<style lang="less"></style>
@@ -8,10 +8,10 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { useSettingStore } from "/@/store/settings";
import { useMounted } from "/@/use/use-mounted";
defineOptions({
name: "SettingsHeaderMenus",
@@ -20,10 +20,7 @@ const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions
const settingStore = useSettingStore();
//
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -11,9 +11,9 @@
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({
name: "SysProductActivationCode",
@@ -21,10 +21,8 @@ defineOptions({
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
onMounted(() => {
// crudExpose.doRefresh();
});
onActivated(async () => {
//
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
@@ -3,9 +3,10 @@
</template>
<script lang="ts" setup>
import { defineEmits, onActivated, onMounted, ref } from "vue";
import { ref } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({
name: "ProductManager",
@@ -16,10 +17,7 @@ const context: any = { emit };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
//
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(async () => {
useMounted(async () => {
await crudExpose.doRefresh();
});
</script>
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.4](https://github.com/certd/certd/compare/v1.41.3...v1.41.4) (2026-06-14)
### Bug Fixes
* 修复设置里面不显示tab页签,导致某些页面需要点击查询按钮才有数据出来的bug ([c1b5a35](https://github.com/certd/certd/commit/c1b5a35f90a7d4b41397717b5c27905bc68e1bfb))
### Performance Improvements
* **plugin:** 增加 Dynadot DNS and access 插件 ([a3a215b](https://github.com/certd/certd/commit/a3a215b7ae2b90efcde91270ce4165bbfe77dc64))
## [1.41.3](https://github.com/certd/certd/compare/v1.41.2...v1.41.3) (2026-06-11)
**Note:** Version bump only for package @certd/ui-server
## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes
@@ -0,0 +1,36 @@
name: dynadot
title: Dynadot授权
desc: ''
icon: simple-icons:dynatrace
input:
apiKey:
title: API Key
component:
placeholder: api key
helper: >-
前往 [Dynadot
API设置](https://www.dynadot.cn/zh/account/domain/setting/api.html) 获取API
Key
required: true
encrypt: true
apiSecret:
title: API Secret
component:
name: a-input-password
vModel: value
placeholder: api secret
helper: >-
前往 [Dynadot
API设置](https://www.dynadot.cn/zh/account/domain/setting/api.html) 获取API
Secret
required: true
encrypt: true
testRequest:
title: 测试
component:
name: api-test
action: TestRequest
helper: 点击测试接口是否正常
pluginType: access
type: builtIn
scriptFilePath: /plugins/plugin-dynadot/access.js
@@ -0,0 +1,8 @@
name: dynadot
title: Dynadot
desc: Dynadot DNS提供商
icon: simple-icons:dynatrace
accessType: dynadot
pluginType: dnsProvider
type: builtIn
scriptFilePath: /plugins/plugin-dynadot/dns-provider.js
+58 -54
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-server",
"version": "1.41.2",
"version": "1.41.4",
"description": "fast-server base midway",
"private": true,
"type": "module",
@@ -21,9 +21,9 @@
"test": "cross-env NODE_ENV=unittest mocha",
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly pnpm run test",
"lint": "mwts check",
"lint:check": "mwts check",
"format": "prettier --write src",
"lint:fix": "mwts fix",
"lint": "mwts fix",
"ci": "pnpm run cov",
"build-only": "cross-env NODE_ENV=production mwtsc -p tsconfig.build.json --cleanOutDir --skipLibCheck",
"build": "pnpm run build-only && pnpm run export-metadata",
@@ -36,44 +36,25 @@
"flame": "clinic flame -- node ./bootstrap.js",
"tsc": "tsc --skipLibCheck",
"slimming": "node ./slimming.js",
"pub": "echo 1"
"pub": "echo 1",
"compile": "",
"lint1": "eslint --fix"
},
"dependencies": {
"@alicloud/fc20230330": "^4.1.7",
"@alicloud/openapi-client": "^0.4.12",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/pop-core": "^1.7.10",
"@alicloud/sts-sdk": "^1.0.2",
"@alicloud/tea-typescript": "^1.8.0",
"@alicloud/tea-util": "^1.4.10",
"@aws-sdk/client-acm": "^3.964.0",
"@aws-sdk/client-cloudfront": "^3.964.0",
"@aws-sdk/client-iam": "^3.964.0",
"@aws-sdk/client-route-53": "^3.964.0",
"@aws-sdk/client-s3": "^3.964.0",
"@aws-sdk/client-sts": "^3.990.0",
"@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1",
"@certd/acme-client": "^1.41.2",
"@certd/basic": "^1.41.2",
"@certd/commercial-core": "^1.41.2",
"@certd/acme-client": "^1.41.4",
"@certd/basic": "^1.41.4",
"@certd/commercial-core": "^1.41.4",
"@certd/cv4pve-api-javascript": "^8.4.2",
"@certd/jdcloud": "^1.41.2",
"@certd/lib-huawei": "^1.41.2",
"@certd/lib-k8s": "^1.41.2",
"@certd/lib-server": "^1.41.2",
"@certd/midway-flyway-js": "^1.41.2",
"@certd/pipeline": "^1.41.2",
"@certd/plugin-cert": "^1.41.2",
"@certd/plugin-lib": "^1.41.2",
"@certd/plugin-plus": "^1.41.2",
"@certd/plus-core": "^1.41.2",
"@google-cloud/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0",
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
"@huaweicloud/huaweicloud-sdk-core": "3.1.185",
"@huaweicloud/huaweicloud-sdk-elb": "3.1.185",
"@huaweicloud/huaweicloud-sdk-iam": "3.1.185",
"@certd/jdcloud": "^1.41.4",
"@certd/lib-huawei": "^1.41.4",
"@certd/lib-k8s": "^1.41.4",
"@certd/lib-server": "^1.41.4",
"@certd/midway-flyway-js": "^1.41.4",
"@certd/pipeline": "^1.41.4",
"@certd/plugin-cert": "^1.41.4",
"@certd/plugin-lib": "^1.41.4",
"@certd/plugin-plus": "^1.41.4",
"@certd/plus-core": "^1.41.4",
"@koa/cors": "^5.0.0",
"@midwayjs/bootstrap": "3.20.11",
"@midwayjs/cache": "3.14.0",
@@ -90,37 +71,27 @@
"@peculiar/x509": "^1.11.0",
"@simplewebauthn/browser": "^13.2.2",
"@simplewebauthn/server": "^13.2.3",
"@ucloud-sdks/ucloud-sdk-js": "^0.2.4",
"@volcengine/openapi": "^1.28.1",
"@volcengine/tos-sdk": "^2.9.1",
"ali-oss": "^6.21.0",
"alipay-sdk": "^4.13.0",
"axios": "^1.9.0",
"basic-ftp": "^5.0.5",
"bcryptjs": "^2.4.3",
"better-sqlite3": "^11.1.2",
"cache-manager": "^6.1.0",
"cos-nodejs-sdk-v5": "^2.14.6",
"cron-parser": "^4.9.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.7",
"esdk-obs-nodejs": "^3.25.6",
"form-data": "^4.0.0",
"glob": "^11.0.0",
"https-proxy-agent": "^7.0.5",
"iconv-lite": "^0.6.3",
"jdcloud-sdk-js": "^1.2.202",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"jsrsasign": "^11.1.0",
"jszip": "^3.10.1",
"koa-send": "^5.0.1",
"lodash-es": "^4.17.21",
"log4js": "^6.7.1",
"log4js": "^6.9.1",
"lru-cache": "^11.0.1",
"mitt": "^3.0.1",
"mwts": "^1.3.0",
"mwtsc": "^1.15.1",
"mysql2": "^3.14.0",
"nanoid": "^5.0.7",
"node-forge": "^1.3.1",
@@ -130,7 +101,6 @@
"pg": "^8.12.0",
"psl": "^1.15.0",
"punycode.js": "^2.3.1",
"qiniu": "^7.12.0",
"qrcode": "^1.5.4",
"qs": "^6.13.1",
"querystring": "^0.2.1",
@@ -141,28 +111,61 @@
"ssh2": "^1.17.0",
"strip-ansi": "^7.1.0",
"svg-captcha": "^1.4.0",
"tencentcloud-sdk-nodejs": "^4.1.112",
"typeorm": "^0.3.20",
"uuid": "^10.0.0",
"wechatpay-node-v3": "^2.2.1",
"whoiser": "2.0.0-beta.10",
"xml2js": "^0.6.2"
},
"lazyDependencies": {
"@alicloud/fc20230330": "^4.1.7",
"@alicloud/tea-typescript": "^1.8.0",
"@alicloud/openapi-client": "^0.4.12",
"@alicloud/openapi-util": "^0.3.2",
"@alicloud/pop-core": "^1.7.10",
"@alicloud/sts-sdk": "^1.0.2",
"@alicloud/tea-util": "^1.4.10",
"@aws-sdk/client-acm": "^3.964.0",
"@aws-sdk/client-cloudfront": "^3.964.0",
"@aws-sdk/client-iam": "^3.964.0",
"@aws-sdk/client-route-53": "^3.964.0",
"@aws-sdk/client-s3": "^3.964.0",
"@aws-sdk/client-sts": "^3.990.0",
"ali-oss": "^6.21.0",
"tencentcloud-sdk-nodejs": "^4.1.112",
"cos-nodejs-sdk-v5": "^2.14.6",
"@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1",
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
"@huaweicloud/huaweicloud-sdk-core": "3.1.185",
"@huaweicloud/huaweicloud-sdk-elb": "3.1.185",
"@huaweicloud/huaweicloud-sdk-iam": "3.1.185",
"@ucloud-sdks/ucloud-sdk-js": "^0.2.4",
"@volcengine/openapi": "^1.28.1",
"@volcengine/tos-sdk": "^2.9.1",
"@google-cloud/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0",
"basic-ftp": "^5.0.5",
"esdk-obs-nodejs": "^3.25.6",
"qiniu": "^7.12.0"
},
"devDependencies": {
"mwts": "^1.3.0",
"mwtsc": "^1.15.1",
"@midwayjs/mock": "3.20.11",
"@types/ali-oss": "^6.16.11",
"@types/cache-manager": "^4.0.6",
"@types/jest": "^29.5.13",
"@types/koa": "2.15.0",
"@types/lodash-es": "^4.17.12",
"@types/mocha": "^10.0.1",
"@types/mocha": "^10.0.6",
"@types/node": "^18",
"@types/nodemailer": "^6.4.8",
"c8": "^10.1.2",
"cross-env": "^7.0.3",
"esmock": "^2.7.5",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"mocha": "^10.6.0",
"prettier": "3.3.3",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tslib": "^2.8.1",
@@ -179,6 +182,7 @@
"pnpm": {
"neverBuiltDependencies": []
},
"author": "anonymous",
"license": "MIT"
}
@@ -16,8 +16,11 @@ import { tmpdir } from "node:os";
import { DefaultUploadFileMimeType, uploadWhiteList } from "@midwayjs/upload";
import path from "path";
import { logger } from "@certd/basic";
import { createRequire } from "module";
const env = process.env.NODE_ENV || "development";
const require = createRequire(import.meta.url);
const pkg = require("../../package.json");
const development = {
midwayLogger: {
@@ -103,6 +106,21 @@ const development = {
certd: {
fileRootDir: "./data/files",
},
runtimeDeps: {
enabled: true,
rootDir: "./data/.runtime-deps",
autoInstall: true,
pnpmCommand: "",
installTimeoutMs: 120000,
lazyDependencies: pkg.lazyDependencies || {},
registry: {
mode: "auto",
fixedUrl: "",
candidates: ["https://registry.npmmirror.com", "https://registry.npmjs.org"],
probeTimeoutMs: 3000,
cacheTtlMs: 6 * 60 * 60 * 1000,
},
},
system: {
resetAdminPasswd: false,
},
@@ -31,7 +31,6 @@ process.on("uncaughtException", error => {
logger.error("您的服务器不支持监听IPV6格式的地址(::),请配置环境变量: certd_koa_hostname=0.0.0.0");
}
});
// function startHeapLog() {
// function format(bytes: any) {
// return (bytes / 1024 / 1024).toFixed(2) + ' MB';
@@ -134,7 +133,5 @@ export class MainConfiguration {
});
logger.info("当前环境:", this.app.getEnv()); // prod
}
}
@@ -7,6 +7,7 @@ import { getEmailSettings } from "../../../modules/sys/settings/fix.js";
import { http, logger, utils } from "@certd/basic";
import { CodeService } from "../../../modules/basic/service/code-service.js";
import { SmsServiceFactory } from "../../../modules/basic/sms/factory.js";
import { RuntimeDepsService } from "../../../modules/runtime-deps/runtime-deps-service.js";
/**
*/
@@ -23,6 +24,8 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
codeService: CodeService;
@Inject()
addonService: AddonService;
@Inject()
runtimeDepsService: RuntimeDepsService;
getService() {
return this.service;
@@ -216,4 +219,10 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
const list = await addonRegistry.getDefineList("oauth");
return this.ok(list);
}
@Post("/clearRuntimeDeps", { description: "sys:settings:edit" })
async clearRuntimeDeps() {
await this.runtimeDepsService.clearRuntimeDeps();
return this.ok(true);
}
}
@@ -8,6 +8,7 @@ import { TaskServiceBuilder } from "../../../modules/pipeline/service/getter/tas
import { cloneDeep } from "lodash-es";
import { ApiTags } from "@midwayjs/swagger";
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
import { RuntimeDepsService } from "../../../modules/runtime-deps/runtime-deps-service.js";
@Provide()
@Controller("/api/pi/handle")
@@ -28,6 +29,9 @@ export class HandleController extends BaseController {
@Inject()
notificationService: NotificationService;
@Inject()
runtimeDepsService: RuntimeDepsService;
@Post("/access", { description: Constants.per.authOnly, summary: "处理授权请求" })
async accessRequest(@Body(ALL) body: AccessRequestHandleReq) {
let { projectId, userId } = await this.getProjectUserIdRead();
@@ -59,8 +63,16 @@ export class HandleController extends BaseController {
inputAccess = this.accessService.decryptAccessEntity(param);
}
}
const accessGetter = new AccessGetter(userId, projectId, this.accessService.getById.bind(this.accessService));
const access = await newAccess(body.typeName, inputAccess, accessGetter);
const getAccessById = this.accessService.getById.bind(this.accessService);
const accessGetter = new AccessGetter(userId, projectId, getAccessById, this.runtimeDepsService);
const accessContext = {
http,
logger,
utils,
accessService: accessGetter,
define: undefined,
} as any;
const access = await newAccess(body.typeName, inputAccess, accessGetter, accessContext);
// mergeUtils.merge(access, body.input);
const res = await access.onRequest(body);
@@ -70,14 +82,17 @@ export class HandleController extends BaseController {
@Post("/notification", { description: Constants.per.authOnly, summary: "处理通知请求" })
async notificationRequest(@Body(ALL) body: NotificationRequestHandleReq) {
const { projectId, userId } = await this.getProjectUserIdRead();
const input = body.input;
const serviceGetter = this.taskServiceBuilder.create({ userId, projectId });
const notification = await newNotification(body.typeName, input, {
http,
logger,
utils,
emailService: this.emailService,
});
serviceGetter,
} as any);
const res = await notification.onRequest(body);
@@ -138,8 +153,8 @@ export class HandleController extends BaseController {
// signal: this.abort.signal,
utils,
serviceGetter: taskServiceGetter,
};
instance.setCtx(taskCtx);
} as any;
await instance.setCtx(taskCtx);
mergeUtils.merge(plugin, body.input);
await instance.onInstance();
const res = await plugin.onRequest(body);
@@ -98,17 +98,17 @@ export class LegacyAcmeAccountAccessFix {
continue;
}
const name = buildAcmeAccountAccessName(parsedKey.caType, parsedKey.email);
const query = {
userId: record.userId,
type: "acmeAccount",
subtype: parsedKey.caType,
name,
} as any
const query = {
userId: record.userId,
type: "acmeAccount",
subtype: parsedKey.caType,
name,
} as any;
if (record.projectId) {
query.projectId = record.projectId;
}
const exists = await this.accessService.findOne({
where:query,
where: query,
});
if (exists) {
continue;

Some files were not shown because too many files have changed in this diff Show More