@cloudbase/app 2.0.3-alpha.0 → 2.5.0-beta.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/.eslintrc.js +15 -0
- package/dist/cjs/constants/common.js +7 -7
- package/dist/cjs/index.js +30 -29
- package/dist/cjs/libs/adapter.d.ts +1 -1
- package/dist/cjs/libs/adapter.js +1 -1
- package/dist/cjs/libs/cache.d.ts +1 -1
- package/dist/cjs/libs/cache.js +1 -1
- package/dist/cjs/libs/component.js +15 -10
- package/dist/cjs/libs/request.d.ts +4 -6
- package/dist/cjs/libs/request.js +49 -47
- package/dist/esm/constants/common.js +7 -7
- package/dist/esm/index.js +30 -29
- package/dist/esm/libs/adapter.d.ts +1 -1
- package/dist/esm/libs/adapter.js +1 -1
- package/dist/esm/libs/cache.d.ts +1 -1
- package/dist/esm/libs/cache.js +2 -2
- package/dist/esm/libs/component.js +15 -10
- package/dist/esm/libs/request.d.ts +4 -6
- package/dist/esm/libs/request.js +50 -48
- package/package.json +12 -16
- package/src/constants/common.ts +15 -21
- package/src/global.d.ts +1 -1
- package/src/index.ts +91 -89
- package/src/libs/adapter.ts +2 -2
- package/src/libs/cache.ts +15 -33
- package/src/libs/component.ts +69 -66
- package/src/libs/request.ts +120 -127
- package/.eslintrc +0 -29
package/src/libs/request.ts
CHANGED
|
@@ -2,27 +2,25 @@ import {
|
|
|
2
2
|
DATA_VERSION,
|
|
3
3
|
getSdkVersion,
|
|
4
4
|
getEndPoint,
|
|
5
|
-
getBaseEndPoint
|
|
6
|
-
} from '../constants/common'
|
|
5
|
+
getBaseEndPoint,
|
|
6
|
+
} from '../constants/common'
|
|
7
7
|
import {
|
|
8
8
|
IRequestOptions,
|
|
9
9
|
SDKRequestInterface,
|
|
10
10
|
ResponseObject,
|
|
11
11
|
IUploadRequestOptions,
|
|
12
|
-
IRequestConfig
|
|
13
|
-
} from '@cloudbase/adapter-interface'
|
|
14
|
-
import { utils, adapters, constants } from '@cloudbase/utilities'
|
|
15
|
-
import { KV } from '@cloudbase/types'
|
|
16
|
-
import { IGetAccessTokenResult, ICloudbaseRequestConfig, IAppendedRequestInfo, IRequestBeforeHook } from '@cloudbase/types/request'
|
|
17
|
-
import { ICloudbaseCache } from '@cloudbase/types/cache'
|
|
18
|
-
import { getLocalCache } from './cache'
|
|
19
|
-
import { Platform } from './adapter'
|
|
20
|
-
const { ERRORS } = constants
|
|
21
|
-
const { genSeqId, isFormData, formatUrl, createSign } = utils
|
|
22
|
-
const { RUNTIME } = adapters
|
|
12
|
+
IRequestConfig,
|
|
13
|
+
} from '@cloudbase/adapter-interface'
|
|
14
|
+
import { utils, adapters, constants } from '@cloudbase/utilities'
|
|
15
|
+
import { KV } from '@cloudbase/types'
|
|
16
|
+
import { IGetAccessTokenResult, ICloudbaseRequestConfig, IAppendedRequestInfo, IRequestBeforeHook } from '@cloudbase/types/request'
|
|
17
|
+
import { ICloudbaseCache } from '@cloudbase/types/cache'
|
|
18
|
+
import { getLocalCache } from './cache'
|
|
19
|
+
import { Platform } from './adapter'
|
|
20
|
+
const { ERRORS } = constants
|
|
21
|
+
const { genSeqId, isFormData, formatUrl, createSign } = utils
|
|
22
|
+
const { RUNTIME } = adapters
|
|
23
23
|
|
|
24
|
-
// import FingerprintJS from '@fingerprintjs/fingerprintjs'
|
|
25
|
-
// const fpPromise = FingerprintJS.load()
|
|
26
24
|
|
|
27
25
|
// 下面几种 action 不需要 access token
|
|
28
26
|
const ACTIONS_WITHOUT_ACCESSTOKEN = [
|
|
@@ -36,50 +34,50 @@ const ACTIONS_WITHOUT_ACCESSTOKEN = [
|
|
|
36
34
|
'auth.activateEndUserMail',
|
|
37
35
|
'auth.sendPasswordResetEmail',
|
|
38
36
|
'auth.resetPasswordWithToken',
|
|
39
|
-
'auth.isUsernameRegistered'
|
|
40
|
-
]
|
|
37
|
+
'auth.isUsernameRegistered',
|
|
38
|
+
]
|
|
41
39
|
|
|
42
40
|
function bindHooks(instance: SDKRequestInterface, name: string, hooks: IRequestBeforeHook[]) {
|
|
43
|
-
const originMethod = instance[name]
|
|
41
|
+
const originMethod = instance[name]
|
|
44
42
|
instance[name] = function (options: IRequestOptions) {
|
|
45
|
-
const data = {}
|
|
46
|
-
const headers = {}
|
|
47
|
-
hooks.forEach(hook => {
|
|
48
|
-
const { data: appendedData, headers: appendedHeaders } = hook.call(instance, options)
|
|
49
|
-
Object.assign(data, appendedData)
|
|
50
|
-
Object.assign(headers, appendedHeaders)
|
|
51
|
-
})
|
|
52
|
-
const originData = options.data
|
|
43
|
+
const data = {}
|
|
44
|
+
const headers = {}
|
|
45
|
+
hooks.forEach((hook) => {
|
|
46
|
+
const { data: appendedData, headers: appendedHeaders } = hook.call(instance, options)
|
|
47
|
+
Object.assign(data, appendedData)
|
|
48
|
+
Object.assign(headers, appendedHeaders)
|
|
49
|
+
})
|
|
50
|
+
const originData = options.data
|
|
53
51
|
originData && (() => {
|
|
54
52
|
if (isFormData(originData)) {
|
|
55
|
-
|
|
56
|
-
(originData as FormData).append(key, data[key])
|
|
57
|
-
}
|
|
58
|
-
return
|
|
53
|
+
Object.keys(data).forEach((key) => {
|
|
54
|
+
(originData as FormData).append(key, data[key])
|
|
55
|
+
})
|
|
56
|
+
return
|
|
59
57
|
}
|
|
60
58
|
options.data = {
|
|
61
59
|
...originData,
|
|
62
|
-
...data
|
|
63
|
-
}
|
|
64
|
-
})()
|
|
60
|
+
...data,
|
|
61
|
+
}
|
|
62
|
+
})()
|
|
65
63
|
options.headers = {
|
|
66
64
|
...(options.headers || {}),
|
|
67
|
-
...headers
|
|
68
|
-
}
|
|
69
|
-
return (originMethod as Function).call(instance, options)
|
|
70
|
-
}
|
|
65
|
+
...headers,
|
|
66
|
+
}
|
|
67
|
+
return (originMethod as Function).call(instance, options)
|
|
68
|
+
}
|
|
71
69
|
}
|
|
72
70
|
function beforeEach(): IAppendedRequestInfo {
|
|
73
|
-
const seqId = genSeqId()
|
|
71
|
+
const seqId = genSeqId()
|
|
74
72
|
return {
|
|
75
73
|
data: {
|
|
76
|
-
seqId
|
|
74
|
+
seqId,
|
|
77
75
|
},
|
|
78
76
|
headers: {
|
|
79
77
|
'X-SDK-Version': `@cloudbase/js-sdk/${getSdkVersion()}`,
|
|
80
|
-
'x-seqid': seqId
|
|
81
|
-
}
|
|
82
|
-
}
|
|
78
|
+
'x-seqid': seqId,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
83
81
|
}
|
|
84
82
|
export interface ICloudbaseRequest {
|
|
85
83
|
post: (options: IRequestOptions) => Promise<ResponseObject>;
|
|
@@ -93,45 +91,42 @@ export interface ICloudbaseRequest {
|
|
|
93
91
|
* @class CloudbaseRequest
|
|
94
92
|
*/
|
|
95
93
|
export class CloudbaseRequest implements ICloudbaseRequest {
|
|
96
|
-
config: ICloudbaseRequestConfig
|
|
97
|
-
|
|
98
|
-
_refreshAccessTokenPromise: Promise<IGetAccessTokenResult> | null
|
|
99
|
-
_reqClass: SDKRequestInterface;
|
|
94
|
+
config: ICloudbaseRequestConfig
|
|
95
|
+
private reqClass: SDKRequestInterface
|
|
100
96
|
// 请求失败是否抛出Error
|
|
101
|
-
private
|
|
97
|
+
private throwWhenRequestFail = false
|
|
102
98
|
// 持久化本地存储
|
|
103
|
-
private
|
|
99
|
+
private localCache: ICloudbaseCache
|
|
104
100
|
/**
|
|
105
101
|
* 初始化
|
|
106
102
|
* @param config
|
|
107
103
|
*/
|
|
108
104
|
constructor(config: ICloudbaseRequestConfig & { throw?: boolean }) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// eslint-disable-next-line
|
|
112
|
-
this._reqClass = new Platform.adapter.reqClass(<IRequestConfig>{
|
|
105
|
+
this.config = config
|
|
106
|
+
const reqConfig: IRequestConfig = {
|
|
113
107
|
timeout: this.config.timeout,
|
|
114
108
|
timeoutMsg: `[@cloudbase/js-sdk] 请求在${this.config.timeout / 1000}s内未完成,已中断`,
|
|
115
|
-
restrictedMethods: ['post', 'put']
|
|
116
|
-
}
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
bindHooks(this.
|
|
121
|
-
bindHooks(this.
|
|
109
|
+
restrictedMethods: ['post', 'put'],
|
|
110
|
+
}
|
|
111
|
+
this.reqClass = new Platform.adapter.reqClass(reqConfig)
|
|
112
|
+
this.throwWhenRequestFail = config.throw || false
|
|
113
|
+
this.localCache = getLocalCache(this.config.env)
|
|
114
|
+
bindHooks(this.reqClass, 'post', [beforeEach])
|
|
115
|
+
bindHooks(this.reqClass, 'upload', [beforeEach])
|
|
116
|
+
bindHooks(this.reqClass, 'download', [beforeEach])
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
public async post(options: IRequestOptions): Promise<ResponseObject> {
|
|
125
|
-
const res = await this.
|
|
126
|
-
return res
|
|
120
|
+
const res = await this.reqClass.post(options)
|
|
121
|
+
return res
|
|
127
122
|
}
|
|
128
123
|
public async upload(options: IUploadRequestOptions): Promise<ResponseObject> {
|
|
129
|
-
const res = await this.
|
|
130
|
-
return res
|
|
124
|
+
const res = await this.reqClass.upload(options)
|
|
125
|
+
return res
|
|
131
126
|
}
|
|
132
127
|
public async download(options: IRequestOptions): Promise<ResponseObject> {
|
|
133
|
-
const res = await this.
|
|
134
|
-
return res
|
|
128
|
+
const res = await this.reqClass.download(options)
|
|
129
|
+
return res
|
|
135
130
|
}
|
|
136
131
|
|
|
137
132
|
public getBaseEndPoint() {
|
|
@@ -140,153 +135,151 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
140
135
|
|
|
141
136
|
public async getOauthAccessTokenV2(oauthClient: any): Promise<IGetAccessTokenResult> {
|
|
142
137
|
const validAccessToken = await oauthClient.getAccessToken()
|
|
143
|
-
const credentials = await oauthClient.
|
|
138
|
+
const credentials = await oauthClient.getCredentials()
|
|
144
139
|
return {
|
|
145
140
|
accessToken: validAccessToken,
|
|
146
|
-
accessTokenExpire: new Date(credentials.expires_at).getTime()
|
|
141
|
+
accessTokenExpire: new Date(credentials.expires_at).getTime(),
|
|
147
142
|
}
|
|
148
143
|
}
|
|
149
144
|
|
|
150
145
|
|
|
151
146
|
/* eslint-disable complexity */
|
|
152
147
|
public async request(action: string, params: KV<any>, options?: KV<any>): Promise<ResponseObject> {
|
|
153
|
-
const tcbTraceKey = `x-tcb-trace_${this.config.env}
|
|
154
|
-
let contentType = 'application/x-www-form-urlencoded'
|
|
155
|
-
// const webDeviceId = await getTcbFingerprintId();
|
|
148
|
+
const tcbTraceKey = `x-tcb-trace_${this.config.env}`
|
|
149
|
+
let contentType = 'application/x-www-form-urlencoded'
|
|
156
150
|
const tmpObj: KV<any> = {
|
|
157
151
|
action,
|
|
158
|
-
// webDeviceId,
|
|
159
152
|
dataVersion: DATA_VERSION,
|
|
160
153
|
env: this.config.env,
|
|
161
|
-
...params
|
|
162
|
-
}
|
|
154
|
+
...params,
|
|
155
|
+
}
|
|
163
156
|
|
|
164
157
|
if (ACTIONS_WITHOUT_ACCESSTOKEN.indexOf(action) === -1) {
|
|
165
158
|
const app = this.config._fromApp
|
|
166
159
|
|
|
167
160
|
if (!app.oauthInstance) {
|
|
168
|
-
throw new Error(
|
|
161
|
+
throw new Error('you can\'t request without auth')
|
|
169
162
|
}
|
|
170
163
|
|
|
171
|
-
const oauthInstance = app
|
|
164
|
+
const { oauthInstance } = app
|
|
172
165
|
const oauthClient = oauthInstance.oauth2client
|
|
173
166
|
tmpObj.access_token = (await this.getOauthAccessTokenV2(oauthClient)).accessToken
|
|
174
167
|
}
|
|
175
168
|
|
|
176
169
|
// 拼body和content-type
|
|
177
|
-
let payload
|
|
170
|
+
let payload
|
|
178
171
|
if (action === 'storage.uploadFile') {
|
|
179
|
-
payload = new FormData()
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
payload.append(key, tmpObj[key])
|
|
172
|
+
payload = new FormData()
|
|
173
|
+
Object.keys(payload).forEach((key) => {
|
|
174
|
+
if (Object.prototype.hasOwnProperty.call(payload, key) && payload[key] !== undefined) {
|
|
175
|
+
payload.append(key, tmpObj[key])
|
|
183
176
|
}
|
|
184
|
-
}
|
|
185
|
-
contentType = 'multipart/form-data'
|
|
177
|
+
})
|
|
178
|
+
contentType = 'multipart/form-data'
|
|
186
179
|
} else {
|
|
187
|
-
contentType = 'application/json;charset=UTF-8'
|
|
188
|
-
payload = {}
|
|
189
|
-
|
|
180
|
+
contentType = 'application/json;charset=UTF-8'
|
|
181
|
+
payload = {}
|
|
182
|
+
Object.keys(tmpObj).forEach((key) => {
|
|
190
183
|
if (tmpObj[key] !== undefined) {
|
|
191
|
-
payload[key] = tmpObj[key]
|
|
184
|
+
payload[key] = tmpObj[key]
|
|
192
185
|
}
|
|
193
|
-
}
|
|
186
|
+
})
|
|
194
187
|
}
|
|
195
|
-
|
|
188
|
+
const opts: any = {
|
|
196
189
|
headers: {
|
|
197
|
-
'content-type': contentType
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (options?.
|
|
201
|
-
opts.onUploadProgress = options
|
|
190
|
+
'content-type': contentType,
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
if (options?.onUploadProgress) {
|
|
194
|
+
opts.onUploadProgress = options.onUploadProgress
|
|
202
195
|
}
|
|
203
196
|
|
|
204
197
|
if (this.config.region) {
|
|
205
|
-
opts.headers['X-TCB-Region'] = this.config.region
|
|
198
|
+
opts.headers['X-TCB-Region'] = this.config.region
|
|
206
199
|
}
|
|
207
200
|
|
|
208
|
-
const traceHeader = this.
|
|
201
|
+
const traceHeader = this.localCache.getStore(tcbTraceKey)
|
|
209
202
|
if (traceHeader) {
|
|
210
|
-
opts.headers['X-TCB-Trace'] = traceHeader
|
|
203
|
+
opts.headers['X-TCB-Trace'] = traceHeader
|
|
211
204
|
}
|
|
212
205
|
// 非web平台使用凭证检验有效性
|
|
213
206
|
if (Platform.runtime !== RUNTIME.WEB) {
|
|
214
|
-
const { appSign, appSecret } = this.config
|
|
215
|
-
const timestamp = Date.now()
|
|
216
|
-
const { appAccessKey, appAccessKeyId } = appSecret
|
|
207
|
+
const { appSign, appSecret } = this.config
|
|
208
|
+
const timestamp = Date.now()
|
|
209
|
+
const { appAccessKey, appAccessKeyId } = appSecret
|
|
217
210
|
const sign = createSign({
|
|
218
211
|
data: {}, // 校验签名流程实际未用到,可设空
|
|
219
212
|
timestamp,
|
|
220
213
|
appAccessKeyId,
|
|
221
|
-
appSign
|
|
222
|
-
}, appAccessKey)
|
|
214
|
+
appSign,
|
|
215
|
+
}, appAccessKey)
|
|
223
216
|
|
|
224
|
-
opts.headers['X-TCB-App-Source'] = `timestamp=${timestamp};appAccessKeyId=${appAccessKeyId};appSign=${appSign};sign=${sign}
|
|
217
|
+
opts.headers['X-TCB-App-Source'] = `timestamp=${timestamp};appAccessKeyId=${appAccessKeyId};appSign=${appSign};sign=${sign}`
|
|
225
218
|
}
|
|
226
219
|
|
|
227
220
|
// 发出请求
|
|
228
221
|
// 新的 url 需要携带 env 参数进行 CORS 校验
|
|
229
222
|
// 请求链接支持添加动态 query 参数,方便用户调试定位请求
|
|
230
|
-
const { parse, inQuery, search } = params
|
|
223
|
+
const { parse, inQuery, search } = params
|
|
231
224
|
let formatQuery: Record<string, any> = {
|
|
232
|
-
env: this.config.env
|
|
233
|
-
}
|
|
225
|
+
env: this.config.env,
|
|
226
|
+
}
|
|
234
227
|
// 尝试解析响应数据为 JSON
|
|
235
|
-
parse && (formatQuery.parse = true)
|
|
228
|
+
parse && (formatQuery.parse = true)
|
|
236
229
|
inQuery && (formatQuery = {
|
|
237
230
|
...inQuery,
|
|
238
|
-
...formatQuery
|
|
239
|
-
})
|
|
240
|
-
const { BASE_URL, PROTOCOL } = getEndPoint()
|
|
231
|
+
...formatQuery,
|
|
232
|
+
})
|
|
233
|
+
const { BASE_URL, PROTOCOL } = getEndPoint()
|
|
241
234
|
// 生成请求 url
|
|
242
|
-
let newUrl = formatUrl(PROTOCOL, BASE_URL, formatQuery)
|
|
235
|
+
let newUrl = formatUrl(PROTOCOL, BASE_URL, formatQuery)
|
|
243
236
|
|
|
244
237
|
if (search) {
|
|
245
|
-
newUrl += search
|
|
238
|
+
newUrl += search
|
|
246
239
|
}
|
|
247
240
|
|
|
248
241
|
const res: ResponseObject = await this.post({
|
|
249
242
|
url: newUrl,
|
|
250
243
|
data: payload,
|
|
251
|
-
...opts
|
|
252
|
-
})
|
|
244
|
+
...opts,
|
|
245
|
+
})
|
|
253
246
|
|
|
254
247
|
// 保存 trace header
|
|
255
|
-
const resTraceHeader = res.header
|
|
248
|
+
const resTraceHeader = res.header?.['x-tcb-trace']
|
|
256
249
|
if (resTraceHeader) {
|
|
257
|
-
this.
|
|
250
|
+
this.localCache.setStore(tcbTraceKey, resTraceHeader)
|
|
258
251
|
}
|
|
259
252
|
|
|
260
253
|
if ((Number(res.status) !== 200 && Number(res.statusCode) !== 200) || !res.data) {
|
|
261
|
-
throw new Error('network request error')
|
|
254
|
+
throw new Error('network request error')
|
|
262
255
|
}
|
|
263
256
|
|
|
264
|
-
return res
|
|
257
|
+
return res
|
|
265
258
|
}
|
|
266
259
|
|
|
267
260
|
public async send(action: string, data: KV<any> = {}): Promise<any> {
|
|
268
|
-
|
|
261
|
+
const response = await this.request(action, data, { onUploadProgress: data.onUploadProgress })
|
|
269
262
|
|
|
270
|
-
if (response.data.code && this.
|
|
263
|
+
if (response.data.code && this.throwWhenRequestFail) {
|
|
271
264
|
throw new Error(JSON.stringify({
|
|
272
265
|
code: ERRORS.OPERATION_FAIL,
|
|
273
|
-
msg: `[${response.data.code}] ${response.data.message}
|
|
274
|
-
}))
|
|
266
|
+
msg: `[${response.data.code}] ${response.data.message}`,
|
|
267
|
+
}))
|
|
275
268
|
}
|
|
276
269
|
|
|
277
|
-
return response.data
|
|
270
|
+
return response.data
|
|
278
271
|
}
|
|
279
272
|
}
|
|
280
273
|
|
|
281
|
-
const requestMap: KV<CloudbaseRequest> = {}
|
|
274
|
+
const requestMap: KV<CloudbaseRequest> = {}
|
|
282
275
|
|
|
283
276
|
export function initRequest(config: ICloudbaseRequestConfig) {
|
|
284
277
|
requestMap[config.env] = new CloudbaseRequest({
|
|
285
278
|
...config,
|
|
286
|
-
throw: true
|
|
287
|
-
})
|
|
279
|
+
throw: true,
|
|
280
|
+
})
|
|
288
281
|
}
|
|
289
282
|
|
|
290
283
|
export function getRequestByEnvId(env: string): CloudbaseRequest {
|
|
291
|
-
return requestMap[env]
|
|
292
|
-
}
|
|
284
|
+
return requestMap[env]
|
|
285
|
+
}
|
package/.eslintrc
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": [
|
|
3
|
-
"eslint-config-alloy/typescript"
|
|
4
|
-
],
|
|
5
|
-
"rules": {
|
|
6
|
-
"indent": [
|
|
7
|
-
"error",
|
|
8
|
-
2,
|
|
9
|
-
{
|
|
10
|
-
"SwitchCase": 1,
|
|
11
|
-
"flatTernaryExpressions": true
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"guard-for-in": 0,
|
|
15
|
-
"no-param-reassign": 0,
|
|
16
|
-
"no-undefined": 0,
|
|
17
|
-
"@typescript-eslint/explicit-member-accessibility": 0,
|
|
18
|
-
"@typescript-eslint/consistent-type-assertions": 0,
|
|
19
|
-
"@typescript-eslint/no-loss-of-precision": 0,
|
|
20
|
-
"@typescript-eslint/no-duplicate-imports": 0
|
|
21
|
-
},
|
|
22
|
-
"parserOptions": {
|
|
23
|
-
"ecmaVersion": 6,
|
|
24
|
-
"sourceType": "module",
|
|
25
|
-
"ecmaFeatures": {
|
|
26
|
-
"modules": true
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|