@karinjs/plugin-basic 1.2.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,127 @@
1
+ import {
2
+ plugin
3
+ } from "./chunk-W3Q26Z2E.js";
4
+
5
+ // src/utils/utils.ts
6
+ import karin, { config, logger } from "node-karin";
7
+ var sendToFirstAdmin = async (selfId, message) => {
8
+ const list = config.master();
9
+ let master = list[0];
10
+ if (master === "console") {
11
+ master = list[1];
12
+ }
13
+ try {
14
+ if (!master) return false;
15
+ const a = await karin.sendMaster(selfId, master, message);
16
+ return a.messageId;
17
+ } catch (error) {
18
+ logger.bot("info", selfId, `[${master}] \u53D1\u9001\u4E3B\u52A8\u6D88\u606F\u5931\u8D25:`);
19
+ logger.error(error);
20
+ }
21
+ };
22
+
23
+ // src/config/config.ts
24
+ import fs from "fs";
25
+ import path from "path";
26
+ import { watch, filesByExt, requireFileSync, logger as logger2 } from "node-karin";
27
+ var Config = class {
28
+ /** 配置缓存 */
29
+ cache;
30
+ /** 用户配置目录 */
31
+ dir = plugin.ConfigDir;
32
+ /** 配置文件路径 */
33
+ configPath = path.join(this.dir, "config.json");
34
+ /** 默认配置 */
35
+ defaultConfig = {
36
+ status: true,
37
+ forward: true,
38
+ restartMode: true,
39
+ restart: true,
40
+ domain: "",
41
+ autoupdate: false,
42
+ autorestart: 0
43
+ };
44
+ constructor() {
45
+ this.init();
46
+ this.watchConfig();
47
+ }
48
+ /**
49
+ * 初始化配置文件
50
+ */
51
+ init() {
52
+ if (!fs.existsSync(this.dir)) {
53
+ fs.mkdirSync(this.dir, { recursive: true });
54
+ }
55
+ if (!fs.existsSync(this.configPath)) {
56
+ fs.writeFileSync(
57
+ this.configPath,
58
+ JSON.stringify(this.defaultConfig, null, 2)
59
+ );
60
+ }
61
+ }
62
+ /**
63
+ * 监听配置文件变化
64
+ */
65
+ watchConfig() {
66
+ setTimeout(() => {
67
+ const list = filesByExt(this.dir, ".json", "abs");
68
+ list.forEach((file) => {
69
+ watch(file, () => {
70
+ this.cache = void 0;
71
+ });
72
+ });
73
+ }, 2e3);
74
+ }
75
+ /**
76
+ * 获取配置
77
+ * @returns 配置对象
78
+ */
79
+ get() {
80
+ if (this.cache) {
81
+ return this.cache;
82
+ }
83
+ try {
84
+ const userConfig = requireFileSync(this.configPath);
85
+ const result = { ...this.defaultConfig, ...userConfig };
86
+ this.cache = result;
87
+ return result;
88
+ } catch (error) {
89
+ logger2.error("\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E:", error);
90
+ return { ...this.defaultConfig };
91
+ }
92
+ }
93
+ /**
94
+ * 写入配置
95
+ * @param config 配置对象
96
+ */
97
+ write(config2) {
98
+ try {
99
+ const result = { ...this.defaultConfig, ...config2 };
100
+ this.cache = result;
101
+ fs.writeFileSync(this.configPath, JSON.stringify(result, null, 2));
102
+ } catch (error) {
103
+ logger2.error("\u5199\u5165\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:", error);
104
+ throw error;
105
+ }
106
+ }
107
+ /**
108
+ * 更新配置(合并现有配置)
109
+ * @param config 要更新的配置项
110
+ */
111
+ update(config2) {
112
+ const current = this.get();
113
+ this.write({ ...current, ...config2 });
114
+ }
115
+ /**
116
+ * 重置为默认配置
117
+ */
118
+ reset() {
119
+ this.write(this.defaultConfig);
120
+ }
121
+ };
122
+ var cfg = new Config();
123
+
124
+ export {
125
+ sendToFirstAdmin,
126
+ cfg
127
+ };
@@ -0,0 +1,131 @@
1
+ // src/utils/dir.ts
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import { fileURLToPath } from "url";
5
+ import { karinPathBase } from "node-karin";
6
+
7
+ // package.json
8
+ var package_default = {
9
+ name: "@karinjs/plugin-basic",
10
+ version: "1.3.2",
11
+ description: "Karin\u7684\u57FA\u7840\u63D2\u4EF6,\u63D0\u4F9B\u6700\u57FA\u7840\u7684\u529F\u80FD",
12
+ homepage: "https://github.com/KarinJS/karin-plugin-basic",
13
+ bugs: {
14
+ url: "https://github.com/KarinJS/karin-plugin-basic/issues"
15
+ },
16
+ repository: {
17
+ type: "git",
18
+ url: "git+https://github.com/KarinJS/karin-plugin-basic.git"
19
+ },
20
+ author: "shijin",
21
+ type: "module",
22
+ main: "dist/index.js",
23
+ files: [
24
+ "dist",
25
+ "config",
26
+ "resources",
27
+ "LICENSE",
28
+ "package.json",
29
+ "README.md"
30
+ ],
31
+ scripts: {
32
+ build: "tsc && tsup",
33
+ pub: "npm publish --access public",
34
+ sort: "npx sort-package-json",
35
+ dev: "tsx src/app.ts",
36
+ watch: "tsx watch src/index.ts",
37
+ karin: "karin"
38
+ },
39
+ devDependencies: {
40
+ "@karinjs/plugin-puppeteer": "^1.1.2",
41
+ "@types/node": "^25.0.3",
42
+ eslint: "^9.39.2",
43
+ neostandard: "^0.12.2",
44
+ "node-karin": "^1.14.1",
45
+ tsup: "^8.5.1",
46
+ tsx: "^4.21.0",
47
+ typescript: "^5.9.3"
48
+ },
49
+ publishConfig: {
50
+ access: "public",
51
+ registry: "https://registry.npmjs.org"
52
+ },
53
+ karin: {
54
+ main: "src/index.ts",
55
+ apps: [
56
+ "dist/apps"
57
+ ],
58
+ "ts-apps": [
59
+ "src/apps"
60
+ ],
61
+ static: [
62
+ "resources"
63
+ ],
64
+ files: [
65
+ "config"
66
+ ],
67
+ "ts-web": "src/web.config.ts",
68
+ web: "dist/web.config.js"
69
+ },
70
+ dependencies: {
71
+ "internal-ip": "^8.0.1"
72
+ }
73
+ };
74
+
75
+ // src/utils/dir.ts
76
+ var __filename = fileURLToPath(import.meta.url);
77
+ var filePath = path.resolve(__filename.replace(/\\/g, "/"), "../../..");
78
+ if (!fs.existsSync(path.join(filePath, "package.json"))) {
79
+ filePath = path.resolve(__filename.replace(/\\/g, "/"), "../..");
80
+ }
81
+ var plugin = {
82
+ /** 插件名 */
83
+ name: package_default.name.replace(/\//g, "-"),
84
+ /** 插件版本 */
85
+ version: package_default.version,
86
+ /** 插件绝对路径 */
87
+ dir: filePath,
88
+ /** 插件 package.json */
89
+ pkg: package_default,
90
+ /** 插件在 @karinjs 中的目录 */
91
+ get BaseDir() {
92
+ return path.join(karinPathBase, this.name);
93
+ },
94
+ /** 配置文件路径 */
95
+ get ConfigDir() {
96
+ return path.join(this.BaseDir, "config");
97
+ }
98
+ };
99
+
100
+ // src/utils/render.ts
101
+ import path2 from "path";
102
+ import { segment, karin, config } from "node-karin";
103
+ var copyright = `${plugin.name} ${plugin.pkg.version} - Copyright \xA9 2025 KarinJS | Powered by Karin v${config.pkg().version}`;
104
+ var render = async (name, params) => {
105
+ name = name.replace(/.html$/, "");
106
+ const root = path2.join(plugin.dir, "resources");
107
+ const img = await karin.render({
108
+ name: path2.basename(name),
109
+ type: "png",
110
+ file: path2.join(root, `${name}.html`),
111
+ data: {
112
+ pluResPath: `${root}/`,
113
+ sys: {
114
+ copyright
115
+ },
116
+ ...params
117
+ },
118
+ pageGotoParams: {
119
+ waitUntil: "networkidle0"
120
+ },
121
+ setViewport: {
122
+ deviceScaleFactor: 3
123
+ }
124
+ });
125
+ return segment.image(`${img.includes("base64://") ? img : `base64://${img}`}`);
126
+ };
127
+
128
+ export {
129
+ plugin,
130
+ render
131
+ };
package/dist/index.js CHANGED
@@ -7,6 +7,23 @@ import {
7
7
  initStat,
8
8
  uptime
9
9
  } from "./chunk-ODFXVVIE.js";
10
+ import {
11
+ cfg
12
+ } from "./chunk-7LNXK3JJ.js";
13
+ import {
14
+ plugin
15
+ } from "./chunk-W3Q26Z2E.js";
16
+
17
+ // src/index.ts
18
+ import { logger, restartDirect } from "node-karin";
19
+ var autorestart = +cfg.get().autorestart;
20
+ if (autorestart && typeof autorestart === "number" && autorestart > 0) {
21
+ setTimeout(() => {
22
+ logger.info(`${logger.violet(`[\u63D2\u4EF6:${plugin.name}]`)} \u5F00\u59CB\u81EA\u52A8\u91CD\u542F...`);
23
+ restartDirect();
24
+ }, autorestart * 1e3);
25
+ }
26
+ logger.info(`${logger.violet(`[\u63D2\u4EF6:${plugin.name}]`)} ${logger.green(plugin.version)} \u521D\u59CB\u5316\u5B8C\u6210~`);
10
27
  export {
11
28
  MB,
12
29
  createKey,
@@ -12,6 +12,10 @@ interface Config {
12
12
  restart: boolean;
13
13
  /** 自定义登录域名 */
14
14
  domain: string;
15
+ /** 是否自动更新 */
16
+ autoupdate: boolean;
17
+ /** 自动重启延迟时间,单位秒,0表示不自动重启 */
18
+ autorestart: number | string;
15
19
  }
16
20
 
17
21
  declare const _default: node_karin.DefineConfig<Config>;
@@ -1,65 +1,78 @@
1
1
  import {
2
- config,
3
- info,
4
- writeConfig
5
- } from "./chunk-MNDJRJH2.js";
2
+ cfg
3
+ } from "./chunk-7LNXK3JJ.js";
4
+ import {
5
+ plugin
6
+ } from "./chunk-W3Q26Z2E.js";
6
7
 
7
8
  // src/web.config.ts
8
9
  import { components, defineConfig } from "node-karin";
9
10
  var web_config_default = defineConfig({
10
11
  info: {
11
- id: info.name,
12
+ id: plugin.name,
12
13
  name: "\u57FA\u7840\u63D2\u4EF6",
13
- version: info.version,
14
- description: info.pkg.description,
14
+ version: plugin.version,
15
+ description: plugin.pkg.description,
15
16
  author: [
16
17
  {
17
- name: info.pkg.author,
18
+ name: plugin.pkg.author,
18
19
  avatar: "https://github.com/sj817.png"
19
20
  }
20
21
  ]
21
22
  },
22
23
  /** 动态渲染的组件 */
23
24
  components: () => {
24
- const cfg = config();
25
+ const config = cfg.get();
25
26
  const list = [
26
27
  components.switch.create("status", {
27
28
  color: "success",
28
29
  label: "\u7EDF\u8BA1\u72B6\u6001",
29
30
  description: "\u5173\u95ED\u540E\u53EF\u964D\u4F4Eredis\u538B\u529B...",
30
- defaultSelected: cfg.status
31
+ defaultSelected: config.status
31
32
  }),
32
33
  components.switch.create("forward", {
33
34
  color: "success",
34
35
  label: "\u66F4\u65B0\u8F6C\u53D1",
35
36
  description: "\u5168\u90E8\u66F4\u65B0\u662F\u5426\u4F7F\u7528\u8F6C\u53D1",
36
- defaultSelected: cfg.forward
37
+ defaultSelected: config.forward
37
38
  }),
38
39
  components.switch.create("restartMode", {
39
40
  color: "success",
40
41
  label: "\u91CD\u542F\u65B9\u5F0F",
41
42
  description: "\u6253\u5F00\u4E3A\u524D\u53F0\u91CD\u542F \u5173\u95ED\u4E3A\u540E\u53F0\u91CD\u542F",
42
- defaultSelected: cfg.restartMode
43
+ defaultSelected: config.restartMode
43
44
  }),
44
45
  components.switch.create("restart", {
45
46
  color: "success",
46
47
  label: "\u81EA\u52A8\u91CD\u542F",
47
48
  description: "\u66F4\u65B0\u5B8C\u6210\u662F\u5426\u81EA\u52A8\u91CD\u542F",
48
- defaultSelected: cfg.restart
49
+ defaultSelected: config.restart
49
50
  }),
50
51
  components.input.string("domain", {
51
52
  color: "success",
52
53
  label: "\u81EA\u5B9A\u4E49\u57DF\u540D",
53
54
  description: "Web\u767B\u5F55\u53D1\u9001\u7684\u81EA\u5B9A\u4E49\u57DF\u540D",
54
- defaultValue: cfg.domain,
55
+ defaultValue: config.domain,
55
56
  isRequired: false
57
+ }),
58
+ components.switch.create("autoupdate", {
59
+ color: "success",
60
+ label: "\u81EA\u52A8\u66F4\u65B0",
61
+ description: "\u662F\u5426\u542F\u7528\u81EA\u52A8\u66F4\u65B0",
62
+ defaultSelected: config.autoupdate
63
+ }),
64
+ components.input.number("autorestart", {
65
+ color: "success",
66
+ label: "\u81EA\u52A8\u91CD\u542F\u5EF6\u8FDF\u65F6\u95F4",
67
+ description: "\u81EA\u52A8\u91CD\u542F\u5EF6\u8FDF\u65F6\u95F4\uFF0C\u5355\u4F4D\u79D2\uFF0C0\u8868\u793A\u4E0D\u81EA\u52A8\u91CD\u542F",
68
+ defaultValue: config.autorestart + ""
56
69
  })
57
70
  ];
58
71
  return list;
59
72
  },
60
73
  /** 前端点击保存之后调用的方法 */
61
- save: (config2) => {
62
- writeConfig(config2);
74
+ save: (config) => {
75
+ cfg.write(config);
63
76
  return {
64
77
  success: true,
65
78
  message: "\u4FDD\u5B58\u6210\u529F"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@karinjs/plugin-basic",
3
- "version": "1.2.1",
4
- "description": "karin plugin for basic functions",
3
+ "version": "1.3.2",
4
+ "description": "Karin的基础插件,提供最基础的功能",
5
5
  "homepage": "https://github.com/KarinJS/karin-plugin-basic",
6
6
  "bugs": {
7
7
  "url": "https://github.com/KarinJS/karin-plugin-basic/issues"
@@ -51,6 +51,6 @@
51
51
  "web": "dist/web.config.js"
52
52
  },
53
53
  "dependencies": {
54
- "internal-ip": "^8.0.0"
54
+ "internal-ip": "^8.0.1"
55
55
  }
56
56
  }
Binary file
Binary file
@@ -0,0 +1,215 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif, 'Microsoft YaHei';
9
+ background: linear-gradient(135deg, #c7d2fe 0%, #fbcfe8 50%, #a5f3fc 100%);
10
+ padding: 20px;
11
+ display: flex;
12
+ align-items: flex-start;
13
+ }
14
+
15
+ .container {
16
+ max-width: 1400px;
17
+ margin: 0 auto;
18
+ background: rgba(255, 255, 255, 0.96);
19
+ border-radius: 18px;
20
+ box-shadow: 0 18px 45px rgba(148, 163, 184, 0.45);
21
+ overflow: hidden;
22
+ }
23
+
24
+ .header {
25
+ position: relative;
26
+ padding: 30px;
27
+ color: #0f172a;
28
+ overflow: hidden;
29
+ background: url('../img/logger.png') center/cover no-repeat, #e0f2ff;
30
+ border-bottom: 1px solid rgba(148, 163, 184, 0.35);
31
+ }
32
+
33
+ .header h1,
34
+ .header .info {
35
+ position: relative;
36
+ z-index: 2;
37
+ }
38
+
39
+ .header-bg-text {
40
+ position: absolute;
41
+ inset: 0;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ font-size: 92px;
46
+ font-weight: 800;
47
+ letter-spacing: 0.12em;
48
+ text-transform: uppercase;
49
+ color: rgba(30, 64, 175, 0.2);
50
+ filter: blur(2px);
51
+ pointer-events: none;
52
+ z-index: 1;
53
+ }
54
+
55
+ .header h1 {
56
+ font-size: 32px;
57
+ margin-bottom: 15px;
58
+ font-weight: 600;
59
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
60
+ }
61
+
62
+ .info {
63
+ display: flex;
64
+ gap: 20px;
65
+ font-size: 14px;
66
+ opacity: 0.95;
67
+ }
68
+
69
+ .info span {
70
+ background: rgba(255, 255, 255, 0.2);
71
+ padding: 6px 12px;
72
+ border-radius: 6px;
73
+ backdrop-filter: blur(10px);
74
+ }
75
+
76
+ .logs-container {
77
+ padding: 20px;
78
+ /* 让截图包含全部日志,不使用内部滚动条 */
79
+ overflow: visible;
80
+ }
81
+
82
+ .log-item {
83
+ display: flex;
84
+ align-items: flex-start;
85
+ padding: 12px 16px;
86
+ margin-bottom: 8px;
87
+ border-radius: 8px;
88
+ background: #f9fafb;
89
+ border-left: 4px solid #e5e7eb;
90
+ transition: all 0.2s ease;
91
+ font-size: 13px;
92
+ line-height: 1.6;
93
+ }
94
+
95
+ .log-item:hover {
96
+ transform: translateX(4px);
97
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
98
+ }
99
+
100
+ .log-time {
101
+ color: #6c757d;
102
+ font-family: 'Consolas', 'Monaco', monospace;
103
+ min-width: 100px;
104
+ margin-right: 12px;
105
+ font-weight: 500;
106
+ }
107
+
108
+ .log-level {
109
+ display: inline-block;
110
+ padding: 2px 10px;
111
+ border-radius: 4px;
112
+ font-weight: 600;
113
+ text-transform: uppercase;
114
+ font-size: 11px;
115
+ min-width: 60px;
116
+ text-align: center;
117
+ margin-right: 12px;
118
+ }
119
+
120
+ .level-debug {
121
+ background: #9ca3af;
122
+ color: white;
123
+ }
124
+
125
+ .level-info {
126
+ background: #38bdf8;
127
+ color: white;
128
+ }
129
+
130
+ .level-mark {
131
+ background: #a855f7;
132
+ color: white;
133
+ }
134
+
135
+ .level-warn {
136
+ background: #facc15;
137
+ color: #422006;
138
+ }
139
+
140
+ .level-error {
141
+ background: #ef4444;
142
+ color: white;
143
+ }
144
+
145
+ .level-fatal {
146
+ background: #000;
147
+ color: white;
148
+ }
149
+
150
+ .log-message {
151
+ flex: 1;
152
+ word-break: break-all;
153
+ color: #212529;
154
+ font-family: 'Consolas', 'Monaco', monospace;
155
+ white-space: pre-wrap;
156
+ }
157
+
158
+ /* 不同日志级别的边框颜色 */
159
+ .log-debug {
160
+ border-left-color: #d1d5db;
161
+ background: #f9fafb;
162
+ }
163
+
164
+ .log-info {
165
+ border-left-color: #93c5fd;
166
+ background: #e0f2fe;
167
+ }
168
+
169
+ .log-mark {
170
+ border-left-color: #c4b5fd;
171
+ background: #f3e8ff;
172
+ }
173
+
174
+ .log-warn {
175
+ border-left-color: #fcd34d;
176
+ background: #fef3c7;
177
+ }
178
+
179
+ .log-error {
180
+ border-left-color: #fca5a5;
181
+ background: #fee2e2;
182
+ }
183
+
184
+ .log-fatal {
185
+ border-left-color: #9ca3af;
186
+ background: #f5f5f5;
187
+ }
188
+
189
+ .footer {
190
+ background: #f8f9fa;
191
+ padding: 15px 30px;
192
+ text-align: center;
193
+ color: #6c757d;
194
+ font-size: 12px;
195
+ border-top: 1px solid #dee2e6;
196
+ }
197
+
198
+ /* 滚动条样式 */
199
+ .logs-container::-webkit-scrollbar {
200
+ width: 8px;
201
+ }
202
+
203
+ .logs-container::-webkit-scrollbar-track {
204
+ background: #f1f1f1;
205
+ border-radius: 4px;
206
+ }
207
+
208
+ .logs-container::-webkit-scrollbar-thumb {
209
+ background: #888;
210
+ border-radius: 4px;
211
+ }
212
+
213
+ .logs-container::-webkit-scrollbar-thumb:hover {
214
+ background: #555;
215
+ }
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Karin 日志</title>
8
+ <link rel="stylesheet" href="{{pluResPath}}logger/index.css">
9
+ </head>
10
+
11
+ <body>
12
+ <div class="container">
13
+ <div class="header">
14
+ <h1>📋 Karin 日志</h1>
15
+ <div class="info">
16
+ <span class="date">{{date}}</span>
17
+ <span class="count">共 {{total}} 条日志</span>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="logs-container">
22
+ {{each logs}}
23
+ <div class="log-item log-{{$value.level}}">
24
+ <span class="log-time">{{$value.time}}</span>
25
+ <span class="log-level level-{{$value.level}}">{{$value.level}}</span>
26
+ <span class="log-message">{{@ $value.messageHtml}}</span>
27
+ </div>
28
+ {{/each}}
29
+ </div>
30
+
31
+ <div class="footer">
32
+ <p>{{sys.copyright}}</p>
33
+ </div>
34
+ </div>
35
+ </body>
36
+
37
+ </html>