@cloudbase/node-sdk 3.17.1 → 3.18.0
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/CHANGELOG.md +24 -0
- package/dist/ai/index.js +58 -0
- package/dist/ai/request-adapter.js +259 -0
- package/dist/auth/index.js +4 -0
- package/dist/cloudbase.js +9 -36
- package/dist/utils/tcbapirequester.js +11 -3
- package/dist/utils/tcbcontext.js +1 -0
- package/dist/utils/tcbopenapicommonrequester.js +25 -7
- package/dist/utils/tcbopenapirequester.js +26 -5
- package/dist/utils/utils.js +73 -1
- package/package.json +1 -1
- package/src/auth/index.ts +5 -1
- package/src/cloudbase.ts +9 -38
- package/src/utils/tcbapirequester.ts +11 -4
- package/src/utils/tcbcontext.ts +1 -0
- package/src/utils/tcbdbapirequester.ts +0 -1
- package/src/utils/tcbopenapicommonrequester.ts +22 -8
- package/src/utils/tcbopenapirequester.ts +24 -6
- package/src/utils/utils.ts +62 -0
- package/types/index.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v3.18.0
|
|
4
|
+
|
|
5
|
+
- [feat] 添加 API Key 授权支持
|
|
6
|
+
|
|
7
|
+
## v3.17.0
|
|
8
|
+
|
|
9
|
+
- [fix] 修复 wx request 响应类型问题
|
|
10
|
+
- [feat] 支持自定义数据库
|
|
11
|
+
|
|
12
|
+
## v3.16.0
|
|
13
|
+
|
|
14
|
+
- [feat] 新增 AI 模块支持
|
|
15
|
+
|
|
16
|
+
## v3.15.0
|
|
17
|
+
|
|
18
|
+
- [feat] callContainer 支持更多请求方法
|
|
19
|
+
- [feat] 添加 RDB 客户端支持
|
|
20
|
+
|
|
21
|
+
## v3.14.0
|
|
22
|
+
|
|
23
|
+
- [feat] 支持配置 region 参数以区分国内和国际区域
|
|
24
|
+
- [feat] 添加 MySQL SDK 支持
|
|
25
|
+
- [feat] 添加 callApis 方法
|
|
26
|
+
|
|
3
27
|
## v2.3.4
|
|
4
28
|
|
|
5
29
|
- [bugfix] 修复geo centerSphere 兼容问题
|
package/dist/ai/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createAI = void 0;
|
|
27
|
+
const ai_1 = require("@cloudbase/ai");
|
|
28
|
+
const request_adapter_1 = require("./request-adapter");
|
|
29
|
+
const tcbopenapiendpoint_1 = require("../utils/tcbopenapiendpoint");
|
|
30
|
+
const symbol_1 = require("../const/symbol");
|
|
31
|
+
const openapicommonrequester = __importStar(require("../utils/tcbopenapicommonrequester"));
|
|
32
|
+
const app_1 = require("@cloudbase/app");
|
|
33
|
+
/**
|
|
34
|
+
* 创建 AI 实例
|
|
35
|
+
* @param cloudbase CloudBase 实例
|
|
36
|
+
* @returns AI 实例
|
|
37
|
+
*/
|
|
38
|
+
function createAI(cloudbase) {
|
|
39
|
+
const config = cloudbase.config;
|
|
40
|
+
// 获取环境 ID
|
|
41
|
+
const envId = config.envName === symbol_1.SYMBOL_CURRENT_ENV ? openapicommonrequester.getEnvIdFromContext() : config.envName;
|
|
42
|
+
// 构建 AI 基础 URL
|
|
43
|
+
const baseUrl = (0, tcbopenapiendpoint_1.buildCommonOpenApiUrlWithPath)({
|
|
44
|
+
serviceUrl: config.serviceUrl,
|
|
45
|
+
envId,
|
|
46
|
+
path: '/v1',
|
|
47
|
+
region: config.region
|
|
48
|
+
});
|
|
49
|
+
// 创建请求适配器
|
|
50
|
+
const requestAdapter = new request_adapter_1.AIRequestAdapter(config, async () => {
|
|
51
|
+
const credential = await cloudbase.auth().getClientCredential();
|
|
52
|
+
return credential.access_token;
|
|
53
|
+
});
|
|
54
|
+
// 创建 AI 实例
|
|
55
|
+
const ai = new ai_1.AI(requestAdapter, baseUrl, { t: (s) => s, lang: app_1.LANGS.ZH, LANG_HEADER_KEY: 'Accept-Language' });
|
|
56
|
+
return ai;
|
|
57
|
+
}
|
|
58
|
+
exports.createAI = createAI;
|
|
@@ -0,0 +1,259 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.AIRequestAdapter = void 0;
|
|
27
|
+
const openapicommonrequester = __importStar(require("../utils/tcbopenapicommonrequester"));
|
|
28
|
+
const web_streams_polyfill_1 = require("web-streams-polyfill");
|
|
29
|
+
const utils_1 = require("../utils/utils");
|
|
30
|
+
class AIRequestAdapter {
|
|
31
|
+
constructor(config, getAccessToken) {
|
|
32
|
+
this.config = config;
|
|
33
|
+
this.getAccessToken = getAccessToken;
|
|
34
|
+
}
|
|
35
|
+
async fetch(options) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const { url, stream = false, timeout, method = 'POST', headers, body } = options;
|
|
38
|
+
const headersObj = {};
|
|
39
|
+
if (isHeaders(headers)) {
|
|
40
|
+
headers.forEach((value, key) => {
|
|
41
|
+
headersObj[key] = value;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (Array.isArray(headers)) {
|
|
45
|
+
headers.forEach(([k, v]) => (headersObj[k] = v));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
Object.assign(headersObj, headers);
|
|
49
|
+
}
|
|
50
|
+
let parsedBody;
|
|
51
|
+
if (typeof body === 'string') {
|
|
52
|
+
try {
|
|
53
|
+
parsedBody = JSON.parse(body);
|
|
54
|
+
}
|
|
55
|
+
catch (_c) {
|
|
56
|
+
parsedBody = body;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
parsedBody = body;
|
|
61
|
+
}
|
|
62
|
+
const token = await this.getAccessToken();
|
|
63
|
+
const result = await openapicommonrequester.request({
|
|
64
|
+
config: this.config,
|
|
65
|
+
data: parsedBody,
|
|
66
|
+
method: (method === null || method === void 0 ? void 0 : method.toUpperCase()) || 'POST',
|
|
67
|
+
url,
|
|
68
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, headersObj),
|
|
69
|
+
token,
|
|
70
|
+
opts: {
|
|
71
|
+
timeout: timeout || this.config.timeout,
|
|
72
|
+
stream
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const { body: bodyData, headers: responseHeaders, statusCode } = result;
|
|
76
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
77
|
+
let errorMessage = `Request failed with status code ${statusCode}`;
|
|
78
|
+
let errorCode = `${statusCode}`;
|
|
79
|
+
let requestId = '';
|
|
80
|
+
let errorBody = null;
|
|
81
|
+
if (typeof bodyData === 'string') {
|
|
82
|
+
errorBody = bodyData;
|
|
83
|
+
}
|
|
84
|
+
else if (Buffer.isBuffer(bodyData)) {
|
|
85
|
+
errorBody = bodyData.toString('utf-8');
|
|
86
|
+
}
|
|
87
|
+
else if (bodyData && typeof bodyData === 'object' && typeof bodyData.on === 'function') {
|
|
88
|
+
errorBody = await readStreamToString(bodyData);
|
|
89
|
+
}
|
|
90
|
+
if (errorBody) {
|
|
91
|
+
try {
|
|
92
|
+
const errorData = JSON.parse(errorBody);
|
|
93
|
+
if ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.message) {
|
|
94
|
+
errorMessage = errorData.error.message;
|
|
95
|
+
}
|
|
96
|
+
else if (errorData.message) {
|
|
97
|
+
errorMessage = errorData.message;
|
|
98
|
+
}
|
|
99
|
+
if ((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.code) {
|
|
100
|
+
errorCode = errorData.error.code;
|
|
101
|
+
}
|
|
102
|
+
else if (errorData.code) {
|
|
103
|
+
errorCode = errorData.code;
|
|
104
|
+
}
|
|
105
|
+
if (errorData.requestId) {
|
|
106
|
+
requestId = errorData.requestId;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (_d) {
|
|
110
|
+
errorMessage = errorBody || errorMessage;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 从响应头中获取 requestId
|
|
114
|
+
if (!requestId && responseHeaders) {
|
|
115
|
+
const headerRequestId = responseHeaders['x-cloudbase-request-id'] || responseHeaders['x-request-id'] || '';
|
|
116
|
+
requestId = Array.isArray(headerRequestId) ? headerRequestId[0] : headerRequestId;
|
|
117
|
+
}
|
|
118
|
+
throw (0, utils_1.E)({
|
|
119
|
+
code: errorCode,
|
|
120
|
+
message: errorMessage,
|
|
121
|
+
requestId
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (stream) {
|
|
125
|
+
// 对于流式响应,将 Node.js 原生流转换为 Web ReadableStream
|
|
126
|
+
let readableStream;
|
|
127
|
+
if (bodyData && typeof bodyData === 'object' && 'on' in bodyData && typeof bodyData.on === 'function') {
|
|
128
|
+
const nodeStream = bodyData;
|
|
129
|
+
// Node 12 兼容: 使用标志位追踪 stream 状态,避免重复 close 导致异常
|
|
130
|
+
let streamClosed = false;
|
|
131
|
+
readableStream = new web_streams_polyfill_1.ReadableStream({
|
|
132
|
+
start(controller) {
|
|
133
|
+
nodeStream.on('data', (chunk) => {
|
|
134
|
+
if (streamClosed)
|
|
135
|
+
return;
|
|
136
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
137
|
+
});
|
|
138
|
+
nodeStream.on('end', () => {
|
|
139
|
+
if (streamClosed)
|
|
140
|
+
return;
|
|
141
|
+
streamClosed = true;
|
|
142
|
+
controller.close();
|
|
143
|
+
});
|
|
144
|
+
nodeStream.on('error', (err) => {
|
|
145
|
+
if (streamClosed)
|
|
146
|
+
return;
|
|
147
|
+
streamClosed = true;
|
|
148
|
+
controller.error(err);
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
cancel() {
|
|
152
|
+
streamClosed = true;
|
|
153
|
+
nodeStream.destroy();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (bodyData instanceof Buffer) {
|
|
158
|
+
readableStream = new web_streams_polyfill_1.ReadableStream({
|
|
159
|
+
start(controller) {
|
|
160
|
+
controller.enqueue(new Uint8Array(bodyData));
|
|
161
|
+
controller.close();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else if (typeof bodyData === 'string') {
|
|
166
|
+
const encoder = new TextEncoder();
|
|
167
|
+
readableStream = new web_streams_polyfill_1.ReadableStream({
|
|
168
|
+
start(controller) {
|
|
169
|
+
controller.enqueue(encoder.encode(bodyData));
|
|
170
|
+
controller.close();
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
readableStream = new web_streams_polyfill_1.ReadableStream({
|
|
176
|
+
start(controller) {
|
|
177
|
+
controller.close();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
data: readableStream,
|
|
183
|
+
statusCode,
|
|
184
|
+
header: responseHeaders
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
let responseData;
|
|
188
|
+
if (typeof bodyData === 'string') {
|
|
189
|
+
try {
|
|
190
|
+
responseData = JSON.parse(bodyData);
|
|
191
|
+
}
|
|
192
|
+
catch (_e) {
|
|
193
|
+
responseData = bodyData;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (bodyData instanceof Buffer) {
|
|
197
|
+
const bodyString = bodyData.toString('utf-8');
|
|
198
|
+
try {
|
|
199
|
+
responseData = JSON.parse(bodyString);
|
|
200
|
+
}
|
|
201
|
+
catch (_f) {
|
|
202
|
+
responseData = bodyString;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
responseData = bodyData;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
data: Promise.resolve(responseData),
|
|
210
|
+
statusCode,
|
|
211
|
+
header: responseHeaders
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* post 方法 - AI 模块可能不使用,但需要实现接口
|
|
216
|
+
*/
|
|
217
|
+
async post() {
|
|
218
|
+
throw new Error('post method is not supported in AI module');
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* upload 方法 - AI 模块可能不使用,但需要实现接口
|
|
222
|
+
*/
|
|
223
|
+
async upload() {
|
|
224
|
+
throw new Error('upload method is not supported in AI module');
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* download 方法 - AI 模块可能不使用,但需要实现接口
|
|
228
|
+
*/
|
|
229
|
+
async download() {
|
|
230
|
+
throw new Error('download method is not supported in AI module');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
exports.AIRequestAdapter = AIRequestAdapter;
|
|
234
|
+
function isHeaders(h) {
|
|
235
|
+
try {
|
|
236
|
+
// Node.js 低版本可能没有 Headers
|
|
237
|
+
return h instanceof Headers;
|
|
238
|
+
}
|
|
239
|
+
catch (_) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 从 Node.js 流中读取完整内容为字符串
|
|
245
|
+
*/
|
|
246
|
+
async function readStreamToString(stream) {
|
|
247
|
+
return await new Promise((resolve, reject) => {
|
|
248
|
+
const chunks = [];
|
|
249
|
+
stream.on('data', (chunk) => {
|
|
250
|
+
chunks.push(chunk);
|
|
251
|
+
});
|
|
252
|
+
stream.on('end', () => {
|
|
253
|
+
resolve(Buffer.concat(chunks).toString('utf-8'));
|
|
254
|
+
});
|
|
255
|
+
stream.on('error', (err) => {
|
|
256
|
+
reject(err);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
package/dist/auth/index.js
CHANGED
|
@@ -135,6 +135,10 @@ class Auth {
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
async getClientCredential(opts) {
|
|
138
|
+
// 如果有 accessKey 直接返回 accessKey,不用再去换取 token
|
|
139
|
+
if (this.cloudbase.config.accessKey) {
|
|
140
|
+
return this.cloudbase.config.accessKey;
|
|
141
|
+
}
|
|
138
142
|
return await tcbopenapicommonrequester.request({
|
|
139
143
|
config: this.cloudbase.config,
|
|
140
144
|
method: 'POST',
|
package/dist/cloudbase.js
CHANGED
|
@@ -22,17 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
-
var t = {};
|
|
27
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
-
t[p] = s[p];
|
|
29
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
-
t[p[i]] = s[p[i]];
|
|
33
|
-
}
|
|
34
|
-
return t;
|
|
35
|
-
};
|
|
36
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
27
|
};
|
|
@@ -49,14 +38,13 @@ const wx_1 = require("./wx");
|
|
|
49
38
|
const analytics_1 = require("./analytics");
|
|
50
39
|
const ai_1 = require("./ai");
|
|
51
40
|
const logger_1 = require("./logger");
|
|
52
|
-
const code_1 = require("./const/code");
|
|
53
|
-
const utils = __importStar(require("./utils/utils"));
|
|
54
41
|
const cloudplatform_1 = require("./utils/cloudplatform");
|
|
55
42
|
const tcbcontext_1 = require("./utils/tcbcontext");
|
|
56
43
|
const notification_1 = require("./notification");
|
|
57
44
|
const openapicommonrequester = __importStar(require("./utils/tcbopenapicommonrequester"));
|
|
58
45
|
const tcbopenapiendpoint_1 = require("./utils/tcbopenapiendpoint");
|
|
59
46
|
const symbol_1 = require("./const/symbol");
|
|
47
|
+
const utils_1 = require("./utils/utils");
|
|
60
48
|
class CloudBase {
|
|
61
49
|
static parseContext(context) {
|
|
62
50
|
const parseResult = (0, tcbcontext_1.parseContext)(context);
|
|
@@ -70,33 +58,14 @@ class CloudBase {
|
|
|
70
58
|
this.init(config);
|
|
71
59
|
}
|
|
72
60
|
init(config = {}) {
|
|
73
|
-
var _a, _b, _c, _d;
|
|
74
61
|
// 预检运行环境,调用与否并不影响后续逻辑
|
|
75
62
|
// 注意:该函数为异步函数,这里并不等待检查结果
|
|
76
63
|
/* eslint-disable-next-line */
|
|
77
64
|
(0, cloudplatform_1.preflightRuntimeCloudPlatform)();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const newConfig = Object.assign(Object.assign({}, restConfig), { debug: !!debug, secretId,
|
|
83
|
-
secretKey,
|
|
84
|
-
sessionToken,
|
|
85
|
-
env, envName: env, headers: Object.assign({}, headers), timeout: timeout || 15000 });
|
|
86
|
-
if ((_a = config.context) === null || _a === void 0 ? void 0 : _a.extendedContext) {
|
|
87
|
-
const extendedContext = config.context.extendedContext;
|
|
88
|
-
if (!newConfig.env) {
|
|
89
|
-
newConfig.env = extendedContext.envId;
|
|
90
|
-
newConfig.envName = newConfig.env;
|
|
91
|
-
}
|
|
92
|
-
// 从 context 中获取 secret
|
|
93
|
-
if (!newConfig.secretId && !newConfig.secretKey) {
|
|
94
|
-
newConfig.secretId = (_b = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _b === void 0 ? void 0 : _b.secretId;
|
|
95
|
-
newConfig.secretKey = (_c = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _c === void 0 ? void 0 : _c.secretKey;
|
|
96
|
-
newConfig.sessionToken = (_d = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _d === void 0 ? void 0 : _d.token;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
this.config = newConfig;
|
|
65
|
+
// 所有的鉴权,参数塑形都在 normalizeConfig 中处理
|
|
66
|
+
// 后续其他模块获取 config 都通过 CloudBase 实例的 config 获取
|
|
67
|
+
// 禁止在业务模块中直接修改 config 配置
|
|
68
|
+
this.config = (0, utils_1.normalizeConfig)(config);
|
|
100
69
|
this.extensionMap = new Map();
|
|
101
70
|
// NOTE:try-catch 为防止 init 报错
|
|
102
71
|
try {
|
|
@@ -112,6 +81,10 @@ class CloudBase {
|
|
|
112
81
|
method: (_a = options.method) === null || _a === void 0 ? void 0 : _a.toUpperCase(),
|
|
113
82
|
url: options.url,
|
|
114
83
|
headers: Object.assign({ 'Content-Type': 'application/json' }, headersInitToRecord(options.headers)),
|
|
84
|
+
/**
|
|
85
|
+
* 既然 openapicommonrequester.request 的参数里的 token 获取也是通过 openapicommonrequester.request 方法去获取的
|
|
86
|
+
* 为什么不把这里的 token 去掉,全部放在 openapicommonrequester.request 中去统一处理 token 获取的逻辑
|
|
87
|
+
*/
|
|
115
88
|
token: (await this.auth().getClientCredential()).access_token
|
|
116
89
|
});
|
|
117
90
|
return result.body;
|
|
@@ -127,9 +127,15 @@ class TcbApiHttpRequester {
|
|
|
127
127
|
this.tracingInfo = (0, tracing_1.generateTracingInfo)((_b = (_a = args.config) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.eventID);
|
|
128
128
|
}
|
|
129
129
|
async request() {
|
|
130
|
-
|
|
130
|
+
// 如果没有配置 accessKey,则通过密钥获取签名,这里先检查密钥是否存在
|
|
131
|
+
if (!this.config.accessKey) {
|
|
132
|
+
// 检查密钥是否存在
|
|
133
|
+
await this.prepareCredentials();
|
|
134
|
+
}
|
|
131
135
|
const params = await this.makeParams();
|
|
136
|
+
// console.log('params', params)
|
|
132
137
|
const opts = this.makeReqOpts(params);
|
|
138
|
+
// console.log('opts', opts)
|
|
133
139
|
const action = this.getAction();
|
|
134
140
|
const key = {
|
|
135
141
|
functions: 'function_name',
|
|
@@ -278,7 +284,7 @@ class TcbApiHttpRequester {
|
|
|
278
284
|
getHeaders(method, url, params) {
|
|
279
285
|
var _a;
|
|
280
286
|
const config = this.config;
|
|
281
|
-
const { context, secretId, secretKey } = config;
|
|
287
|
+
const { context, secretId, secretKey, accessKey } = config;
|
|
282
288
|
const args = this.args;
|
|
283
289
|
const { TCB_SOURCE } = cloudbase_1.CloudBase.getCloudbaseContext();
|
|
284
290
|
// Note: 云函数被调用时可能调用端未传递 SOURCE,TCB_SOURCE 可能为空
|
|
@@ -318,7 +324,8 @@ class TcbApiHttpRequester {
|
|
|
318
324
|
timestamp: second() - 1
|
|
319
325
|
});
|
|
320
326
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
321
|
-
|
|
327
|
+
// 优先使用 accessKey,否则使用签名
|
|
328
|
+
requiredHeaders['Authorization'] = accessKey ? `Bearer ${accessKey}` : authorization;
|
|
322
329
|
requiredHeaders['X-Signature-Expires'] = 600;
|
|
323
330
|
requiredHeaders['X-Timestamp'] = timestamp;
|
|
324
331
|
return Object.assign({}, requiredHeaders);
|
|
@@ -335,6 +342,7 @@ const handleWxOpenApiData = (res, err, response, body) => {
|
|
|
335
342
|
return transformRes;
|
|
336
343
|
};
|
|
337
344
|
async function request(args) {
|
|
345
|
+
// console.log('args', args)
|
|
338
346
|
if (typeof args.isInternal === 'undefined') {
|
|
339
347
|
args.isInternal = await (0, cloudplatform_1.checkIsInternalAsync)();
|
|
340
348
|
}
|
package/dist/utils/tcbcontext.js
CHANGED
|
@@ -60,6 +60,7 @@ exports.parseContext = parseContext;
|
|
|
60
60
|
* 获取当前函数内的所有环境变量(作为获取变量的统一方法,取值来源 process.env 和 context)
|
|
61
61
|
*/
|
|
62
62
|
function getCloudbaseContext(context) {
|
|
63
|
+
// console.log('context', context)
|
|
63
64
|
if ((0, cloudplatform_1.checkIsInScf)()) {
|
|
64
65
|
// 云函数环境下,应该包含以下环境变量,如果没有,后续逻辑可能会有问题
|
|
65
66
|
if (!process.env.TENCENTCLOUD_REGION) {
|
|
@@ -56,8 +56,13 @@ class TcbOpenApiHttpCommonRequester {
|
|
|
56
56
|
this.tracingInfo = (0, tracing_1.generateTracingInfo)((_b = (_a = args.config) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.eventID);
|
|
57
57
|
}
|
|
58
58
|
async request() {
|
|
59
|
-
|
|
59
|
+
// 如果没有 accessKey,去检查密钥是否存在,有则直接使用
|
|
60
|
+
if (!this.config.accessKey) {
|
|
61
|
+
// 检查密钥是否存在
|
|
62
|
+
await this.prepareCredentials();
|
|
63
|
+
}
|
|
60
64
|
const opts = this.makeReqOpts();
|
|
65
|
+
// console.log('opts', opts)
|
|
61
66
|
const argopts = this.opts;
|
|
62
67
|
const config = this.config;
|
|
63
68
|
// 注意:必须初始化为 null
|
|
@@ -140,7 +145,7 @@ class TcbOpenApiHttpCommonRequester {
|
|
|
140
145
|
buildHeaders(method, url) {
|
|
141
146
|
var _a;
|
|
142
147
|
const config = this.config;
|
|
143
|
-
const { context, secretId, secretKey, sessionToken } = config;
|
|
148
|
+
const { context, secretId, secretKey, sessionToken, accessKey } = config;
|
|
144
149
|
const args = this.args;
|
|
145
150
|
const { TCB_SOURCE } = cloudbase_1.CloudBase.getCloudbaseContext();
|
|
146
151
|
// Note: 云函数被调用时可能调用端未传递 SOURCE,TCB_SOURCE 可能为空
|
|
@@ -181,12 +186,25 @@ class TcbOpenApiHttpCommonRequester {
|
|
|
181
186
|
withSignedParams: false,
|
|
182
187
|
isCloudApi: true
|
|
183
188
|
});
|
|
189
|
+
// console.log('xxxx', authorization)
|
|
190
|
+
let token = '';
|
|
191
|
+
// 如果请求参数里面传了 token,优先使用 token
|
|
192
|
+
if (args.token) {
|
|
193
|
+
token = makeBearerToken(args.token);
|
|
194
|
+
}
|
|
195
|
+
else if (accessKey) {
|
|
196
|
+
// 如果配置了 API_KEY,优先使用 API_KEY
|
|
197
|
+
token = makeBearerToken(accessKey);
|
|
198
|
+
}
|
|
199
|
+
else if (typeof sessionToken === 'string' && sessionToken !== '') {
|
|
200
|
+
// 如果配置了 sessionToken,携带 sessionToken
|
|
201
|
+
token = `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
token = `${authorization}, Timestamp=${timestamp}`;
|
|
205
|
+
}
|
|
184
206
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
185
|
-
requiredHeaders['Authorization'] =
|
|
186
|
-
? makeBearerToken(args.token)
|
|
187
|
-
: typeof sessionToken === 'string' && sessionToken !== ''
|
|
188
|
-
? `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
189
|
-
: `${authorization}, Timestamp=${timestamp}`;
|
|
207
|
+
requiredHeaders['Authorization'] = token;
|
|
190
208
|
return Object.assign({}, requiredHeaders);
|
|
191
209
|
}
|
|
192
210
|
}
|
|
@@ -56,8 +56,11 @@ class TcbOpenApiHttpRequester {
|
|
|
56
56
|
this.tracingInfo = (0, tracing_1.generateTracingInfo)((_b = (_a = args.config) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.eventID);
|
|
57
57
|
}
|
|
58
58
|
async request() {
|
|
59
|
-
|
|
59
|
+
if (!this.config.accessKey) {
|
|
60
|
+
await this.prepareCredentials();
|
|
61
|
+
}
|
|
60
62
|
const opts = this.makeReqOpts();
|
|
63
|
+
// console.log('opts', opts)
|
|
61
64
|
const argopts = this.opts;
|
|
62
65
|
const config = this.config;
|
|
63
66
|
// 注意:必须初始化为 null
|
|
@@ -140,7 +143,7 @@ class TcbOpenApiHttpRequester {
|
|
|
140
143
|
buildHeaders(method, url) {
|
|
141
144
|
var _a;
|
|
142
145
|
const config = this.config;
|
|
143
|
-
const { context, secretId, secretKey, sessionToken } = config;
|
|
146
|
+
const { context, secretId, secretKey, sessionToken, accessKey } = config;
|
|
144
147
|
const args = this.args;
|
|
145
148
|
const { TCB_SOURCE } = cloudbase_1.CloudBase.getCloudbaseContext();
|
|
146
149
|
// Note: 云函数被调用时可能调用端未传递 SOURCE,TCB_SOURCE 可能为空
|
|
@@ -186,10 +189,24 @@ class TcbOpenApiHttpRequester {
|
|
|
186
189
|
withSignedParams: false,
|
|
187
190
|
isCloudApi: true
|
|
188
191
|
});
|
|
192
|
+
let token = '';
|
|
193
|
+
// 如果请求参数里面传了 token,优先使用 token
|
|
194
|
+
if (args.token) {
|
|
195
|
+
token = makeBearerToken(args.token);
|
|
196
|
+
}
|
|
197
|
+
else if (accessKey) {
|
|
198
|
+
// 如果配置了 API_KEY,优先使用 API_KEY
|
|
199
|
+
token = makeBearerToken(accessKey);
|
|
200
|
+
}
|
|
201
|
+
else if (typeof sessionToken === 'string' && sessionToken !== '') {
|
|
202
|
+
// 如果配置了 sessionToken,使用 sessionToken
|
|
203
|
+
token = `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
token = `${authorization}, Timestamp=${timestamp}`;
|
|
207
|
+
}
|
|
189
208
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
190
|
-
requiredHeaders['Authorization'] =
|
|
191
|
-
? `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
192
|
-
: `${authorization}, Timestamp=${timestamp}`;
|
|
209
|
+
requiredHeaders['Authorization'] = token;
|
|
193
210
|
return Object.assign({}, requiredHeaders);
|
|
194
211
|
}
|
|
195
212
|
}
|
|
@@ -204,3 +221,7 @@ async function request(args) {
|
|
|
204
221
|
return await requester.request();
|
|
205
222
|
}
|
|
206
223
|
exports.request = request;
|
|
224
|
+
function makeBearerToken(token) {
|
|
225
|
+
const trimmed = token.trim();
|
|
226
|
+
return trimmed.startsWith('Bearer ') ? trimmed : `Bearer ${trimmed}`;
|
|
227
|
+
}
|
package/dist/utils/utils.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isValidEnvFormat = exports.isPageModuleName = exports.processReturn = exports.setThrowOnCode = exports.second = exports.isNonEmptyString = exports.E = exports.filterUndefined = exports.filterValue = exports.isAppId = exports.TcbError = void 0;
|
|
26
|
+
exports.normalizeConfig = exports.isValidEnvFormat = exports.isPageModuleName = exports.processReturn = exports.setThrowOnCode = exports.second = exports.isNonEmptyString = exports.E = exports.filterUndefined = exports.filterValue = exports.isAppId = exports.TcbError = void 0;
|
|
27
|
+
const utils = __importStar(require("../utils/utils"));
|
|
28
|
+
const code_1 = require("../const/code");
|
|
4
29
|
class TcbError extends Error {
|
|
5
30
|
constructor(error) {
|
|
6
31
|
super(error.message);
|
|
@@ -72,3 +97,50 @@ function isValidEnvFormat(env = '') {
|
|
|
72
97
|
return typeof env === 'string' && kEnvRuleReg.test(env);
|
|
73
98
|
}
|
|
74
99
|
exports.isValidEnvFormat = isValidEnvFormat;
|
|
100
|
+
function normalizeConfig(config) {
|
|
101
|
+
var _a, _b, _c, _d;
|
|
102
|
+
const { debug = false, secretId, secretKey, env, timeout = 15000, headers = {}, accessKey } = config;
|
|
103
|
+
// 检查用户显示配置的 secretId 和 secretKey 是否成对出现,要么都有,要么都没有
|
|
104
|
+
if (!secretId !== !secretKey) {
|
|
105
|
+
throw utils.E(Object.assign(Object.assign({}, code_1.ERROR.INVALID_PARAM), { message: 'secretId and secretKey must be a pair' }));
|
|
106
|
+
}
|
|
107
|
+
const cloudbaseConfigBase = Object.assign(Object.assign({}, config), { debug,
|
|
108
|
+
// secretId,
|
|
109
|
+
// secretKey,
|
|
110
|
+
envName: env, headers: Object.assign({}, headers), // 结构用户传进来的 headers,防止用户修改原对象
|
|
111
|
+
timeout
|
|
112
|
+
// accessKey: accessKey || process.env.CLOUDBASE_APIKEY
|
|
113
|
+
});
|
|
114
|
+
const { TENCENTCLOUD_SECRETID, TENCENTCLOUD_SECRETKEY, TENCENTCLOUD_SESSIONTOKEN, CLOUDBASE_APIKEY } = process.env;
|
|
115
|
+
// 如果用户显示配置了accessKey,取用户显示配置的 accessKey,优先级最高
|
|
116
|
+
if (accessKey) {
|
|
117
|
+
return Object.assign(cloudbaseConfigBase, { secretId: undefined, secretKey: undefined, accessKey });
|
|
118
|
+
}
|
|
119
|
+
// 显示配置了 secretId, secretKey,取 secretId, secretKey
|
|
120
|
+
if (secretId && secretKey) {
|
|
121
|
+
return Object.assign(cloudbaseConfigBase, { secretId, secretKey, accessKey: undefined });
|
|
122
|
+
}
|
|
123
|
+
// 下面从环境变量取 secretId, secretKey, accessKey
|
|
124
|
+
if (CLOUDBASE_APIKEY) {
|
|
125
|
+
return Object.assign(cloudbaseConfigBase, { secretId: undefined, secretKey: undefined, accessKey: CLOUDBASE_APIKEY });
|
|
126
|
+
}
|
|
127
|
+
if (TENCENTCLOUD_SECRETID && TENCENTCLOUD_SECRETKEY) {
|
|
128
|
+
return Object.assign(cloudbaseConfigBase, { secretId: TENCENTCLOUD_SECRETID, secretKey: TENCENTCLOUD_SECRETKEY, sessionToken: TENCENTCLOUD_SESSIONTOKEN, accessKey: undefined });
|
|
129
|
+
}
|
|
130
|
+
if ((_a = config.context) === null || _a === void 0 ? void 0 : _a.extendedContext) {
|
|
131
|
+
const extendedContext = config.context.extendedContext;
|
|
132
|
+
if (!cloudbaseConfigBase.env) {
|
|
133
|
+
cloudbaseConfigBase.env = extendedContext.envId;
|
|
134
|
+
cloudbaseConfigBase.envName = extendedContext.envId;
|
|
135
|
+
}
|
|
136
|
+
// 从 context 中获取 secret
|
|
137
|
+
if (!cloudbaseConfigBase.secretId && !cloudbaseConfigBase.secretKey) {
|
|
138
|
+
cloudbaseConfigBase.secretId = (_b = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _b === void 0 ? void 0 : _b.secretId;
|
|
139
|
+
cloudbaseConfigBase.secretKey = (_c = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _c === void 0 ? void 0 : _c.secretKey;
|
|
140
|
+
cloudbaseConfigBase.sessionToken = (_d = extendedContext === null || extendedContext === void 0 ? void 0 : extendedContext.tmpSecret) === null || _d === void 0 ? void 0 : _d.token;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 都没有配置,返回原始的配置
|
|
144
|
+
return cloudbaseConfigBase;
|
|
145
|
+
}
|
|
146
|
+
exports.normalizeConfig = normalizeConfig;
|
package/package.json
CHANGED
package/src/auth/index.ts
CHANGED
|
@@ -147,6 +147,10 @@ export class Auth {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
public async getClientCredential(opts?: ICustomReqOpts): Promise<any> {
|
|
150
|
+
// 如果有 accessKey 直接返回 accessKey,不用再去换取 token
|
|
151
|
+
if (this.cloudbase.config.accessKey) {
|
|
152
|
+
return this.cloudbase.config.accessKey
|
|
153
|
+
}
|
|
150
154
|
return await tcbopenapicommonrequester.request({
|
|
151
155
|
config: this.cloudbase.config,
|
|
152
156
|
method: 'POST',
|
|
@@ -183,7 +187,7 @@ export class Auth {
|
|
|
183
187
|
throw E({
|
|
184
188
|
...ERROR.INVALID_PARAM,
|
|
185
189
|
message:
|
|
186
|
-
|
|
190
|
+
'当前私钥未包含env_id 信息, 请前往腾讯云云开发控制台,获取自定义登录最新私钥'
|
|
187
191
|
})
|
|
188
192
|
}
|
|
189
193
|
|
package/src/cloudbase.ts
CHANGED
|
@@ -63,7 +63,7 @@ import { IFetchOptions } from '@cloudbase/adapter-interface'
|
|
|
63
63
|
import { buildCommonOpenApiUrlWithPath } from './utils/tcbopenapiendpoint'
|
|
64
64
|
import { SYMBOL_CURRENT_ENV } from './const/symbol'
|
|
65
65
|
import { IncomingHttpHeaders } from 'http'
|
|
66
|
-
|
|
66
|
+
import { normalizeConfig } from './utils/utils'
|
|
67
67
|
export class CloudBase {
|
|
68
68
|
public static scfContext: ISCFContext
|
|
69
69
|
|
|
@@ -100,43 +100,10 @@ export class CloudBase {
|
|
|
100
100
|
/* eslint-disable-next-line */
|
|
101
101
|
preflightRuntimeCloudPlatform()
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
...ERROR.INVALID_PARAM,
|
|
108
|
-
message: 'secretId and secretKey must be a pair'
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const newConfig: ICloudBaseConfig = {
|
|
113
|
-
...restConfig,
|
|
114
|
-
debug: !!debug,
|
|
115
|
-
secretId,
|
|
116
|
-
secretKey,
|
|
117
|
-
sessionToken,
|
|
118
|
-
env,
|
|
119
|
-
envName: env,
|
|
120
|
-
headers: { ...headers },
|
|
121
|
-
timeout: timeout || 15000
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (config.context?.extendedContext) {
|
|
125
|
-
const extendedContext = config.context.extendedContext
|
|
126
|
-
if (!newConfig.env) {
|
|
127
|
-
newConfig.env = extendedContext.envId
|
|
128
|
-
newConfig.envName = newConfig.env
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 从 context 中获取 secret
|
|
132
|
-
if (!newConfig.secretId && !newConfig.secretKey) {
|
|
133
|
-
newConfig.secretId = extendedContext?.tmpSecret?.secretId
|
|
134
|
-
newConfig.secretKey = extendedContext?.tmpSecret?.secretKey
|
|
135
|
-
newConfig.sessionToken = extendedContext?.tmpSecret?.token
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
this.config = newConfig
|
|
103
|
+
// 所有的鉴权,参数塑形都在 normalizeConfig 中处理
|
|
104
|
+
// 后续其他模块获取 config 都通过 CloudBase 实例的 config 获取
|
|
105
|
+
// 禁止在业务模块中直接修改 config 配置
|
|
106
|
+
this.config = normalizeConfig(config)
|
|
140
107
|
this.extensionMap = new Map()
|
|
141
108
|
|
|
142
109
|
// NOTE:try-catch 为防止 init 报错
|
|
@@ -155,6 +122,10 @@ export class CloudBase {
|
|
|
155
122
|
'Content-Type': 'application/json',
|
|
156
123
|
...headersInitToRecord(options.headers)
|
|
157
124
|
},
|
|
125
|
+
/**
|
|
126
|
+
* 既然 openapicommonrequester.request 的参数里的 token 获取也是通过 openapicommonrequester.request 方法去获取的
|
|
127
|
+
* 为什么不把这里的 token 去掉,全部放在 openapicommonrequester.request 中去统一处理 token 获取的逻辑
|
|
128
|
+
*/
|
|
158
129
|
token: (await this.auth().getClientCredential()).access_token
|
|
159
130
|
})
|
|
160
131
|
return result.body
|
|
@@ -147,10 +147,15 @@ export class TcbApiHttpRequester {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
public async request(): Promise<any> {
|
|
150
|
-
|
|
150
|
+
// 如果没有配置 accessKey,则通过密钥获取签名,这里先检查密钥是否存在
|
|
151
|
+
if (!this.config.accessKey) {
|
|
152
|
+
// 检查密钥是否存在
|
|
153
|
+
await this.prepareCredentials()
|
|
154
|
+
}
|
|
151
155
|
const params = await this.makeParams()
|
|
152
|
-
|
|
156
|
+
// console.log('params', params)
|
|
153
157
|
const opts = this.makeReqOpts(params)
|
|
158
|
+
// console.log('opts', opts)
|
|
154
159
|
const action = this.getAction()
|
|
155
160
|
const key = {
|
|
156
161
|
functions: 'function_name',
|
|
@@ -321,7 +326,7 @@ export class TcbApiHttpRequester {
|
|
|
321
326
|
|
|
322
327
|
private getHeaders(method: string, url: string, params: any): any {
|
|
323
328
|
const config = this.config
|
|
324
|
-
const { context, secretId, secretKey } = config
|
|
329
|
+
const { context, secretId, secretKey, accessKey } = config
|
|
325
330
|
const args = this.args
|
|
326
331
|
|
|
327
332
|
const { TCB_SOURCE } = CloudBase.getCloudbaseContext()
|
|
@@ -371,7 +376,8 @@ export class TcbApiHttpRequester {
|
|
|
371
376
|
})
|
|
372
377
|
|
|
373
378
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
374
|
-
|
|
379
|
+
// 优先使用 accessKey,否则使用签名
|
|
380
|
+
requiredHeaders['Authorization'] = accessKey ? `Bearer ${accessKey}` : authorization
|
|
375
381
|
requiredHeaders['X-Signature-Expires'] = 600
|
|
376
382
|
requiredHeaders['X-Timestamp'] = timestamp
|
|
377
383
|
|
|
@@ -390,6 +396,7 @@ const handleWxOpenApiData = (res: any, err: any, response: any, body: any): any
|
|
|
390
396
|
}
|
|
391
397
|
|
|
392
398
|
export async function request(args: IRequestInfo): Promise<any> {
|
|
399
|
+
// console.log('args', args)
|
|
393
400
|
if (typeof args.isInternal === 'undefined') {
|
|
394
401
|
args.isInternal = await checkIsInternalAsync()
|
|
395
402
|
}
|
package/src/utils/tcbcontext.ts
CHANGED
|
@@ -76,6 +76,7 @@ export function parseContext(context: IContextParam): ISCFContext {
|
|
|
76
76
|
* 获取当前函数内的所有环境变量(作为获取变量的统一方法,取值来源 process.env 和 context)
|
|
77
77
|
*/
|
|
78
78
|
export function getCloudbaseContext(context?: IContextParam): ICompleteCloudbaseContext {
|
|
79
|
+
// console.log('context', context)
|
|
79
80
|
if (checkIsInScf()) {
|
|
80
81
|
// 云函数环境下,应该包含以下环境变量,如果没有,后续逻辑可能会有问题
|
|
81
82
|
if (!process.env.TENCENTCLOUD_REGION) {
|
|
@@ -17,7 +17,6 @@ export class TcbDBApiHttpRequester {
|
|
|
17
17
|
public async send(api: string, data: any, opts?: ICustomReqOpts): Promise<any> {
|
|
18
18
|
const { instance, database, ...config } = this.config
|
|
19
19
|
const params = { ...data, action: api, instance, database }
|
|
20
|
-
|
|
21
20
|
return await tcbapicaller.request({
|
|
22
21
|
config,
|
|
23
22
|
params,
|
|
@@ -54,9 +54,14 @@ export class TcbOpenApiHttpCommonRequester {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
public async request() {
|
|
57
|
-
|
|
57
|
+
// 如果没有 accessKey,去检查密钥是否存在,有则直接使用
|
|
58
|
+
if (!this.config.accessKey) {
|
|
59
|
+
// 检查密钥是否存在
|
|
60
|
+
await this.prepareCredentials()
|
|
61
|
+
}
|
|
58
62
|
|
|
59
63
|
const opts = this.makeReqOpts()
|
|
64
|
+
// console.log('opts', opts)
|
|
60
65
|
|
|
61
66
|
const argopts: any = this.opts
|
|
62
67
|
const config = this.config
|
|
@@ -144,7 +149,7 @@ export class TcbOpenApiHttpCommonRequester {
|
|
|
144
149
|
|
|
145
150
|
private buildHeaders(method: string, url: string): any {
|
|
146
151
|
const config = this.config
|
|
147
|
-
const { context, secretId, secretKey, sessionToken } = config
|
|
152
|
+
const { context, secretId, secretKey, sessionToken, accessKey } = config
|
|
148
153
|
const args = this.args
|
|
149
154
|
|
|
150
155
|
const { TCB_SOURCE } = CloudBase.getCloudbaseContext()
|
|
@@ -194,13 +199,22 @@ export class TcbOpenApiHttpCommonRequester {
|
|
|
194
199
|
withSignedParams: false,
|
|
195
200
|
isCloudApi: true
|
|
196
201
|
})
|
|
197
|
-
|
|
202
|
+
// console.log('xxxx', authorization)
|
|
203
|
+
let token = ''
|
|
204
|
+
// 如果请求参数里面传了 token,优先使用 token
|
|
205
|
+
if (args.token) {
|
|
206
|
+
token = makeBearerToken(args.token)
|
|
207
|
+
} else if (accessKey) {
|
|
208
|
+
// 如果配置了 API_KEY,优先使用 API_KEY
|
|
209
|
+
token = makeBearerToken(accessKey)
|
|
210
|
+
} else if (typeof sessionToken === 'string' && sessionToken !== '') {
|
|
211
|
+
// 如果配置了 sessionToken,携带 sessionToken
|
|
212
|
+
token = `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
213
|
+
} else {
|
|
214
|
+
token = `${authorization}, Timestamp=${timestamp}`
|
|
215
|
+
}
|
|
198
216
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
199
|
-
requiredHeaders['Authorization'] =
|
|
200
|
-
? makeBearerToken(args.token)
|
|
201
|
-
: typeof sessionToken === 'string' && sessionToken !== ''
|
|
202
|
-
? `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
203
|
-
: `${authorization}, Timestamp=${timestamp}`
|
|
217
|
+
requiredHeaders['Authorization'] = token
|
|
204
218
|
|
|
205
219
|
return { ...requiredHeaders }
|
|
206
220
|
}
|
|
@@ -30,6 +30,7 @@ export function getEnvIdFromContext(): string {
|
|
|
30
30
|
type ICallContainerRequestInfo = Omit<IRequestInfo, 'params'> & {
|
|
31
31
|
path: string
|
|
32
32
|
data: any
|
|
33
|
+
token?: string
|
|
33
34
|
cloudrun: {
|
|
34
35
|
name: string
|
|
35
36
|
// version: string
|
|
@@ -56,9 +57,12 @@ export class TcbOpenApiHttpRequester {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
public async request(): Promise<any> {
|
|
59
|
-
|
|
60
|
+
if (!this.config.accessKey) {
|
|
61
|
+
await this.prepareCredentials()
|
|
62
|
+
}
|
|
60
63
|
|
|
61
64
|
const opts = this.makeReqOpts()
|
|
65
|
+
// console.log('opts', opts)
|
|
62
66
|
|
|
63
67
|
const argopts: any = this.opts
|
|
64
68
|
const config = this.config
|
|
@@ -147,7 +151,7 @@ export class TcbOpenApiHttpRequester {
|
|
|
147
151
|
|
|
148
152
|
private buildHeaders(method: string, url: string): any {
|
|
149
153
|
const config = this.config
|
|
150
|
-
const { context, secretId, secretKey, sessionToken } = config
|
|
154
|
+
const { context, secretId, secretKey, sessionToken, accessKey } = config
|
|
151
155
|
const args = this.args
|
|
152
156
|
|
|
153
157
|
const { TCB_SOURCE } = CloudBase.getCloudbaseContext()
|
|
@@ -204,11 +208,21 @@ export class TcbOpenApiHttpRequester {
|
|
|
204
208
|
withSignedParams: false,
|
|
205
209
|
isCloudApi: true
|
|
206
210
|
})
|
|
207
|
-
|
|
211
|
+
let token = ''
|
|
212
|
+
// 如果请求参数里面传了 token,优先使用 token
|
|
213
|
+
if (args.token) {
|
|
214
|
+
token = makeBearerToken(args.token)
|
|
215
|
+
} else if (accessKey) {
|
|
216
|
+
// 如果配置了 API_KEY,优先使用 API_KEY
|
|
217
|
+
token = makeBearerToken(accessKey)
|
|
218
|
+
} else if (typeof sessionToken === 'string' && sessionToken !== '') {
|
|
219
|
+
// 如果配置了 sessionToken,使用 sessionToken
|
|
220
|
+
token = `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
221
|
+
} else {
|
|
222
|
+
token = `${authorization}, Timestamp=${timestamp}`
|
|
223
|
+
}
|
|
208
224
|
/* eslint-disable @typescript-eslint/dot-notation */
|
|
209
|
-
requiredHeaders['Authorization'] =
|
|
210
|
-
? `${authorization}, Timestamp=${timestamp}, Token=${sessionToken}`
|
|
211
|
-
: `${authorization}, Timestamp=${timestamp}`
|
|
225
|
+
requiredHeaders['Authorization'] = token
|
|
212
226
|
|
|
213
227
|
return { ...requiredHeaders }
|
|
214
228
|
}
|
|
@@ -225,3 +239,7 @@ export async function request(args: ICallContainerRequestInfo & { path: string }
|
|
|
225
239
|
|
|
226
240
|
return await requester.request()
|
|
227
241
|
}
|
|
242
|
+
function makeBearerToken(token: string): string {
|
|
243
|
+
const trimmed = token.trim()
|
|
244
|
+
return trimmed.startsWith('Bearer ') ? trimmed : `Bearer ${trimmed}`
|
|
245
|
+
}
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { ICloudBaseConfig } from '../../types'
|
|
2
|
+
import * as utils from '../utils/utils'
|
|
3
|
+
import { ERROR } from '../const/code'
|
|
4
|
+
|
|
1
5
|
interface IErrorInfo {
|
|
2
6
|
requestId?: string
|
|
3
7
|
code?: string
|
|
@@ -81,3 +85,61 @@ const kEnvRuleReg = /^[a-z0-9_-]{1,40}$/
|
|
|
81
85
|
export function isValidEnvFormat(env = '') {
|
|
82
86
|
return typeof env === 'string' && kEnvRuleReg.test(env)
|
|
83
87
|
}
|
|
88
|
+
export function normalizeConfig(config: ICloudBaseConfig) {
|
|
89
|
+
const { debug = false, secretId, secretKey, env, timeout = 15000, headers = {}, accessKey } = config
|
|
90
|
+
|
|
91
|
+
// 检查用户显示配置的 secretId 和 secretKey 是否成对出现,要么都有,要么都没有
|
|
92
|
+
if (!secretId !== !secretKey) {
|
|
93
|
+
throw utils.E({
|
|
94
|
+
...ERROR.INVALID_PARAM,
|
|
95
|
+
message: 'secretId and secretKey must be a pair'
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
const cloudbaseConfigBase: ICloudBaseConfig = {
|
|
99
|
+
...config,
|
|
100
|
+
debug,
|
|
101
|
+
// secretId,
|
|
102
|
+
// secretKey,
|
|
103
|
+
envName: env,
|
|
104
|
+
headers: { ...headers }, // 结构用户传进来的 headers,防止用户修改原对象
|
|
105
|
+
timeout
|
|
106
|
+
// accessKey: accessKey || process.env.CLOUDBASE_APIKEY
|
|
107
|
+
}
|
|
108
|
+
const {
|
|
109
|
+
TENCENTCLOUD_SECRETID,
|
|
110
|
+
TENCENTCLOUD_SECRETKEY,
|
|
111
|
+
TENCENTCLOUD_SESSIONTOKEN,
|
|
112
|
+
CLOUDBASE_APIKEY
|
|
113
|
+
} = process.env
|
|
114
|
+
// 如果用户显示配置了accessKey,取用户显示配置的 accessKey,优先级最高
|
|
115
|
+
if (accessKey) {
|
|
116
|
+
return Object.assign(cloudbaseConfigBase, { secretId: undefined, secretKey: undefined, accessKey })
|
|
117
|
+
}
|
|
118
|
+
// 显示配置了 secretId, secretKey,取 secretId, secretKey
|
|
119
|
+
if (secretId && secretKey) {
|
|
120
|
+
return Object.assign(cloudbaseConfigBase, { secretId, secretKey, accessKey: undefined })
|
|
121
|
+
}
|
|
122
|
+
// 下面从环境变量取 secretId, secretKey, accessKey
|
|
123
|
+
if (CLOUDBASE_APIKEY) {
|
|
124
|
+
return Object.assign(cloudbaseConfigBase, { secretId: undefined, secretKey: undefined, accessKey: CLOUDBASE_APIKEY })
|
|
125
|
+
}
|
|
126
|
+
if (TENCENTCLOUD_SECRETID && TENCENTCLOUD_SECRETKEY) {
|
|
127
|
+
return Object.assign(cloudbaseConfigBase, { secretId: TENCENTCLOUD_SECRETID, secretKey: TENCENTCLOUD_SECRETKEY, sessionToken: TENCENTCLOUD_SESSIONTOKEN, accessKey: undefined })
|
|
128
|
+
}
|
|
129
|
+
if (config.context?.extendedContext) {
|
|
130
|
+
const extendedContext = config.context.extendedContext
|
|
131
|
+
if (!cloudbaseConfigBase.env) {
|
|
132
|
+
cloudbaseConfigBase.env = extendedContext.envId
|
|
133
|
+
cloudbaseConfigBase.envName = extendedContext.envId
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 从 context 中获取 secret
|
|
137
|
+
if (!cloudbaseConfigBase.secretId && !cloudbaseConfigBase.secretKey) {
|
|
138
|
+
cloudbaseConfigBase.secretId = extendedContext?.tmpSecret?.secretId
|
|
139
|
+
cloudbaseConfigBase.secretKey = extendedContext?.tmpSecret?.secretKey
|
|
140
|
+
cloudbaseConfigBase.sessionToken = extendedContext?.tmpSecret?.token
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 都没有配置,返回原始的配置
|
|
144
|
+
return cloudbaseConfigBase
|
|
145
|
+
}
|
package/types/index.d.ts
CHANGED