@skillbuilder/minitool-core 0.0.0-beta-20261027053041051
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.
- package/README.md +74 -0
- package/lib/di/index.js +21 -0
- package/lib/di/modules.js +23 -0
- package/lib/di/tokens.js +12 -0
- package/lib/index.js +29 -0
- package/lib/runtime.js +42 -0
- package/lib/services/index.js +19 -0
- package/lib/services/minitool-api.js +125 -0
- package/lib/services/minitool-contract.js +76 -0
- package/lib/services/minitool-service.js +161 -0
- package/lib/services/upload-service.js +183 -0
- package/lib/utils/config-merger.js +63 -0
- package/lib/utils/cos-uploader.js +120 -0
- package/lib/utils/env-helper.js +4 -0
- package/lib/utils/helper.js +46 -0
- package/lib/utils/loading.js +52 -0
- package/lib/utils/logger.js +83 -0
- package/lib/utils/open-browser.js +32 -0
- package/lib/utils/openChrome.applescript +78 -0
- package/lib/utils/output.js +19 -0
- package/lib/utils/port-finder.js +43 -0
- package/lib/utils/project-validator.js +233 -0
- package/lib/utils/request.js +73 -0
- package/lib/utils/table.js +29 -0
- package/lib/utils/to-hump.js +5 -0
- package/lib/utils/tracker/ai-apm.js +119 -0
- package/lib/utils/tracker/apm.js +73 -0
- package/lib/utils/tracker/cli-apm.js +188 -0
- package/lib/utils/tracker/device.js +30 -0
- package/lib/utils/tracker/index.js +21 -0
- package/lib/utils/tracker/tracker.js +2 -0
- package/package.json +32 -0
- package/types/di/index.d.ts +3 -0
- package/types/di/modules.d.ts +9 -0
- package/types/di/tokens.d.ts +9 -0
- package/types/index.d.ts +14 -0
- package/types/runtime.d.ts +24 -0
- package/types/services/index.d.ts +3 -0
- package/types/services/minitool-api.d.ts +30 -0
- package/types/services/minitool-contract.d.ts +103 -0
- package/types/services/minitool-service.d.ts +29 -0
- package/types/services/upload-service.d.ts +48 -0
- package/types/utils/config-merger.d.ts +6 -0
- package/types/utils/cos-uploader.d.ts +45 -0
- package/types/utils/env-helper.d.ts +1 -0
- package/types/utils/helper.d.ts +8 -0
- package/types/utils/loading.d.ts +15 -0
- package/types/utils/logger.d.ts +27 -0
- package/types/utils/open-browser.d.ts +2 -0
- package/types/utils/output.d.ts +7 -0
- package/types/utils/port-finder.d.ts +2 -0
- package/types/utils/project-validator.d.ts +25 -0
- package/types/utils/request.d.ts +26 -0
- package/types/utils/table.d.ts +9 -0
- package/types/utils/to-hump.d.ts +1 -0
- package/types/utils/tracker/ai-apm.d.ts +68 -0
- package/types/utils/tracker/apm.d.ts +21 -0
- package/types/utils/tracker/cli-apm.d.ts +47 -0
- package/types/utils/tracker/device.d.ts +8 -0
- package/types/utils/tracker/index.d.ts +5 -0
- package/types/utils/tracker/tracker.d.ts +22 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLI_MEASUREMENT_NAME = void 0;
|
|
4
|
+
exports.initCliApm = initCliApm;
|
|
5
|
+
exports.setCliApmCurrentCommand = setCliApmCurrentCommand;
|
|
6
|
+
exports.createCliCommandTracker = createCliCommandTracker;
|
|
7
|
+
exports.reportCliException = reportCliException;
|
|
8
|
+
exports.reportCliHttpError = reportCliHttpError;
|
|
9
|
+
exports.flushCliApm = flushCliApm;
|
|
10
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
|
+
/** CLI 通用埋点;不依赖小工具业务服务,也不读取本地凭据。 */
|
|
12
|
+
exports.CLI_MEASUREMENT_NAME = "redminitool_cli_usage";
|
|
13
|
+
let transport;
|
|
14
|
+
let cliVersion = "unknown";
|
|
15
|
+
let currentCmdPath;
|
|
16
|
+
let sequence = 0;
|
|
17
|
+
let sessionId = (0, node_crypto_1.randomUUID)();
|
|
18
|
+
const pending = new Set();
|
|
19
|
+
const controllers = new Set();
|
|
20
|
+
function createHttpTransport(endpoint) {
|
|
21
|
+
let url;
|
|
22
|
+
try {
|
|
23
|
+
url = new URL(endpoint);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
// 远端上报仅允许 HTTPS;本机 HTTP 用于联调和测试。
|
|
29
|
+
if (url.protocol !== "https:" &&
|
|
30
|
+
!(url.protocol === "http:" && ["localhost", "127.0.0.1"].includes(url.hostname))) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
async report(event) {
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
controllers.add(controller);
|
|
37
|
+
const timer = setTimeout(() => controller.abort(), 1500);
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: { "content-type": "application/json", batch: "true", "biz-type": "apm_fe" },
|
|
42
|
+
body: JSON.stringify([event]),
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok)
|
|
46
|
+
throw new Error(`APM HTTP ${response.status}`);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
controllers.delete(controller);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function initCliApm(options = {}) {
|
|
56
|
+
cliVersion = options.cliVersion || "unknown";
|
|
57
|
+
sessionId = (0, node_crypto_1.randomUUID)();
|
|
58
|
+
sequence = 0;
|
|
59
|
+
currentCmdPath = undefined;
|
|
60
|
+
transport =
|
|
61
|
+
options.transport ||
|
|
62
|
+
createHttpTransport(options.endpoint || process.env.REDMINITOOL_APM_ENDPOINT || "");
|
|
63
|
+
}
|
|
64
|
+
function setCliApmCurrentCommand(cmdPath) {
|
|
65
|
+
currentCmdPath = cmdPath;
|
|
66
|
+
}
|
|
67
|
+
function safeError(err) {
|
|
68
|
+
const error = err && typeof err === "object" ? err : {};
|
|
69
|
+
const message = typeof error.message === "string" ? error.message.toLowerCase() : "";
|
|
70
|
+
const rawCode = error.code ?? error.statusCode ?? error.status;
|
|
71
|
+
const errorCode = typeof rawCode === "number" && Number.isInteger(rawCode)
|
|
72
|
+
? rawCode
|
|
73
|
+
: typeof rawCode === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(rawCode)
|
|
74
|
+
? rawCode
|
|
75
|
+
: undefined;
|
|
76
|
+
let errorType = "unknown";
|
|
77
|
+
if (typeof errorCode === "number" && errorCode >= 400)
|
|
78
|
+
errorType = "http";
|
|
79
|
+
if (/http|request|fetch/.test(message))
|
|
80
|
+
errorType = "http";
|
|
81
|
+
if (/token|login|auth|secret/.test(message))
|
|
82
|
+
errorType = "auth";
|
|
83
|
+
if (/invalid|参数|校验/.test(message))
|
|
84
|
+
errorType = "validation";
|
|
85
|
+
// 不上报 message、stack 或任意服务端响应,避免 Secret/Token 从异常文本泄露。
|
|
86
|
+
return { error_type: errorType, ...(errorCode !== undefined ? { error_code: errorCode } : {}) };
|
|
87
|
+
}
|
|
88
|
+
function report(data) {
|
|
89
|
+
const target = transport;
|
|
90
|
+
if (!target)
|
|
91
|
+
return;
|
|
92
|
+
const event = {
|
|
93
|
+
context_nameTracker: "nodeT",
|
|
94
|
+
context_platform: process.platform,
|
|
95
|
+
context_appVersion: cliVersion,
|
|
96
|
+
context_matchedPath: "cli",
|
|
97
|
+
context_sdkSessionId: sessionId,
|
|
98
|
+
context_sdkSeqId: ++sequence,
|
|
99
|
+
clientTime: Date.now(),
|
|
100
|
+
measurement_name: exports.CLI_MEASUREMENT_NAME,
|
|
101
|
+
measurement_data: {
|
|
102
|
+
...data,
|
|
103
|
+
cli_version: cliVersion,
|
|
104
|
+
node_major: Number(process.versions.node.split(".")[0]),
|
|
105
|
+
is_ci: process.env.CI ? 1 : 0,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
let task;
|
|
109
|
+
task = Promise.resolve()
|
|
110
|
+
.then(() => target.report(event))
|
|
111
|
+
.then(() => undefined, () => undefined)
|
|
112
|
+
.finally(() => pending.delete(task));
|
|
113
|
+
pending.add(task);
|
|
114
|
+
}
|
|
115
|
+
function createCliCommandTracker(meta) {
|
|
116
|
+
setCliApmCurrentCommand(meta.cmd_path);
|
|
117
|
+
const base = {
|
|
118
|
+
event: "command",
|
|
119
|
+
cmd_path: meta.cmd_path,
|
|
120
|
+
...(meta.cmd_root ? { cmd_root: meta.cmd_root } : {}),
|
|
121
|
+
...(typeof meta.params_count === "number" ? { params_count: meta.params_count } : {}),
|
|
122
|
+
// 仅上报选项名称;认证参数名称也排除,永不传递参数值。
|
|
123
|
+
...(meta.options_keys
|
|
124
|
+
? {
|
|
125
|
+
options_keys: JSON.stringify(meta.options_keys.filter((key) => !/secret|token|password|credential|auth/i.test(key))),
|
|
126
|
+
}
|
|
127
|
+
: {}),
|
|
128
|
+
};
|
|
129
|
+
return {
|
|
130
|
+
reportSuccess(durationMs) {
|
|
131
|
+
report({ ...base, status: 1, duration: durationMs });
|
|
132
|
+
setCliApmCurrentCommand(undefined);
|
|
133
|
+
},
|
|
134
|
+
reportFail(durationMs, err) {
|
|
135
|
+
report({
|
|
136
|
+
...base,
|
|
137
|
+
status: 0,
|
|
138
|
+
duration: durationMs,
|
|
139
|
+
...safeError(err),
|
|
140
|
+
});
|
|
141
|
+
setCliApmCurrentCommand(undefined);
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function reportCliException(source, err) {
|
|
146
|
+
report({
|
|
147
|
+
event: "exception",
|
|
148
|
+
source,
|
|
149
|
+
...(currentCmdPath ? { cmd_path: currentCmdPath } : {}),
|
|
150
|
+
...safeError(err),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function reportCliHttpError(meta, err) {
|
|
154
|
+
let host;
|
|
155
|
+
try {
|
|
156
|
+
if (meta.url)
|
|
157
|
+
host = new URL(meta.url).host;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
/* 无效 URL 不影响业务 */
|
|
161
|
+
}
|
|
162
|
+
report({
|
|
163
|
+
event: "http_error",
|
|
164
|
+
...(meta.method ? { method: meta.method } : {}),
|
|
165
|
+
...(host ? { host } : {}),
|
|
166
|
+
...(typeof meta.status_code === "number" ? { status_code: meta.status_code } : {}),
|
|
167
|
+
...(currentCmdPath ? { cmd_path: currentCmdPath } : {}),
|
|
168
|
+
...(err ? safeError(err) : {}),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/** CLI 退出前最多等待一小段时间,超时后取消请求;上报失败永不影响命令结果。 */
|
|
172
|
+
async function flushCliApm(timeoutMs = 350) {
|
|
173
|
+
if (!pending.size)
|
|
174
|
+
return;
|
|
175
|
+
let timer;
|
|
176
|
+
await Promise.race([
|
|
177
|
+
Promise.allSettled([...pending]),
|
|
178
|
+
new Promise((resolve) => {
|
|
179
|
+
timer = setTimeout(() => {
|
|
180
|
+
for (const controller of controllers)
|
|
181
|
+
controller.abort();
|
|
182
|
+
resolve();
|
|
183
|
+
}, timeoutMs);
|
|
184
|
+
}),
|
|
185
|
+
]);
|
|
186
|
+
if (timer)
|
|
187
|
+
clearTimeout(timer);
|
|
188
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDeviceInfo = getDeviceInfo;
|
|
7
|
+
exports.deviceUA = deviceUA;
|
|
8
|
+
exports.machineId = machineId;
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
/** 本地诊断信息;CLI APM 不会自动采集或发送这些字段。 */
|
|
11
|
+
function getDeviceInfo() {
|
|
12
|
+
const cpu = node_os_1.default.cpus()[0];
|
|
13
|
+
return {
|
|
14
|
+
os_platform: process.platform,
|
|
15
|
+
os_arch: process.arch,
|
|
16
|
+
cpu_speed: cpu?.speed ?? 0,
|
|
17
|
+
cpu_model: cpu?.model ?? "",
|
|
18
|
+
machine_memory: Math.round(node_os_1.default.totalmem() / 1024 / 1024),
|
|
19
|
+
os_version: node_os_1.default.release(),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function deviceUA() {
|
|
23
|
+
return { node_version: process.version };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 旧版会读取硬件 UUID 并写 ~/.rcb/.device.json;该持久设备标识未获隐私评审,不再生成。
|
|
27
|
+
*/
|
|
28
|
+
function machineId() {
|
|
29
|
+
throw new Error("持久设备标识已禁用;需要先完成隐私评审");
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./apm"), exports);
|
|
18
|
+
__exportStar(require("./ai-apm"), exports);
|
|
19
|
+
__exportStar(require("./cli-apm"), exports);
|
|
20
|
+
__exportStar(require("./device"), exports);
|
|
21
|
+
__exportStar(require("./tracker"), exports);
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skillbuilder/minitool-core",
|
|
3
|
+
"version": "0.0.0-beta-20261027053041051",
|
|
4
|
+
"description": "小红书小工具 DI/IoC 业务核心与上传能力",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "types/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"types",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20.0.0"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"chalk": "^2.4.2",
|
|
17
|
+
"cli-table3": "^0.5.1",
|
|
18
|
+
"cos-nodejs-sdk-v5": "2.x",
|
|
19
|
+
"dayjs": "^1.11.13",
|
|
20
|
+
"inversify": "^7.11.0",
|
|
21
|
+
"log-symbols": "^3.0.0",
|
|
22
|
+
"open": "^7.4.2",
|
|
23
|
+
"ora": "^4.0.2",
|
|
24
|
+
"reflect-metadata": "0.2.2",
|
|
25
|
+
"terminal-link": "^2.1.1",
|
|
26
|
+
"zod": "4.3.5",
|
|
27
|
+
"jszip": "^3.10.1",
|
|
28
|
+
"@skillbuilder/minitool-cli-auth": "0.0.0-beta-20261027053041051",
|
|
29
|
+
"@skillbuilder/endpoints": "0.0.0-beta-20261027053041051"
|
|
30
|
+
},
|
|
31
|
+
"license": "ISC"
|
|
32
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AccessTokenProvider } from "@skillbuilder/minitool-cli-auth";
|
|
2
|
+
import { ContainerModule } from "inversify";
|
|
3
|
+
import { type MiniToolApiOptions } from "../services/minitool-api";
|
|
4
|
+
export interface MinitoolModuleOptions {
|
|
5
|
+
auth: AccessTokenProvider;
|
|
6
|
+
api: MiniToolApiOptions;
|
|
7
|
+
}
|
|
8
|
+
/** MiniTool Core 显式注册业务、传输及其窄依赖。 */
|
|
9
|
+
export declare function createMinitoolModule(options: MinitoolModuleOptions): ContainerModule;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./di";
|
|
2
|
+
export * from "./runtime";
|
|
3
|
+
export * from "./services";
|
|
4
|
+
export * from "./utils/tracker";
|
|
5
|
+
export * from "./utils/helper";
|
|
6
|
+
export * from "./utils/loading";
|
|
7
|
+
export * from "./utils/logger";
|
|
8
|
+
export * from "./utils/open-browser";
|
|
9
|
+
export * from "./utils/output";
|
|
10
|
+
export * from "./utils/port-finder";
|
|
11
|
+
export * from "./utils/project-validator";
|
|
12
|
+
export * from "./utils/request";
|
|
13
|
+
export * from "./utils/table";
|
|
14
|
+
export type { CosClientFactory, CosUploadClient } from "./utils/cos-uploader";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AccessTokenProvider } from "@skillbuilder/minitool-cli-auth";
|
|
2
|
+
import { type ContainerModule } from "inversify";
|
|
3
|
+
import type { MiniToolApiOptions } from "./services/minitool-api";
|
|
4
|
+
import type { IMiniToolService } from "./services/minitool-service";
|
|
5
|
+
import type { IUploadService } from "./services/upload-service";
|
|
6
|
+
export interface MinitoolServiceGraph {
|
|
7
|
+
readonly upload: IUploadService;
|
|
8
|
+
readonly miniTools: IMiniToolService;
|
|
9
|
+
}
|
|
10
|
+
export interface MinitoolRuntime extends MinitoolServiceGraph {
|
|
11
|
+
readonly isDisposed: boolean;
|
|
12
|
+
dispose(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface CreateMinitoolCoreOptions {
|
|
15
|
+
accessTokens: AccessTokenProvider;
|
|
16
|
+
api?: MiniToolApiOptions;
|
|
17
|
+
/**
|
|
18
|
+
* 在默认模块之后加载。测试可使用公共 Token + rebindSync 替换服务,
|
|
19
|
+
* 业务扩展也必须以显式 ContainerModule 接入,禁止目录扫描。
|
|
20
|
+
*/
|
|
21
|
+
modules?: readonly ContainerModule[];
|
|
22
|
+
}
|
|
23
|
+
/** 组装相互隔离、可释放的业务 Runtime;Container 不向调用方暴露。 */
|
|
24
|
+
export declare function createMinitoolCore(options: CreateMinitoolCoreOptions): MinitoolRuntime;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import type { AccessTokenProvider } from "@skillbuilder/minitool-cli-auth";
|
|
3
|
+
export declare const MINITOOL_ROUTES: Readonly<{
|
|
4
|
+
readonly config: readonly ["GET", "/api/sns/v2/creator/red_app/third/config"];
|
|
5
|
+
readonly list: readonly ["GET", "/api/sns/v2/creator/red_app/third/list"];
|
|
6
|
+
readonly status: readonly ["GET", "/api/sns/v2/creator/red_app/third/detail"];
|
|
7
|
+
readonly history: readonly ["GET", "/api/sns/v2/creator/red_app/third/history_version"];
|
|
8
|
+
readonly submit: readonly ["POST", "/api/sns/v2/creator/red_app/third/save"];
|
|
9
|
+
readonly edit: readonly ["POST", "/api/sns/v2/creator/red_app/third/base/save"];
|
|
10
|
+
readonly preview: readonly ["POST", "/api/sns/v2/creator/red_app/third/preview_code"];
|
|
11
|
+
readonly permit: readonly ["GET", "/api/sns/v2/red_skill/upload/permit"];
|
|
12
|
+
}>;
|
|
13
|
+
export type MiniToolOperation = keyof typeof MINITOOL_ROUTES;
|
|
14
|
+
export interface MiniToolApiOptions {
|
|
15
|
+
apiBaseUrl: string;
|
|
16
|
+
request?: typeof fetch;
|
|
17
|
+
}
|
|
18
|
+
export interface IMiniToolApi {
|
|
19
|
+
call(operation: MiniToolOperation, payload: object): Promise<Record<string, unknown>>;
|
|
20
|
+
}
|
|
21
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
22
|
+
/** 仅允许 HTTPS 或本机测试地址,且禁止凭据重定向到其他 host。 */
|
|
23
|
+
export declare function validateApiBaseUrl(value: string): string;
|
|
24
|
+
export declare class MiniToolHttpClient implements IMiniToolApi {
|
|
25
|
+
private readonly accessTokens;
|
|
26
|
+
private readonly baseUrl;
|
|
27
|
+
private readonly request;
|
|
28
|
+
constructor(accessTokens: AccessTokenProvider, options: MiniToolApiOptions);
|
|
29
|
+
call(operation: MiniToolOperation, payload: object): Promise<Record<string, unknown>>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const miniToolSourceSchema: z.ZodObject<{
|
|
3
|
+
source: z.ZodString;
|
|
4
|
+
}, z.core.$strict>;
|
|
5
|
+
export declare const miniToolListSchema: z.ZodObject<{
|
|
6
|
+
pageNum: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
pageSize: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
source: z.ZodString;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export declare const miniToolDetailSchema: z.ZodObject<{
|
|
11
|
+
appId: z.ZodString;
|
|
12
|
+
source: z.ZodString;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export declare const miniToolPreviewSchema: z.ZodObject<{
|
|
15
|
+
pkgFileId: z.ZodString;
|
|
16
|
+
md5: z.ZodString;
|
|
17
|
+
appName: z.ZodOptional<z.ZodString>;
|
|
18
|
+
iconFileId: z.ZodOptional<z.ZodString>;
|
|
19
|
+
version: z.ZodOptional<z.ZodString>;
|
|
20
|
+
source: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
export declare const miniToolReviewSchema: z.ZodObject<{
|
|
23
|
+
appId: z.ZodOptional<z.ZodString>;
|
|
24
|
+
appName: z.ZodString;
|
|
25
|
+
slogan: z.ZodString;
|
|
26
|
+
iconFileId: z.ZodString;
|
|
27
|
+
coverFileId: z.ZodString;
|
|
28
|
+
version: z.ZodString;
|
|
29
|
+
pkgFileId: z.ZodString;
|
|
30
|
+
md5: z.ZodString;
|
|
31
|
+
categories: z.ZodArray<z.ZodString>;
|
|
32
|
+
authorizations: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
33
|
+
source: z.ZodString;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
export declare const miniToolEditSchema: z.ZodObject<{
|
|
36
|
+
appId: z.ZodString;
|
|
37
|
+
appName: z.ZodString;
|
|
38
|
+
slogan: z.ZodString;
|
|
39
|
+
iconFileId: z.ZodString;
|
|
40
|
+
coverFileId: z.ZodOptional<z.ZodString>;
|
|
41
|
+
source: z.ZodString;
|
|
42
|
+
}, z.core.$strict>;
|
|
43
|
+
export declare const miniToolUploadSchema: z.ZodObject<{
|
|
44
|
+
filePath: z.ZodString;
|
|
45
|
+
type: z.ZodEnum<{
|
|
46
|
+
pkg: "pkg";
|
|
47
|
+
image: "image";
|
|
48
|
+
}>;
|
|
49
|
+
expectedSha256: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strict>;
|
|
51
|
+
export type MiniToolSourceInput = z.input<typeof miniToolSourceSchema>;
|
|
52
|
+
export type MiniToolListInput = z.input<typeof miniToolListSchema>;
|
|
53
|
+
export type MiniToolDetailInput = z.input<typeof miniToolDetailSchema>;
|
|
54
|
+
export type MiniToolPreviewInput = z.input<typeof miniToolPreviewSchema>;
|
|
55
|
+
export type MiniToolReviewInput = z.input<typeof miniToolReviewSchema>;
|
|
56
|
+
export type MiniToolEditInput = z.input<typeof miniToolEditSchema>;
|
|
57
|
+
export type UploadInput = z.input<typeof miniToolUploadSchema>;
|
|
58
|
+
export interface MiniToolSummary extends Record<string, unknown> {
|
|
59
|
+
appId: string;
|
|
60
|
+
appName?: string;
|
|
61
|
+
version?: string;
|
|
62
|
+
status?: number;
|
|
63
|
+
statusText?: string;
|
|
64
|
+
auditStatus?: number;
|
|
65
|
+
auditStatusText?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface MiniToolPage {
|
|
68
|
+
apps: MiniToolSummary[];
|
|
69
|
+
total: number;
|
|
70
|
+
pageNum: number;
|
|
71
|
+
pageSize: number;
|
|
72
|
+
}
|
|
73
|
+
export interface MiniToolConfig extends Record<string, unknown> {
|
|
74
|
+
categories: {
|
|
75
|
+
code: string;
|
|
76
|
+
name?: string;
|
|
77
|
+
}[];
|
|
78
|
+
authorizations: {
|
|
79
|
+
code: string;
|
|
80
|
+
name?: string;
|
|
81
|
+
}[];
|
|
82
|
+
}
|
|
83
|
+
export interface MiniToolHistory extends Record<string, unknown> {
|
|
84
|
+
versions: Record<string, unknown>[];
|
|
85
|
+
}
|
|
86
|
+
export interface MiniToolPreviewResult extends Record<string, unknown> {
|
|
87
|
+
previewUrl: string;
|
|
88
|
+
}
|
|
89
|
+
export interface MiniToolReviewResult extends Record<string, unknown> {
|
|
90
|
+
appId: string;
|
|
91
|
+
}
|
|
92
|
+
export interface MiniToolUploadResult {
|
|
93
|
+
fileId: string;
|
|
94
|
+
md5: string;
|
|
95
|
+
sha256: string;
|
|
96
|
+
size: number;
|
|
97
|
+
type: "pkg" | "image";
|
|
98
|
+
}
|
|
99
|
+
export declare function parseMiniToolInput<T>(schema: z.ZodType<T>, value: unknown): T;
|
|
100
|
+
export declare class MiniToolError extends Error {
|
|
101
|
+
readonly code: string;
|
|
102
|
+
constructor(code: string, message: string);
|
|
103
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import type { IMiniToolApi } from "./minitool-api";
|
|
3
|
+
import { type MiniToolConfig, type MiniToolDetailInput, type MiniToolEditInput, type MiniToolHistory, type MiniToolListInput, type MiniToolPage, type MiniToolPreviewInput, type MiniToolPreviewResult, type MiniToolReviewInput, type MiniToolReviewResult, type MiniToolSourceInput, type MiniToolSummary, type MiniToolUploadResult, type UploadInput } from "./minitool-contract";
|
|
4
|
+
import { type IUploadService } from "./upload-service";
|
|
5
|
+
export * from "./minitool-contract";
|
|
6
|
+
export interface IMiniToolService {
|
|
7
|
+
getConfig(input: MiniToolSourceInput): Promise<MiniToolConfig>;
|
|
8
|
+
list(input: MiniToolListInput): Promise<MiniToolPage>;
|
|
9
|
+
getStatus(input: MiniToolDetailInput): Promise<MiniToolSummary>;
|
|
10
|
+
getHistory(input: MiniToolDetailInput): Promise<MiniToolHistory>;
|
|
11
|
+
upload(input: UploadInput): Promise<MiniToolUploadResult>;
|
|
12
|
+
createPreview(input: MiniToolPreviewInput): Promise<MiniToolPreviewResult>;
|
|
13
|
+
submitReview(input: MiniToolReviewInput): Promise<MiniToolReviewResult>;
|
|
14
|
+
edit(input: MiniToolEditInput): Promise<MiniToolReviewResult>;
|
|
15
|
+
}
|
|
16
|
+
/** 编排业务校验、平台接口与文件传输;不读取凭据文件。 */
|
|
17
|
+
export declare class MiniToolService implements IMiniToolService {
|
|
18
|
+
private readonly api;
|
|
19
|
+
private readonly uploadService;
|
|
20
|
+
constructor(api: IMiniToolApi, uploadService: IUploadService);
|
|
21
|
+
getConfig(input: MiniToolSourceInput): Promise<MiniToolConfig>;
|
|
22
|
+
list(input: MiniToolListInput): Promise<MiniToolPage>;
|
|
23
|
+
getStatus(input: MiniToolDetailInput): Promise<MiniToolSummary>;
|
|
24
|
+
getHistory(input: MiniToolDetailInput): Promise<MiniToolHistory>;
|
|
25
|
+
upload(input: UploadInput): Promise<MiniToolUploadResult>;
|
|
26
|
+
createPreview(input: MiniToolPreviewInput): Promise<MiniToolPreviewResult>;
|
|
27
|
+
submitReview(input: MiniToolReviewInput): Promise<MiniToolReviewResult>;
|
|
28
|
+
edit(input: MiniToolEditInput): Promise<MiniToolReviewResult>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { type CosClientFactory } from "../utils/cos-uploader";
|
|
3
|
+
export interface UploadTempPermit {
|
|
4
|
+
secretId?: string;
|
|
5
|
+
secretKey?: string;
|
|
6
|
+
token: string;
|
|
7
|
+
uploadAddr: string;
|
|
8
|
+
expireTime: number;
|
|
9
|
+
qos: number;
|
|
10
|
+
cloudType: number;
|
|
11
|
+
bucket: string;
|
|
12
|
+
region: string;
|
|
13
|
+
fileIds: string[];
|
|
14
|
+
masterCloudId: number;
|
|
15
|
+
uploadId: number;
|
|
16
|
+
cdnDomain?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface UploadPermitResponse {
|
|
19
|
+
uploadLimitPolicy?: {
|
|
20
|
+
fileTypes?: string[];
|
|
21
|
+
maxSize?: number;
|
|
22
|
+
};
|
|
23
|
+
uploadTempPermits: UploadTempPermit[];
|
|
24
|
+
}
|
|
25
|
+
export type GetUploadPermit = () => Promise<UploadPermitResponse>;
|
|
26
|
+
export interface ArtifactUploadInput {
|
|
27
|
+
filePath: string;
|
|
28
|
+
bizName: string;
|
|
29
|
+
scene: string;
|
|
30
|
+
contentType?: string;
|
|
31
|
+
getPermit(): Promise<UploadPermitResponse>;
|
|
32
|
+
}
|
|
33
|
+
export interface UploadedArtifact {
|
|
34
|
+
fileId: string;
|
|
35
|
+
url?: string;
|
|
36
|
+
cloudType: number;
|
|
37
|
+
}
|
|
38
|
+
export interface IUploadService {
|
|
39
|
+
upload(input: ArtifactUploadInput): Promise<UploadedArtifact>;
|
|
40
|
+
}
|
|
41
|
+
/** 与具体业务无关的上传服务:获取临时凭证并把本地文件传输到 COS。 */
|
|
42
|
+
export declare class UploadService implements IUploadService {
|
|
43
|
+
private readonly createCos;
|
|
44
|
+
constructor(createCos: CosClientFactory);
|
|
45
|
+
upload(input: ArtifactUploadInput): Promise<UploadedArtifact>;
|
|
46
|
+
}
|
|
47
|
+
/** ROS 上传授权允许 snake_case 与 camelCase;对外只返回文件标识。 */
|
|
48
|
+
export declare function normalizeUploadPermit(data: Record<string, unknown>): UploadPermitResponse;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import COS, { type UploadBody } from "cos-nodejs-sdk-v5";
|
|
2
|
+
import type { GetUploadPermit } from "../services/upload-service";
|
|
3
|
+
export type CosUploadClient = Pick<COS, "uploadFile">;
|
|
4
|
+
export type CosClientFactory = (options: COS.COSOptions) => CosUploadClient;
|
|
5
|
+
interface IFileInfo {
|
|
6
|
+
name: string;
|
|
7
|
+
size: number;
|
|
8
|
+
type: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UploadResponse extends COS.UploadFileResult {
|
|
11
|
+
bizName: string;
|
|
12
|
+
scene: string;
|
|
13
|
+
cloudType: number;
|
|
14
|
+
cdnDomain?: string;
|
|
15
|
+
fileId: string;
|
|
16
|
+
previewUrl?: string;
|
|
17
|
+
staticUrl?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
useCache?: boolean;
|
|
20
|
+
sliceSize?: number;
|
|
21
|
+
isSlice?: boolean;
|
|
22
|
+
tokenFail?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare class Uploader {
|
|
25
|
+
bizName: string;
|
|
26
|
+
scene: string;
|
|
27
|
+
getToken: GetUploadPermit;
|
|
28
|
+
enableResume?: boolean;
|
|
29
|
+
private readonly createCos;
|
|
30
|
+
constructor(args: {
|
|
31
|
+
bizName: string;
|
|
32
|
+
scene: string;
|
|
33
|
+
getToken: GetUploadPermit;
|
|
34
|
+
enableResume?: boolean;
|
|
35
|
+
createCos?: CosClientFactory;
|
|
36
|
+
});
|
|
37
|
+
private getPermit;
|
|
38
|
+
post(options: Omit<COS.UploadFileParams, "Bucket" | "Region" | "Key"> & {
|
|
39
|
+
Body: UploadBody;
|
|
40
|
+
fileInfo: IFileInfo;
|
|
41
|
+
fileFormat?: string;
|
|
42
|
+
onInstanceCreated?: (instance: CosUploadClient) => void;
|
|
43
|
+
}): Promise<UploadResponse>;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isIDE: boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { toHump } from "./to-hump";
|
|
2
|
+
export declare function getFixedFormatTime(format: string, timeDistance?: number): string;
|
|
3
|
+
/** 安全随机数;可用于请求 nonce,不使用 Math.random。 */
|
|
4
|
+
export declare function getNonce(): string;
|
|
5
|
+
/** 仅供非安全场景的兼容性摘要,不应用于签名或密码存储。 */
|
|
6
|
+
export declare function getMd5(value: string): string;
|
|
7
|
+
export declare function guid(): string;
|
|
8
|
+
export declare function retry<T>(fn: () => Promise<T>, maxRetries?: number, delay?: number): Promise<T>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class Loading {
|
|
2
|
+
private readonly spinner;
|
|
3
|
+
set text(value: string);
|
|
4
|
+
start(text: string): void;
|
|
5
|
+
stop(): void;
|
|
6
|
+
succeed(text: string): void;
|
|
7
|
+
fail(text: string): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadingFactory(): Loading;
|
|
10
|
+
export interface ILoadingOptions {
|
|
11
|
+
startTip?: string;
|
|
12
|
+
successTip?: string;
|
|
13
|
+
failTip?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function execWithLoading<T>(task: (flush: (text: string) => void) => Promise<T>, options?: ILoadingOptions): Promise<T>;
|