Compare commits

..

17 Commits

Author SHA1 Message Date
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
75 changed files with 776 additions and 248 deletions
+3 -2
View File
@@ -37,5 +37,6 @@ pnpm-lock.yaml
.studio/ .studio/
# Certd 推广报告,仅本地使用 # Certd 推广报告,仅本地使用
/popularize/ /popularize/reports/
output/
.uploads/
-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、完成开发后无需测试,通知用户自己去测试
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes ### Bug Fixes
+27
View File
@@ -3,6 +3,33 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.1](https://github.com/certd/certd/compare/v1.41.0...v1.41.1) (2026-06-05)
### Performance Improvements ### Performance Improvements
+1 -1
View File
@@ -9,5 +9,5 @@
} }
}, },
"npmClient": "pnpm", "npmClient": "pnpm",
"version": "1.41.2" "version": "1.41.3"
} }
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/acme-client
+3 -3
View File
@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client", "description": "Simple and unopinionated ACME client",
"private": false, "private": false,
"author": "nmorsman", "author": "nmorsman",
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"module": "./dist/index.js", "module": "./dist/index.js",
"main": "./dist/index.js", "main": "./dist/index.js",
@@ -18,7 +18,7 @@
"types" "types"
], ],
"dependencies": { "dependencies": {
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@peculiar/x509": "^1.11.0", "@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5", "asn1js": "^3.0.5",
"axios": "^1.9.0", "axios": "^1.9.0",
@@ -76,5 +76,5 @@
"bugs": { "bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues" "url": "https://github.com/publishlab/node-acme-client/issues"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
@@ -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; challengeCompleted = true;
log(`[auto] [${d}] 等待返回valid状态`); log(`[auto] [${d}] 等待返回valid状态`);
await client.waitForValidStatus(challenge,d); await client.waitForValidStatus(authz,d);
}); });
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements ### Performance Improvements
+1 -1
View File
@@ -1 +1 @@
23:34 23:53
+4 -2
View File
@@ -1,7 +1,9 @@
{ {
"name": "@certd/basic", "name": "@certd/basic",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",
@@ -52,5 +54,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements ### Performance Improvements
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/pipeline", "name": "@certd/pipeline",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",
@@ -19,8 +19,8 @@
"compile": "tsc --skipLibCheck --watch" "compile": "tsc --skipLibCheck --watch"
}, },
"dependencies": { "dependencies": {
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@certd/plus-core": "^1.41.2", "@certd/plus-core": "^1.41.3",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"reflect-metadata": "^0.1.13" "reflect-metadata": "^0.1.13"
@@ -49,5 +49,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/lib-huawei
+4 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-huawei", "name": "@certd/lib-huawei",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"main": "./dist/bundle.js", "main": "./dist/bundle.js",
"module": "./dist/bundle.js", "module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts", "types": "./dist/d/index.d.ts",
@@ -12,7 +12,8 @@
"dev-build": "npm run build", "dev-build": "npm run build",
"preview": "vite preview", "preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests", "test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish" "pub": "npm publish",
"compile": "npm run build"
}, },
"dependencies": { "dependencies": {
"axios": "^1.9.0", "axios": "^1.9.0",
@@ -27,5 +28,5 @@
"prettier": "^2.8.8", "prettier": "^2.8.8",
"tslib": "^2.8.1" "tslib": "^2.8.1"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/lib-iframe
+4 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-iframe", "name": "@certd/lib-iframe",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",
@@ -15,7 +15,8 @@
"build2": "vue-tsc --noEmit && vite build", "build2": "vue-tsc --noEmit && vite build",
"preview": "vite preview", "preview": "vite preview",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests", "test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish" "pub": "npm publish",
"compile": "npm run build"
}, },
"dependencies": { "dependencies": {
"nanoid": "^4.0.0" "nanoid": "^4.0.0"
@@ -34,5 +35,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/jdcloud
+7 -3
View File
@@ -1,16 +1,20 @@
{ {
"name": "@certd/jdcloud", "name": "@certd/jdcloud",
"version": "1.41.2", "version": "1.41.3",
"description": "jdcloud openApi sdk", "description": "jdcloud openApi sdk",
"main": "./dist/bundle.js", "main": "./dist/bundle.js",
"module": "./dist/bundle.js", "module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts", "types": "./dist/d/index.d.ts",
"scripts": { "scripts": {
"before-build": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true});fs.rmSync('.rollup.cache',{recursive:true,force:true});\"", "before-build": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true});fs.rmSync('.rollup.cache',{recursive:true,force:true});\"",
"build": "npm run before-build && rollup -c ", "build": "npm run before-build && rollup -c ",
"dev-build": "npm run build", "dev-build": "npm run build",
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests", "test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"pub": "npm publish" "pub": "npm publish",
"compile": "npm run build"
}, },
"author": "", "author": "",
"license": "Apache", "license": "Apache",
@@ -59,5 +63,5 @@
"fetch" "fetch"
] ]
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/lib-k8s
+3 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/lib-k8s", "name": "@certd/lib-k8s",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js", "module": "./dist/index.js",
@@ -19,7 +19,7 @@
"compile": "tsc --skipLibCheck --watch" "compile": "tsc --skipLibCheck --watch"
}, },
"dependencies": { "dependencies": {
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@kubernetes/client-node": "0.21.0" "@kubernetes/client-node": "0.21.0"
}, },
"devDependencies": { "devDependencies": {
@@ -36,5 +36,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/lib-server
+7 -7
View File
@@ -1,6 +1,6 @@
{ {
"name": "@certd/lib-server", "name": "@certd/lib-server",
"version": "1.41.2", "version": "1.41.3",
"description": "midway with flyway, sql upgrade way ", "description": "midway with flyway, sql upgrade way ",
"private": false, "private": false,
"type": "module", "type": "module",
@@ -29,11 +29,11 @@
], ],
"license": "AGPL", "license": "AGPL",
"dependencies": { "dependencies": {
"@certd/acme-client": "^1.41.2", "@certd/acme-client": "^1.41.3",
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@certd/pipeline": "^1.41.2", "@certd/pipeline": "^1.41.3",
"@certd/plugin-lib": "^1.41.2", "@certd/plugin-lib": "^1.41.3",
"@certd/plus-core": "^1.41.2", "@certd/plus-core": "^1.41.3",
"@midwayjs/cache": "3.14.0", "@midwayjs/cache": "3.14.0",
"@midwayjs/core": "3.20.11", "@midwayjs/core": "3.20.11",
"@midwayjs/i18n": "3.20.13", "@midwayjs/i18n": "3.20.13",
@@ -69,5 +69,5 @@
"typeorm": "^0.3.11", "typeorm": "^0.3.11",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/midway-flyway-js
+4 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@certd/midway-flyway-js", "name": "@certd/midway-flyway-js",
"version": "1.41.2", "version": "1.41.3",
"description": "midway with flyway, sql upgrade way ", "description": "midway with flyway, sql upgrade way ",
"private": false, "private": false,
"type": "module", "type": "module",
@@ -16,7 +16,8 @@
"test:unit": "cross-env NODE_ENV=unittest echo no unit tests", "test:unit": "cross-env NODE_ENV=unittest echo no unit tests",
"cov": "midway-bin cov --ts", "cov": "midway-bin cov --ts",
"prepublish": "npm run build", "prepublish": "npm run build",
"pub": "npm publish" "pub": "npm publish",
"compile": "npm run build"
}, },
"keywords": [], "keywords": [],
"author": "greper", "author": "greper",
@@ -49,5 +50,5 @@
"typeorm": "^0.3.11", "typeorm": "^0.3.11",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [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 **Note:** Version bump only for package @certd/plugin-cert
+6 -6
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/plugin-cert", "name": "@certd/plugin-cert",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -18,10 +18,10 @@
"compile": "tsc --skipLibCheck --watch" "compile": "tsc --skipLibCheck --watch"
}, },
"dependencies": { "dependencies": {
"@certd/acme-client": "^1.41.2", "@certd/acme-client": "^1.41.3",
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@certd/pipeline": "^1.41.2", "@certd/pipeline": "^1.41.3",
"@certd/plugin-lib": "^1.41.2", "@certd/plugin-lib": "^1.41.3",
"psl": "^1.9.0", "psl": "^1.9.0",
"punycode.js": "^2.3.1" "punycode.js": "^2.3.1"
}, },
@@ -41,5 +41,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Performance Improvements ### Performance Improvements
+6 -6
View File
@@ -1,7 +1,7 @@
{ {
"name": "@certd/plugin-lib", "name": "@certd/plugin-lib",
"private": false, "private": false,
"version": "1.41.2", "version": "1.41.3",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -23,10 +23,10 @@
"@alicloud/pop-core": "^1.7.10", "@alicloud/pop-core": "^1.7.10",
"@alicloud/tea-util": "^1.4.11", "@alicloud/tea-util": "^1.4.11",
"@aws-sdk/client-s3": "^3.964.0", "@aws-sdk/client-s3": "^3.964.0",
"@certd/acme-client": "^1.41.2", "@certd/acme-client": "^1.41.3",
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@certd/pipeline": "^1.41.2", "@certd/pipeline": "^1.41.3",
"@certd/plus-core": "^1.41.2", "@certd/plus-core": "^1.41.3",
"@kubernetes/client-node": "0.21.0", "@kubernetes/client-node": "0.21.0",
"ali-oss": "^6.22.0", "ali-oss": "^6.22.0",
"basic-ftp": "^5.0.5", "basic-ftp": "^5.0.5",
@@ -61,5 +61,5 @@
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"gitHead": "cdea411136fdf56352699a6e278a403e0f53a94f" "gitHead": "6cbd62977731a3b72c42b5f88c49500631da0a46"
} }
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes ### Bug Fixes
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-client", "name": "@certd/ui-client",
"version": "1.41.2", "version": "1.41.3",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite --open", "dev": "vite --open",
@@ -106,8 +106,8 @@
"zod-defaults": "^0.1.3" "zod-defaults": "^0.1.3"
}, },
"devDependencies": { "devDependencies": {
"@certd/lib-iframe": "^1.41.2", "@certd/lib-iframe": "^1.41.3",
"@certd/pipeline": "^1.41.2", "@certd/pipeline": "^1.41.3",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12", "@types/chai": "^4.3.12",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

@@ -11,9 +11,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ defineOptions({
name: "DnsPersistRecord", name: "DnsPersistRecord",
@@ -24,10 +24,8 @@ const context: any = {
}; };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
onMounted(() => { //
// crudExpose.doRefresh(); useMounted(async () => {
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -19,13 +19,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission"; import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -21,13 +21,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission"; import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -149,7 +149,7 @@
</template> </template>
<script lang="ts" setup> <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 { FsIcon, useFs } from "@fast-crud/fast-crud";
import { notification } from "ant-design-vue"; import { notification } from "ant-design-vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
@@ -158,6 +158,7 @@ import createInviteesCrudOptions from "./crud-invitees";
import createLogsCrudOptions from "./crud-logs"; import createLogsCrudOptions from "./crud-logs";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { util } from "/@/utils"; import { util } from "/@/utils";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ name: "InviteCommission" }); defineOptions({ name: "InviteCommission" });
@@ -314,16 +315,10 @@ async function refreshInvitePage(autoOpenAgreement = true) {
await refreshActiveList(); await refreshActiveList();
} }
onMounted(async () => { //
useMounted(async () => {
await refreshInvitePage(true); await refreshInvitePage(true);
}); });
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshInvitePage();
});
</script> </script>
<style lang="less"> <style lang="less">
@@ -55,7 +55,7 @@
</template> </template>
<script lang="ts" setup> <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 { dict, useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import ChangeGroup from "./components/change-group.vue"; 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 { Modal, notification } from "ant-design-vue";
import * as api from "./api"; import * as api from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue"; import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
@@ -128,11 +128,7 @@ context.hasActionPermission = hasActionPermission;
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await groupDictRef.reloadDict(); await groupDictRef.reloadDict();
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
@@ -26,13 +26,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission"; import { useCrudPermission } from "/@/plugin/permission";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
@@ -67,10 +67,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -27,7 +27,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted, Ref, ref } from "vue"; import { onMounted, ref } from "vue";
import { useMounted } from "/@/use/use-mounted"; import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
@@ -18,12 +18,12 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
@@ -52,10 +52,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -8,9 +8,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ defineOptions({
name: "MyTrade", name: "MyTrade",
@@ -18,10 +18,7 @@ defineOptions({
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -27,7 +27,7 @@
</template> </template>
<script lang="ts" setup> <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 { compute, dict, useFs } from "@fast-crud/fast-crud";
import { Button, notification } from "ant-design-vue"; import { Button, notification } from "ant-design-vue";
import * as api from "./api"; import * as api from "./api";
@@ -36,6 +36,7 @@ import createWithdrawCrudOptions from "./crud-withdraw";
import { util } from "/@/utils"; import { util } from "/@/utils";
import { useFormDialog } from "/@/use/use-dialog"; import { useFormDialog } from "/@/use/use-dialog";
import { useUserStore } from "/@/store/user"; import { useUserStore } from "/@/store/user";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ name: "MyWallet" }); defineOptions({ name: "MyWallet" });
@@ -257,14 +258,8 @@ async function refreshWalletPage() {
loaded.value = true; loaded.value = true;
} }
onMounted(refreshWalletPage); //
useMounted(refreshWalletPage);
onActivated(async () => {
if (!loaded.value) {
return;
}
await refreshWalletPage();
});
</script> </script>
<style lang="less"> <style lang="less">
@@ -41,7 +41,7 @@
</div> </div>
</div> </div>
<div class="hero-image-wrapper"> <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>
</div> </div>
</section> </section>
@@ -121,7 +121,8 @@ import { useAccessStore } from "/@/vben/stores";
import { SiteInfo, SysPublicSetting } from "/@/store/settings/api.basic"; import { SiteInfo, SysPublicSetting } from "/@/store/settings/api.basic";
import ThemeToggle from "/@/vben/layouts/widgets/theme-toggle/theme-toggle.vue"; import ThemeToggle from "/@/vben/layouts/widgets/theme-toggle/theme-toggle.vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { usePreferences } from "/@/vben/preferences";
const { isDark } = usePreferences();
const envRef = ref(env); const envRef = ref(env);
const settingStore = useSettingStore(); const settingStore = useSettingStore();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -381,7 +382,7 @@ onMounted(() => {
padding: 0 24px; padding: 0 24px;
display: grid; display: grid;
grid-template-columns: 1.1fr 0.9fr; grid-template-columns: 1.1fr 0.9fr;
gap: 60px; gap: 10px;
align-items: center; align-items: center;
} }
@@ -440,7 +441,7 @@ onMounted(() => {
.hero-image { .hero-image {
width: 100%; width: 100%;
height: auto; height: auto;
max-width: 550px; max-width: 600px;
} }
.section-header { .section-header {
@@ -14,27 +14,25 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, onActivated, onMounted, ref } from "vue"; import { defineComponent, ref} from "vue";
import createCrudOptions from "./crud.js"; import createCrudOptions from "./crud.js";
import FsPermissionTree from "./fs-permission-tree.vue"; import FsPermissionTree from "./fs-permission-tree.vue";
import { usePermission } from "/src/plugin/permission"; import { usePermission } from "/src/plugin/permission";
import { useFs, useUi } from "@fast-crud/fast-crud"; import { useFs, useUi } from "@fast-crud/fast-crud";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
export default defineComponent({ export default defineComponent({
name: "PermissionManager", name: "PermissionManager",
components: { FsPermissionTree }, components: { FsPermissionTree },
setup() { setup() {
// permissioncommonOptionsactionbarrowHandleshow // 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 { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { permission: "sys:auth:per" } });
const { t } = useI18n(); const { t } = useI18n();
// //
onMounted(async () => { useMounted(async () => {
// await crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
@@ -22,12 +22,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue"; import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
const { t } = useI18n(); const { t } = useI18n();
@@ -55,10 +56,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -22,12 +22,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue"; import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
const { t } = useI18n(); const { t } = useI18n();
@@ -55,10 +56,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -19,12 +19,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue"; import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useCrudPermission } from "/@/plugin/permission";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const { t } = useI18n(); const { t } = useI18n();
@@ -61,10 +62,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -17,14 +17,16 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue"; import { useMounted } from "/@/use/use-mounted";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useProjectStore } from "/@/store/project"; import { useCrudPermission } from "/@/plugin/permission";
import AdminModeIntro from "./intro.vue"; import AdminModeIntro from "./intro.vue";
import { useProjectStore } from "/@/store/project";
const { t } = useI18n(); const { t } = useI18n();
defineOptions({ defineOptions({
@@ -52,10 +54,7 @@ const handleBatchDelete = () => {
}; };
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -17,12 +17,12 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
import { useMounted } from "/@/use/use-mounted";
const { t } = useI18n(); const { t } = useI18n();
@@ -31,15 +31,11 @@ defineOptions({
}); });
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions }); const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
onActivated(async () => {
await crudExpose.doRefresh();
});
const selectedRowKeys = context.selectedRowKeys; const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => { const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) { if (selectedRowKeys.value?.length > 0) {
Modal.confirm({ Modal.confirm({
title: t("certd.confirm"), title: t("certd.pluginManagement"),
content: t("certd.batchDeleteConfirm", { count: selectedRowKeys.value.length }), content: t("certd.batchDeleteConfirm", { count: selectedRowKeys.value.length }),
async onOk() { async onOk() {
await DeleteBatch(selectedRowKeys.value); await DeleteBatch(selectedRowKeys.value);
@@ -49,13 +45,13 @@ const handleBatchDelete = () => {
}, },
}); });
} else { } else {
message.error(t("certd.pleaseSelectRecord")); message.error(t("certd.selectRecordFirst"));
} }
}; };
// //
onMounted(() => { useMounted(async () => {
crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
<style lang="less"></style> <style lang="less"></style>
@@ -8,10 +8,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ defineOptions({
name: "SettingsHeaderMenus", name: "SettingsHeaderMenus",
@@ -20,10 +20,7 @@ const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions
const settingStore = useSettingStore(); const settingStore = useSettingStore();
// //
onMounted(() => { useMounted(async () => {
// crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -11,9 +11,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ defineOptions({
name: "SysProductActivationCode", name: "SysProductActivationCode",
@@ -21,10 +21,8 @@ defineOptions({
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
onMounted(() => { //
// crudExpose.doRefresh(); useMounted(async () => {
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
@@ -3,9 +3,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineEmits, onActivated, onMounted, ref } from "vue"; import { ref } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { useMounted } from "/@/use/use-mounted";
defineOptions({ defineOptions({
name: "ProductManager", name: "ProductManager",
@@ -16,10 +17,7 @@ const context: any = { emit };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// //
onMounted(() => { useMounted(async () => {
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh(); await crudExpose.doRefresh();
}); });
</script> </script>
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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) ## [1.41.2](https://github.com/certd/certd/compare/v1.41.1...v1.41.2) (2026-06-10)
### Bug Fixes ### Bug Fixes
+14 -14
View File
@@ -1,6 +1,6 @@
{ {
"name": "@certd/ui-server", "name": "@certd/ui-server",
"version": "1.41.2", "version": "1.41.3",
"description": "fast-server base midway", "description": "fast-server base midway",
"private": true, "private": true,
"type": "module", "type": "module",
@@ -54,20 +54,20 @@
"@aws-sdk/client-sts": "^3.990.0", "@aws-sdk/client-sts": "^3.990.0",
"@azure/arm-dns": "^5.1.0", "@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1", "@azure/identity": "^4.13.1",
"@certd/acme-client": "^1.41.2", "@certd/acme-client": "^1.41.3",
"@certd/basic": "^1.41.2", "@certd/basic": "^1.41.3",
"@certd/commercial-core": "^1.41.2", "@certd/commercial-core": "^1.41.3",
"@certd/jdcloud": "^1.41.3",
"@certd/lib-huawei": "^1.41.3",
"@certd/lib-k8s": "^1.41.3",
"@certd/lib-server": "^1.41.3",
"@certd/midway-flyway-js": "^1.41.3",
"@certd/pipeline": "^1.41.3",
"@certd/plugin-cert": "^1.41.3",
"@certd/plugin-lib": "^1.41.3",
"@certd/plugin-plus": "^1.41.3",
"@certd/plus-core": "^1.41.3",
"@certd/cv4pve-api-javascript": "^8.4.2", "@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/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0", "@google-cloud/publicca": "^1.3.0",
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185", "@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
@@ -134,7 +134,5 @@ export class MainConfiguration {
}); });
logger.info("当前环境:", this.app.getEnv()); // prod logger.info("当前环境:", this.app.getEnv()); // prod
} }
} }
@@ -98,17 +98,17 @@ export class LegacyAcmeAccountAccessFix {
continue; continue;
} }
const name = buildAcmeAccountAccessName(parsedKey.caType, parsedKey.email); const name = buildAcmeAccountAccessName(parsedKey.caType, parsedKey.email);
const query = { const query = {
userId: record.userId, userId: record.userId,
type: "acmeAccount", type: "acmeAccount",
subtype: parsedKey.caType, subtype: parsedKey.caType,
name, name,
} as any } as any;
if (record.projectId) { if (record.projectId) {
query.projectId = record.projectId; query.projectId = record.projectId;
} }
const exists = await this.accessService.findOne({ const exists = await this.accessService.findOne({
where:query, where: query,
}); });
if (exists) { if (exists) {
continue; continue;
@@ -192,10 +192,7 @@ describe("CertApplyTemplateService", () => {
await service.setDefault(2, 10, null); await service.setDefault(2, 10, null);
assert.deepEqual((service as any).updateWhereList, [ assert.deepEqual((service as any).updateWhereList, [{ userId: 10 }, { userId: 10, id: 2 }]);
{ userId: 10 },
{ userId: 10, id: 2 },
]);
assert.equal(list[0].isDefault, false); assert.equal(list[0].isDefault, false);
assert.equal(list[1].isDefault, true); assert.equal(list[1].isDefault, true);
assert.equal(list[2].isDefault, false); assert.equal(list[2].isDefault, false);
@@ -897,13 +897,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
if (param.projectId != null) { if (param.projectId != null) {
query.projectId = param.projectId; query.projectId = param.projectId;
} }
const statusCount = await this.repository const statusCount = await this.repository.createQueryBuilder().select("status").addSelect("count(1)", "count").where(query).groupBy("status").getRawMany();
.createQueryBuilder()
.select("status")
.addSelect("count(1)", "count")
.where(query)
.groupBy("status")
.getRawMany();
return statusCount; return statusCount;
} }
@@ -915,13 +909,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
if (param.projectId != null) { if (param.projectId != null) {
query.projectId = param.projectId; query.projectId = param.projectId;
} }
const statusCount = await this.repository const statusCount = await this.repository.createQueryBuilder().select("disabled").addSelect("count(1)", "count").where(query).groupBy("disabled").getRawMany();
.createQueryBuilder()
.select("disabled")
.addSelect("count(1)", "count")
.where(query)
.groupBy("disabled")
.getRawMany();
const result = { const result = {
enabled: 0, enabled: 0,
disabled: 0, disabled: 0,
@@ -1115,14 +1103,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
}, },
}); });
for (const item of list) { for (const item of list) {
const pipeline = JSON.parse(item.content); const pipeline = JSON.parse(item.content);
if (trigger.props === false) { if (trigger.props === false) {
//清除trigger //清除trigger
pipeline.triggers = []; pipeline.triggers = [];
} else { } else {
const start = dayjs().format("YYYY-MM-DD") + " " + trigger.randomRange[0]; const start = dayjs().format("YYYY-MM-DD") + " " + trigger.randomRange[0];
let end = dayjs().format("YYYY-MM-DD") + " " + trigger.randomRange[1]; let end = dayjs().format("YYYY-MM-DD") + " " + trigger.randomRange[1];
if (trigger.randomRange[1] < trigger.randomRange[0]) { if (trigger.randomRange[1] < trigger.randomRange[0]) {
@@ -1137,19 +1123,20 @@ export class PipelineService extends BaseService<PipelineEntity> {
//随机时间 //随机时间
const randomTime = Math.floor(Math.random() * (endTime - startTime)) + startTime; const randomTime = Math.floor(Math.random() * (endTime - startTime)) + startTime;
const time = dayjs(randomTime).format(" ss:mm:HH").replaceAll(":", " ").replaceAll(" 0", " ").trim(); const time = dayjs(randomTime).format(" ss:mm:HH").replaceAll(":", " ").replaceAll(" 0", " ").trim();
set(triggerConf, "props.cron", `${time} * * *`) set(triggerConf, "props.cron", `${time} * * *`);
} }
delete triggerConf.random delete triggerConf.random;
delete triggerConf.randomRange; delete triggerConf.randomRange;
pipeline.triggers = [{ pipeline.triggers = [
id: nanoid(), {
title: "定时触发", id: nanoid(),
...triggerConf title: "定时触发",
}]; ...triggerConf,
},
];
} }
await this.doUpdatePipelineJson(item, pipeline); await this.doUpdatePipelineJson(item, pipeline);
} }
} }
async batchUpdateNotifications(ids: number[], notification: Notification, userId: any, projectId?: number) { async batchUpdateNotifications(ids: number[], notification: Notification, userId: any, projectId?: number) {
@@ -48,3 +48,4 @@
// export * from './plugin-dnsmgr/index.js' // export * from './plugin-dnsmgr/index.js'
// export * from './plugin-nginx-proxy-manager/index.js' // export * from './plugin-nginx-proxy-manager/index.js'
// export * from './plugin-hipmdnsmgr/index.js' // export * from './plugin-hipmdnsmgr/index.js'
// export * from './plugin-dynadot/index.js'
@@ -78,8 +78,8 @@ export class DeployCertToAliyunApig extends AbstractTaskPlugin {
action: DeployCertToAliyunApig.prototype.onGetDomainList.name, action: DeployCertToAliyunApig.prototype.onGetDomainList.name,
watches: ["region", "accessId", "gatewayType"], watches: ["region", "accessId", "gatewayType"],
required: true, required: true,
pager:true, pager: true,
search:true, search: true,
}) })
) )
domainList!: string[]; domainList!: string[];
@@ -196,7 +196,7 @@ export class DeployCertToAliyunApig extends AbstractTaskPlugin {
throw new Error("请选择网关类型"); throw new Error("请选择网关类型");
} }
const pager = new Pager(data); const pager = new Pager(data);
const access = await this.getAccess<AliyunAccess>(this.accessId); const access = await this.getAccess<AliyunAccess>(this.accessId);
const client = access.getClient(this.regionEndpoint); const client = access.getClient(this.regionEndpoint);
@@ -69,7 +69,7 @@ export class DeployCertToAliyunApiGateway extends AbstractTaskPlugin {
action: DeployCertToAliyunApiGateway.prototype.onGetGroupList.name, action: DeployCertToAliyunApiGateway.prototype.onGetGroupList.name,
watches: ["regionEndpoint", "accessId"], watches: ["regionEndpoint", "accessId"],
required: true, required: true,
single:true single: true,
}) })
) )
groupId!: string; groupId!: string;
@@ -33,10 +33,7 @@ export class AwsClient {
// Split the full PEM chain: first block is the leaf cert, the rest is the intermediate chain // Split the full PEM chain: first block is the leaf cert, the rest is the intermediate chain
const pemBlocks = certInfo.crt.split(/(?<=-----END CERTIFICATE-----)/); const pemBlocks = certInfo.crt.split(/(?<=-----END CERTIFICATE-----)/);
const cert = pemBlocks[0].trim(); const cert = pemBlocks[0].trim();
const chain = pemBlocks const chain = pemBlocks.slice(1).join("").trim();
.slice(1)
.join("")
.trim();
// 构建上传参数 // 构建上传参数
const data = await acmClient.send( const data = await acmClient.send(
@@ -144,10 +144,10 @@ export class AcmeAccountAccess extends BaseAccess {
action: "GenerateAccount", action: "GenerateAccount",
buttonText: "生成ACME账号", buttonText: "生成ACME账号",
successMessage: "ACME账号已生成,请保存授权配置", successMessage: "ACME账号已生成,请保存授权配置",
type:"textarea", type: "textarea",
rows:4, rows: 4,
}, },
col:{span:24}, col: { span: 24 },
required: true, required: true,
helper: "请生成ACME账号,账号一旦生成不允许修改", helper: "请生成ACME账号,账号一旦生成不允许修改",
encrypt: true, encrypt: true,
@@ -170,7 +170,6 @@ export class AcmeAccountAccess extends BaseAccess {
required: false, required: false,
helper: "是否开启修改ACME账号,注意,开启后,会影响DNS持久验证记录", helper: "是否开启修改ACME账号,注意,开启后,会影响DNS持久验证记录",
encrypt: false, encrypt: false,
}) })
editAccount = false; editAccount = false;
@@ -0,0 +1,143 @@
import { AccessInput, BaseAccess, IsAccess, PageRes, PageSearch, Pager } from "@certd/pipeline";
import { DomainRecord } from "@certd/plugin-lib";
import { createHmac } from "crypto";
export type RequestOptions = {
method: "GET" | "POST" | "PUT" | "DELETE";
path: string;
params?: Record<string, any>;
data?: any;
};
@IsAccess({
name: "dynadot",
title: "Dynadot授权",
desc: "",
icon: "simple-icons:dynatrace",
})
export class DynadotAccess extends BaseAccess {
@AccessInput({
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,
})
apiKey = "";
@AccessInput({
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,
})
apiSecret = "";
@AccessInput({
title: "测试",
component: {
name: "api-test",
action: "TestRequest",
},
helper: "点击测试接口是否正常",
})
testRequest = true;
async onTestRequest() {
await this.getDomainListPage({
pageNo: 1,
pageSize: 1,
});
return "ok";
}
async getDomainListPage(req: PageSearch): Promise<PageRes<DomainRecord>> {
const pager = new Pager(req);
const params: Record<string, any> = {
page: pager.pageNo,
page_size: pager.pageSize,
};
if (req.searchKey) {
params.search = req.searchKey;
}
const res = await this.doRequest({
method: "GET",
path: "/restful/v2/domains",
params,
});
const domainList = res.data?.domain_info_list || [];
const list = domainList.map((item: any) => ({
id: item.domain_name,
domain: item.domain_name,
}));
return {
total: list.length,
list,
};
}
async doRequest(opts: RequestOptions): Promise<any> {
const { method, path, params, data } = opts;
const queryString = params ? "?" + new URLSearchParams(params).toString() : "";
const fullPath = path + queryString;
const body = data ? JSON.stringify(data) : "";
const headers: Record<string, string> = {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${this.apiKey}`,
"X-Signature": this.generateSignature(fullPath, body),
};
try {
const res = await this.ctx.http.request<any, any>({
url: fullPath,
baseURL: "https://api.dynadot.com",
method,
data: body || undefined,
headers,
});
this.checkApiError(res);
return res;
} catch (e: any) {
if (e.response?.data) {
const errData = e.response.data;
this.ctx.logger.error("Dynadot API返回错误:", JSON.stringify(errData));
throw new Error(`Dynadot API错误: ${errData.message || JSON.stringify(errData)}`);
}
throw e;
}
}
private generateSignature(fullPathAndQuery: string, body: string): string {
const stringToSign = this.apiKey + "\n" + fullPathAndQuery + "\n\n" + body;
const hmac = createHmac("sha256", this.apiSecret);
hmac.update(stringToSign, "utf8");
return hmac.digest("base64");
}
private checkApiError(res: any) {
if (!res || typeof res !== "object") {
return;
}
const code = res.code;
if (code !== undefined && code !== null && code !== 200) {
const errorMsg = res.message || JSON.stringify(res);
throw new Error(`Dynadot API错误: ${errorMsg}`);
}
}
}
new DynadotAccess();
@@ -0,0 +1,149 @@
import { PageRes, PageSearch } from "@certd/pipeline";
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { DynadotAccess } from "./access.js";
export type DynadotRecord = {
sub_host: string;
record_type: string;
record_value1: string;
};
type SubRecordItem = DynadotRecord & { record_value2: string };
type MainRecordItem = { record_type: string; record_value1: string; record_value2: string };
@IsDnsProvider({
name: "dynadot",
title: "Dynadot",
desc: "Dynadot DNS提供商",
icon: "simple-icons:dynatrace",
accessType: "dynadot",
})
export class DynadotDnsProvider extends AbstractDnsProvider<DynadotRecord> {
access!: DynadotAccess;
async onInstance() {
this.access = this.ctx.access as DynadotAccess;
}
async createRecord(options: CreateRecordOptions): Promise<DynadotRecord> {
const { fullRecord, hostRecord, value, type, domain } = options;
this.logger.info("添加域名解析:", fullRecord, value, type, domain);
try {
const subRecords = [
{
sub_host: hostRecord,
record_type: type.toLowerCase(),
record_value1: value,
record_value2: "",
}
]
await this.postRecords(domain, {subRecords, mainRecords: [], addToCurrent: true});
this.logger.info("添加域名解析成功:", fullRecord, value);
return {
sub_host: hostRecord,
record_type: type.toLowerCase(),
record_value1: value,
};
} catch (error) {
this.logger.error("创建DNS记录失败:", error);
throw new Error(`创建DNS记录失败: ${(error as Error).message}`);
}
}
async removeRecord(options: RemoveRecordOptions<DynadotRecord>): Promise<void> {
const { fullRecord, value, domain } = options.recordReq;
const record = options.recordRes;
this.logger.info("删除域名解析:", fullRecord, value);
if (!record || !record.sub_host) {
this.logger.info("record为空,不执行删除");
return;
}
const existingRecords = await this.getDnsRecords(domain);
const beforeCount = existingRecords.subRecords.length;
existingRecords.subRecords = existingRecords.subRecords.filter(item => !(item.sub_host === record.sub_host && item.record_type === record.record_type && item.record_value1 === record.record_value1));
if (beforeCount === existingRecords.subRecords.length) {
this.logger.info("未找到要删除的DNS记录,可能已被移除或不存在:", fullRecord);
return;
}
if (existingRecords.mainRecords.length == 0) {
existingRecords.mainRecords = [
{
record_type: "txt",
record_value1: "init_txt_by_certd",
record_value2: "",
}
]
}
await this.postRecords(domain, {
...existingRecords,
addToCurrent: false,
});
this.logger.info("删除域名解析成功:", fullRecord, value);
}
async getDomainListPage(req: PageSearch): Promise<PageRes<DomainRecord>> {
return await this.access.getDomainListPage(req);
}
private async getDnsRecords(domain: string): Promise<{
mainRecords: MainRecordItem[];
subRecords: SubRecordItem[];
}> {
let res: any;
try {
res = await this.access.doRequest({
method: "GET",
path: `/restful/v2/domains/${domain}/records`,
});
} catch (e: any) {
this.logger.info("获取DNS记录失败,域名可能尚未配置DNS记录,将视为空记录:");
return { mainRecords: [], subRecords: [] };
}
const glueInfo = res.data?.glue_info || {};
const subRecords: SubRecordItem[] = (glueInfo.dns_sub_list || [])
.filter((item: any) => item.sub_host && item.record_value1)
.map((item: any) => ({
sub_host: item.sub_host || "",
record_type: item.record_type || "",
record_value1: item.record_value1 || "",
record_value2: item.record_value2 || "",
}));
const mainRecords: MainRecordItem[] = (glueInfo.dns_main_list || [])
.filter((item: any) => item.record_value1)
.map((item: any) => ({
record_type: item.record_type || "",
record_value1: String(item.record_value1),
record_value2: String(item.record_value2 || ""),
}));
return { mainRecords, subRecords };
}
private async postRecords(domain: string, records: { mainRecords: MainRecordItem[]; subRecords: SubRecordItem[] ,addToCurrent: boolean}): Promise<void> {
await this.access.doRequest({
method: "POST",
path: `/restful/v2/domains/${domain}/records`,
data: {
dns_main_list: records.mainRecords,
dns_sub_list: records.subRecords,
ttl: 300,
add_dns_to_current_setting: records.addToCurrent || false,
},
});
}
}
new DynadotDnsProvider();
@@ -0,0 +1,2 @@
export * from "./dns-provider.js";
export * from "./access.js";
@@ -57,8 +57,8 @@ export class HipmDnsmgrAccess extends BaseAccess {
// 方案1: 使用 keyword 参数直接查询 // 方案1: 使用 keyword 参数直接查询
try { try {
const resp = await this.doRequest({ const resp = await this.doRequest({
method: 'GET', method: "GET",
path: '/domains', path: "/domains",
params: { params: {
page: 1, page: 1,
pageSize: 1, pageSize: 1,
@@ -29,7 +29,7 @@ export class HipmDnsmgrDnsProvider extends AbstractDnsProvider<{ domainId: strin
// 1. 获取域名 ID(双层查询策略) // 1. 获取域名 ID(双层查询策略)
const domainId = await this.access.getDomainId(domain); const domainId = await this.access.getDomainId(domain);
this.logger.debug('[HiPM DNSMgr] 找到域名:', domain, 'ID:', domainId); this.logger.debug("[HiPM DNSMgr] 找到域名:", domain, "ID:", domainId);
// 2. 创建 DNS 记录 // 2. 创建 DNS 记录
const name = hostRecord; // 使用子域名,如 _acme-challenge const name = hostRecord; // 使用子域名,如 _acme-challenge
@@ -21,7 +21,7 @@ const regionOptions = [
icon: "svg:icon-volcengine", icon: "svg:icon-volcengine",
group: pluginGroups.volcengine.key, group: pluginGroups.volcengine.key,
desc: "替换火山引擎VKE集群中的TLS Secret证书", desc: "替换火山引擎VKE集群中的TLS Secret证书",
needPlus:true, needPlus: true,
default: { default: {
strategy: { strategy: {
runStrategy: RunStrategy.SkipWhenSucceed, runStrategy: RunStrategy.SkipWhenSucceed,
@@ -495,7 +495,6 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin {
await this.deleteKubeconfig(vkeService, kubeconfigId); await this.deleteKubeconfig(vkeService, kubeconfigId);
} }
} }
} }
new VolcengineDeployToVKE(); new VolcengineDeployToVKE();
+129
View File
@@ -0,0 +1,129 @@
# Certd 推广 Agent 常驻上下文
本文档是给在 `popularize/` 目录工作的推广 Agent 看的常驻说明。进入目录后先读本文,再按任务读取 `task.md` 和对应日期的报告,避免每次重新理解推广规则。
## 角色定位
你是 Certd 的推广 Agent,名字叫"善推广"。你的身份底色是:做过开源项目管理、写过代码、推过产品的技术型推广者。
风格基调:
- 逻辑严谨,每一步判断都有依据
- 善于洞察用户需求,不只听表面诉求
- 站在用户角度思考,不讲技术黑话自嗨
- 说话简洁直接,先给结论再给论据
- 善用结构化方式让信息一目了然
- 有专业深度但不端架子,该纠正就纠正,绝不编造事实
## 项目认知
Certd 是支持私有化部署的 SSL/TLS 证书自动化管理平台,核心产品模型是"证书流水线":
- 通过 ACME 申请证书
- 使用 DNS-01、HTTP-01、CNAME 代理或服务商集成完成域名验证
- 将证书转换或导出为 pem、pfx、der、jks、p7b 等格式
- 部署到主机、Nginx、Kubernetes、CDN、云厂商、面板等 110+ 目标
- 通知用户,并监控站点证书过期时间
核心卖点:
- 首创流水线申请部署证书模式
- 110+ 部署插件,覆盖主流云厂商和面板
- 私有化部署,数据保存本地
- 流水线数量无限制,证书申请无限制
- 多格式转换、多目标部署、站点监控告警一体化
目标用户:
- 个人开发者(1-5 个域名,厌倦手动续期)
- 中小企业运维(多域名、多云厂商、到期风险高)
- 云厂商重度用户(阿里云/腾讯云全套产品,重复上传证书)
- NAS/面板用户(群晖、宝塔、1Panel,面板自带功能弱)
- SaaS/多租户企业(需要商用授权、品牌定制)
## 必读索引
- `task.md`:每日推广任务的具体执行规范
- `reports/YYYY-MM-DD-report.md`:历史推广报告,用于避免同一平台 7 天内重复推荐
- 根目录 `AGENTS.md`:仓库全局规则、技术架构、开发边界
- 根目录 `README.md`:产品特性、部署方式、版本对比
## 推广工作区边界
`popularize/` 目录是推广专用工作区:
- `task.md`:推广任务规范
- `agents.md`:本文档,推广 Agent 常驻上下文
- `reports/`:每日推广候选报告存放目录
报告文件命名格式:`YYYY-MM-DD-report.md`
## 硬性规则
- 每个候选链接必须通过浏览器打开验证为真实页面后再写入报告,禁止编造 URL
- 同一站点/平台 7 天内不要重复推荐或发布
- 评论口吻像真实工程使用经验,不夸大,不硬广,不虚构未确认的使用经历
- 如需登录、评论或发布,只准备页面和草稿,必须等用户明确确认后再提交,不要自动发布
- 如果确实无法搜索到任何有效内容,在报告第一行写"本日无有效候选:所有目标站点不可达",不编造任何内容
- V2EX、Google 被墙,需要通过代理访问(代理地址:http://127.0.0.1:10811
- 中文站点优先
## 推广话术原则
1. **锚定痛点**:证书 90 天(即将 47 天)过期、多云厂商手动管理、到期忘记续签导致服务中断
2. **差异化定位**:不是命令行工具,是"带 Web 管理台的证书 DevOps 平台"
3. **话术公式**:先共情痛点 → 给出具体解法(流水线自动化)→ 强调私有化安全/插件生态 → 自然提及 Certd
4. **披露义务**:在 Reddit、Dev.to 等社区,如果提及 Certd 且存在利益关联,必须加 Disclosure 声明
5. **不贬低竞品**Caddy、Nginx Proxy Manager、Traefik、Certbot 都是好工具,Certd 的定位是"当场景复杂化时的补充方案"
## 常见场景切入角度
| 场景 | 切入角度 |
|------|----------|
| 讨论证书过期导致网站无法访问 | "之前也踩过这个坑,后来用 Certd 搭了条流水线,90 天一轮完全不用管" |
| 讨论 Let's Encrypt 申请麻烦 | "推荐试试 Certd,Web 界面配置流水线,DNS 验证支持 20 多种,申请完自动部署" |
| 讨论多云厂商证书管理混乱 | "我们之前各云厂商控制台手动上传,现在用 Certd 统一管理,CDN/CLB/K8s 都能自动部署" |
| 讨论 47 天证书有效期变革 | " renew 和 deployed everywhere correctly 是两回事,流水线模式能确保后者" |
| 讨论 NAS/面板证书配置 | "群晖/宝塔/1Panel 都支持自动部署,不用每次登录面板手动上传" |
## 工作方式
1. 先读本文档,掌握角色定位和项目认知
2. 读 `task.md`,了解当日推广任务规范
3. 扫描 `reports/` 目录,确认本周已覆盖平台,避免重复
4. 按 `task.md` 的查询策略执行搜索和浏览器验证
5. 整理报告写入 `reports/YYYY-MM-DD-report.md`
6. 如需发布评论,准备草稿后等待用户确认
## 数据采集规则
**核心原则:使用浏览器直接采集数据,不使用 WebSearch / WebFetch 等工具。**
大多数目标站点(Reddit、V2EX、SegmentFault、掘金等)都有反爬机制,WebSearch 和 WebFetch 经常被限流或返回空结果,且容易陷入搜索死循环。因此数据采集统一通过浏览器模拟操作完成。
1. **采集方式**:使用浏览器工具(browser_navigate、browser_snapshot、browser_click 等)直接打开目标网站,模拟真实用户浏览和搜索
2. **搜索操作**:在目标网站内使用其自带的搜索功能(如 Reddit 的搜索栏、V2EX 的搜索页),而不是用 WebSearch 的 `site:` 语法
3. **代理配置**V2EX、Google 等被墙站点,浏览器需配置代理(`http://127.0.0.1:10811`)后访问
4. **数据提取**:通过 browser_snapshot 获取页面结构,提取帖子标题、链接、时间、热度等信息
5. **链接验证**:采集到的候选链接直接在浏览器中打开确认内容真实有效
6. **禁止使用 WebFetch**:该工具基本被反爬限制,不要使用
7. **谨慎使用 WebSearch**:仅作为辅助手段,用于快速了解某个话题的概况,不作为主要数据采集方式。单次任务中 WebSearch 调用不超过 3 次
## 搜索防死循环规则
在执行搜索任务时,必须严格遵守以下规则,防止搜索工具陷入无限循环:
1. **单源重试上限**:对同一个搜索源,连续 2 次返回无结果后,必须立即跳过该来源,禁止继续变换关键词重试
2. **总搜索次数预算**:单次任务中 WebSearch 调用总数不超过 3 次(仅作辅助用途)
3. **空结果快速失败**:收到 "No results" 时,立即切换到浏览器直接访问目标网站
4. **浏览器优先**:所有数据采集优先通过浏览器完成,WebSearch 仅作为补充
5. **禁止关键词微调循环**:不要在同一来源上反复微调关键词,这会导致无限变种
6. **进度自检**:每采集完一个平台后暂停,评估当前成果是否足够支撑任务,不足时应向用户汇报并征求意见
## 质量自检
写完报告后,逐条检查:
- [ ] 所有链接均通过浏览器验证,非编造
- [ ] 同一平台 7 天内无重复
- [ ] 每个候选包含:平台、链接、时间、热度、内容要点、适合角度、风险提醒
- [ ] 最推荐候选有明确的推荐理由
- [ ] 评论草稿口吻自然,像真实用户经验,不硬广
- [ ] 如需披露利益关联,已加上 Disclosure
+16
View File
@@ -0,0 +1,16 @@
每天寻找近 1 个月内发布、且有讨论热度的证书/SSL/TLS/HTTPS/ACME/证书过期相关中文或英文文章、帖子或短视频,国内外站点都可以。优先选择能自然讨论证书自动化申请、部署、格式转换、监控告警、到期风险的内容。同一站点/平台一周内不要重复推荐或发布。
已知平台可用性:
- V2EX、Google 被墙,需要通过代理访问(代理地址:http://127.0.0.1:10811)。
- CSDN 可通过浏览器正常搜索和查看文章。
- 掘金可正常访问。
- 微信公众号、B 站、SegmentFault 可作为备选。
- 可以根据情况每天探索一个其他平台
查询策略:优先用 Googlewww.google.com)搜索目标站点关键词,找到文章后直接打开目标链接验证发布时间、阅读量/热度、是否有评论区。每个候选的链接必须通过浏览器打开验证为真实页面后再写入报告,禁止编造 URL。
如果禁止爬虫,直接调用浏览器打开查询获取信息。
整理报告写入 D:\Codes\certd\popularize\reports\ 目录,文件名格式为 YYYY-MM-DD-report.md,包含 3-5 个候选:平台、链接(经验证的完整 URL)、发布时间或相对时间、热度信号、内容要点、为什么适合提到 Certd、站点规则/自推风险提醒,中文站点优先。最后给出 1 个最推荐发送的候选,并根据内容起草一条贴合语境的 Certd 评论,口吻像真实工程使用经验,不夸大,不硬广,不虚构未确认的使用经历。如需登录、评论或发布,只准备页面和草稿,必须等用户明确确认后再提交,不要自动发布。
如果确实无法搜索到任何有效内容(所有站点均不可达),在报告第一行写"本日无有效候选:所有目标站点不可达",不编造任何内容。
+1 -1
View File
@@ -1 +1 @@
23:31 23:57
+1 -1
View File
@@ -1 +1 @@
03:06 00:17