@be-link/shield-for-tcb-node-sdk 0.0.1

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 ADDED
@@ -0,0 +1,88 @@
1
+ # ShieldForTCB SDK
2
+
3
+ ShieldForTCB Node.js SDK - 敏感信息管理服务客户端
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @be-link/shield-for-tcb-node-sdk
9
+ # 或
10
+ pnpm add @be-link/shield-for-tcb-node-sdk
11
+ ```
12
+
13
+ ## 使用
14
+
15
+ ```typescript
16
+ import { backendConfigService, frontendConfigService } from '@be-link/shield-for-tcb-node-sdk'
17
+
18
+ // 服务端使用(默认,包含异常处理)
19
+ const config = await backendConfigService.fetchConfig({ key: 'your-key', type: 'json' })
20
+
21
+ // 前端使用(跳过异常处理,直接抛出原始错误)
22
+ const frontendConfig = await frontendConfigService.fetchConfig({ key: 'your-key', type: 'json' })
23
+
24
+ // 获取全局动态配置
25
+ const globalConfig = await backendConfigService.fetchGlobalDynamicConfig()
26
+
27
+ // 获取 COS 临时密钥
28
+ const cosTempSecret = await backendConfigService.getCosTempSecret()
29
+ ```
30
+
31
+ ## 发布流程
32
+
33
+ ### 自动发布(推荐)
34
+
35
+ 使用发布脚本,会自动完成版本更新、构建和发布:
36
+
37
+ ```bash
38
+ # 在 SDK 目录下执行
39
+ cd packages/sdk
40
+ pnpm publish
41
+
42
+ # 或在根目录执行
43
+ pnpm publish:sdk
44
+ ```
45
+
46
+ 发布脚本会自动:
47
+ 1. 设置 npm 配置和认证(需要 `NPM_DEPLOY_TOKEN` 环境变量)
48
+ 2. 更新版本号(使用 `npm version patch`,只读模式)
49
+ 3. 构建项目
50
+ 4. 发布到 npm(使用 `pnpm publish --no-git-checks`,只读文件发布)
51
+ 5. 发送飞书通知(需要 `FEISHU_WEBHOOK_URL` 环境变量)
52
+
53
+ ### 环境变量
54
+
55
+ 发布脚本需要以下环境变量(可选):
56
+
57
+ - `NPM_DEPLOY_TOKEN`: npm 发布 token
58
+ - `FEISHU_WEBHOOK_URL`: 飞书 webhook URL(用于发送发布通知)
59
+
60
+ ### CI/CD 集成
61
+
62
+ 在 Jenkins 或其他 CI/CD 平台中,可以这样使用:
63
+
64
+ ```bash
65
+ export NPM_DEPLOY_TOKEN="your-token"
66
+ export FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
67
+ cd packages/sdk
68
+ pnpm publish
69
+ ```
70
+
71
+ ### 手动发布
72
+
73
+ 如果需要手动发布:
74
+
75
+ ```bash
76
+ # 1. 构建
77
+ pnpm build
78
+
79
+ # 2. 进入 dist 目录发布(只读文件发布)
80
+ cd dist
81
+ pnpm publish --no-git-checks --access public
82
+ cd ..
83
+ ```
84
+
85
+ ## License
86
+
87
+ ISC
88
+
package/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { backendConfigService, frontendConfigService } from './modules/config/service';
2
+ export type { Service as ConfigControllerTypes } from './modules/config/types';
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.frontendConfigService = exports.backendConfigService = void 0;
4
+ var service_1 = require("./modules/config/service");
5
+ Object.defineProperty(exports, "backendConfigService", { enumerable: true, get: function () { return service_1.backendConfigService; } });
6
+ Object.defineProperty(exports, "frontendConfigService", { enumerable: true, get: function () { return service_1.frontendConfigService; } });
@@ -0,0 +1,14 @@
1
+ export default abstract class BaseService {
2
+ private isPublicEnv;
3
+ /** URL一级路径 */
4
+ protected abstract prefixUrl: string;
5
+ /** 子网域名 */
6
+ protected readonly natDevHost = "http://yayvmsbg.shield-for-tcb.07vmo6rk.by26x7u9.com:8090";
7
+ protected readonly natProdHost = "";
8
+ /** 公网域名 */
9
+ protected readonly publicDevHost = "https://shield-for-tcb-196345-5-1304510571.sh.run.tcloudbase.com";
10
+ protected readonly publicProdHost = "";
11
+ constructor();
12
+ /** 获取API URL */
13
+ protected getApiUrl(func: Function): string;
14
+ }
@@ -0,0 +1,31 @@
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
+ const env_1 = __importDefault(require("../utils/env"));
7
+ const string_1 = require("../utils/string");
8
+ class BaseService {
9
+ constructor() {
10
+ /** 子网域名 */
11
+ this.natDevHost = 'http://yayvmsbg.shield-for-tcb.07vmo6rk.by26x7u9.com:8090';
12
+ this.natProdHost = '';
13
+ /** 公网域名 */
14
+ this.publicDevHost = 'https://shield-for-tcb-196345-5-1304510571.sh.run.tcloudbase.com';
15
+ this.publicProdHost = '';
16
+ /** 如果是云函数环境, 默认走公网访问 */
17
+ this.isPublicEnv = (process.env.CONTAINER_ENV || 'SCF') === 'SCF';
18
+ }
19
+ /** 获取API URL */
20
+ getApiUrl(func) {
21
+ const host = this.isPublicEnv
22
+ ? env_1.default.isProduction()
23
+ ? this.publicProdHost
24
+ : this.publicDevHost
25
+ : env_1.default.isProduction()
26
+ ? this.natProdHost
27
+ : this.natDevHost;
28
+ return `${host}${this.prefixUrl}/${(0, string_1.camelToKebabCase)(func.name)}`;
29
+ }
30
+ }
31
+ exports.default = BaseService;
@@ -0,0 +1,19 @@
1
+ import { Service } from './types';
2
+ import BaseService from '../BaseService';
3
+ type CallerType = 'frontend' | 'backend';
4
+ export interface ConfigServiceOptions {
5
+ caller?: CallerType;
6
+ }
7
+ export declare class ConfigService extends BaseService implements Service.ConfigController {
8
+ protected prefixUrl: string;
9
+ private caller;
10
+ constructor(options?: ConfigServiceOptions);
11
+ private get shouldSkipErrorHandling();
12
+ fetchConfig(req: Service.Request.QueryFetchConfig): Promise<any>;
13
+ fetchGlobalDynamicConfig(): Promise<Service.Response.IFetchGlobalDynamicConfigResponse>;
14
+ getCosTempSecret(): Promise<Service.Response.CosTempSecretResponse>;
15
+ fetchSystemTime(): Promise<Date>;
16
+ }
17
+ export declare const backendConfigService: ConfigService;
18
+ export declare const frontendConfigService: ConfigService;
19
+ export {};
@@ -0,0 +1,35 @@
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.frontendConfigService = exports.backendConfigService = exports.ConfigService = void 0;
7
+ const http_1 = require("../../utils/http");
8
+ const BaseService_1 = __importDefault(require("../BaseService"));
9
+ class ConfigService extends BaseService_1.default {
10
+ constructor(options) {
11
+ super();
12
+ this.prefixUrl = '/config';
13
+ this.caller = options?.caller ?? 'backend';
14
+ }
15
+ get shouldSkipErrorHandling() {
16
+ return this.caller === 'frontend';
17
+ }
18
+ fetchConfig(req) {
19
+ return (0, http_1.callApi)(this.getApiUrl(this.fetchConfig), req, {
20
+ skipErrorHandling: this.shouldSkipErrorHandling,
21
+ });
22
+ }
23
+ fetchGlobalDynamicConfig() {
24
+ return (0, http_1.callApi)(this.getApiUrl(this.fetchGlobalDynamicConfig), undefined, { skipErrorHandling: this.shouldSkipErrorHandling });
25
+ }
26
+ getCosTempSecret() {
27
+ return (0, http_1.callApi)(this.getApiUrl(this.getCosTempSecret), undefined, { skipErrorHandling: this.shouldSkipErrorHandling });
28
+ }
29
+ fetchSystemTime() {
30
+ return (0, http_1.callApi)(this.getApiUrl(this.fetchSystemTime), undefined, { skipErrorHandling: this.shouldSkipErrorHandling });
31
+ }
32
+ }
33
+ exports.ConfigService = ConfigService;
34
+ exports.backendConfigService = new ConfigService({ caller: 'backend' });
35
+ exports.frontendConfigService = new ConfigService({ caller: 'frontend' });
@@ -0,0 +1,65 @@
1
+ export declare namespace Service {
2
+ namespace Entity { }
3
+ namespace Request {
4
+ /**
5
+ * 获取配置请求参数
6
+ */
7
+ interface QueryFetchConfig {
8
+ key: string;
9
+ type?: 'json' | 'yaml';
10
+ env?: string;
11
+ }
12
+ }
13
+ namespace Response {
14
+ /**
15
+ * 获取全局动态配置响应
16
+ */
17
+ interface IFetchGlobalDynamicConfigResponse {
18
+ [key: string]: any;
19
+ }
20
+ /**
21
+ * COS 临时密钥凭证
22
+ */
23
+ interface Credentials {
24
+ sessionToken: string;
25
+ tmpSecretId: string;
26
+ tmpSecretKey: string;
27
+ }
28
+ /**
29
+ * COS 临时密钥响应
30
+ */
31
+ interface CosTempSecretResponse {
32
+ expiredTime: number;
33
+ expiration: string;
34
+ credentials: Credentials;
35
+ requestId: string;
36
+ startTime: number;
37
+ }
38
+ }
39
+ /**
40
+ * Config Controller 接口定义
41
+ */
42
+ interface ConfigController {
43
+ /**
44
+ * 获取配置
45
+ * @param req 请求参数
46
+ * @returns 配置数据
47
+ */
48
+ fetchConfig(req: Service.Request.QueryFetchConfig): Promise<any>;
49
+ /**
50
+ * 获取全局动态配置
51
+ * @returns 全局动态配置数据
52
+ */
53
+ fetchGlobalDynamicConfig(): Promise<Service.Response.IFetchGlobalDynamicConfigResponse>;
54
+ /**
55
+ * 获取 COS 临时密钥
56
+ * @returns COS 临时密钥数据
57
+ */
58
+ getCosTempSecret(): Promise<Service.Response.CosTempSecretResponse>;
59
+ /**
60
+ * 获取系统时间
61
+ * @returns 系统时间
62
+ */
63
+ fetchSystemTime(): Promise<Date>;
64
+ }
65
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@be-link/shield-for-tcb-node-sdk",
3
+ "version": "0.0.1",
4
+ "description": "ShieldForTCB Node.js SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "keywords": [
8
+ "shield",
9
+ "tcb",
10
+ "sdk"
11
+ ],
12
+ "author": "",
13
+ "license": "ISC",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "dependencies": {
18
+ "axios": "1.13.2",
19
+ "axios-retry": "^4.0.0",
20
+ "uuid": "^9.0.1"
21
+ },
22
+ "devDependencies": {
23
+ "@types/uuid": "^9.0.6"
24
+ },
25
+ "scripts": {
26
+ "build": "rm -rf ./dist && tsc && cp package.json README.md ./dist/ 2>/dev/null || true",
27
+ "test": "jest"
28
+ }
29
+ }
package/utils/env.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ declare class EnvUtils {
2
+ /**
3
+ * 判断是否为生产环境
4
+ */
5
+ isProduction(): boolean;
6
+ /**
7
+ * 获取环境变量
8
+ */
9
+ getEnv(key: string, defaultValue?: string): string | undefined;
10
+ }
11
+ declare const envUtils: EnvUtils;
12
+ export default envUtils;
package/utils/env.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class EnvUtils {
4
+ /**
5
+ * 判断是否为生产环境
6
+ */
7
+ isProduction() {
8
+ return process.env.NODE_ENV === 'prod';
9
+ }
10
+ /**
11
+ * 获取环境变量
12
+ */
13
+ getEnv(key, defaultValue) {
14
+ return process.env[key] || defaultValue;
15
+ }
16
+ }
17
+ const envUtils = new EnvUtils();
18
+ exports.default = envUtils;
@@ -0,0 +1,5 @@
1
+ type CallApiOptions = {
2
+ skipErrorHandling?: boolean;
3
+ };
4
+ export declare function callApi<T extends (args: any) => Promise<any>>(url: string, request?: Parameters<T>[0], options?: CallApiOptions): Promise<Awaited<ReturnType<T>>>;
5
+ export {};
package/utils/http.js ADDED
@@ -0,0 +1,99 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.callApi = callApi;
40
+ const axios_1 = __importDefault(require("axios"));
41
+ const uuid_1 = require("uuid");
42
+ const axios_retry_1 = __importDefault(require("axios-retry"));
43
+ (0, axios_retry_1.default)(axios_1.default, {
44
+ retries: 1,
45
+ retryCondition(error) {
46
+ return error.response?.status === 502;
47
+ },
48
+ retryDelay: (retryCount) => {
49
+ console.info(`retryCount: ${retryCount}, retryDelay: ${retryCount * 500}`);
50
+ return retryCount * 500;
51
+ },
52
+ onRetry(retryCount, error, requestConfig) {
53
+ console.info(`retryCount: ${retryCount}, onRetry: ${error.message}, requestHeader: ${JSON.stringify(requestConfig.headers)}`);
54
+ },
55
+ });
56
+ async function callApi(url, request, options) {
57
+ const requestId = (0, uuid_1.v4)();
58
+ try {
59
+ console.info(`准备发起SHIELD-FOR-TCB请求[${requestId}]: ${url}, 参数: ${JSON.stringify(request)}`);
60
+ const response = await axios_1.default.post(url, request, { headers: { 'x-request-id': requestId } });
61
+ const responseData = response.data;
62
+ return responseData.data;
63
+ }
64
+ catch (error) {
65
+ if (options?.skipErrorHandling) {
66
+ throw error;
67
+ }
68
+ const axiosError = error;
69
+ if (axiosError.response) {
70
+ const response = axiosError.response;
71
+ const data = response.data;
72
+ console.error(`SHIELD 异常: ${axiosError.message},requestId: ${requestId}`);
73
+ console.info('响应信息', data.message);
74
+ console.error('异常堆栈', JSON.stringify(error.stack));
75
+ throw new Error(data.errorType + ' - ' + data.message);
76
+ }
77
+ // 调用dns模块解析url
78
+ const dns = await Promise.resolve().then(() => __importStar(require('dns')));
79
+ const dnsPromise = new Promise((resolve, reject) => {
80
+ const lookupRes = dns.lookup(url, (err, address) => {
81
+ if (err) {
82
+ console.error(err.message);
83
+ reject(err);
84
+ }
85
+ console.info(`lookup: ${JSON.stringify(lookupRes)}`);
86
+ resolve(address);
87
+ });
88
+ });
89
+ try {
90
+ const address = await dnsPromise;
91
+ console.info(`address: ${JSON.stringify(address)}`);
92
+ }
93
+ catch (error) {
94
+ console.info(`error: ${JSON.stringify(error)}`);
95
+ }
96
+ console.error(`SHIELD 未知异常: ${axiosError.message}`, error.stack);
97
+ throw error;
98
+ }
99
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 将驼峰命名转换为短横线命名
3
+ * @param str 驼峰命名字符串
4
+ * @returns 短横线命名字符串
5
+ * @example
6
+ * camelToKebabCase('fetchConfig') // 'fetch-config'
7
+ * camelToKebabCase('getCosTempSecret') // 'get-cos-temp-secret'
8
+ */
9
+ export declare function camelToKebabCase(str: string): string;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.camelToKebabCase = camelToKebabCase;
4
+ /**
5
+ * 将驼峰命名转换为短横线命名
6
+ * @param str 驼峰命名字符串
7
+ * @returns 短横线命名字符串
8
+ * @example
9
+ * camelToKebabCase('fetchConfig') // 'fetch-config'
10
+ * camelToKebabCase('getCosTempSecret') // 'get-cos-temp-secret'
11
+ */
12
+ function camelToKebabCase(str) {
13
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
14
+ }