@cloudbase/node-sdk 3.17.2 → 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 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 兼容问题
@@ -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
- const { debug, secretId, secretKey, sessionToken, env, timeout, headers = {} } = config, restConfig = __rest(config, ["debug", "secretId", "secretKey", "sessionToken", "env", "timeout", "headers"]);
79
- if (('secretId' in config && !('secretKey' in config)) || (!('secretId' in config) && 'secretKey' in config)) {
80
- throw utils.E(Object.assign(Object.assign({}, code_1.ERROR.INVALID_PARAM), { message: 'secretId and secretKey must be a pair' }));
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
- await this.prepareCredentials();
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
- requiredHeaders['Authorization'] = authorization;
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
  }
@@ -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
- await this.prepareCredentials();
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'] = args.token
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
- await this.prepareCredentials();
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'] = typeof sessionToken === 'string' && sessionToken !== ''
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
+ }
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/node-sdk",
3
- "version": "3.17.2",
3
+ "version": "3.18.0",
4
4
  "description": "tencent cloud base server sdk for node.js",
5
5
  "main": "dist/index.js",
6
6
  "typings": "types/index.d.ts",
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
- '当前私钥未包含env_id 信息, 请前往腾讯云云开发控制台,获取自定义登录最新私钥'
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
- const { debug, secretId, secretKey, sessionToken, env, timeout, headers = {}, ...restConfig } = config
104
-
105
- if (('secretId' in config && !('secretKey' in config)) || (!('secretId' in config) && 'secretKey' in config)) {
106
- throw utils.E({
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
- await this.prepareCredentials()
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
- requiredHeaders['Authorization'] = authorization
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
  }
@@ -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
- await this.prepareCredentials()
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'] = args.token
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
- await this.prepareCredentials()
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'] = typeof sessionToken === 'string' && sessionToken !== ''
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
+ }
@@ -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
@@ -197,6 +197,7 @@ export interface ICloudBaseConfig extends IKeyValue {
197
197
  version?: string
198
198
  credentials?: ICredentialsInfo
199
199
  region?: string
200
+ accessKey?: string
200
201
 
201
202
  // @cloudbase/functions-framework 函数上下文,只要求部分字段
202
203
  context?: Readonly<{