@cloudbase/app 1.5.1-alpha.0 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/constants/common.d.ts +1 -0
- package/dist/cjs/constants/common.js +8 -2
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +6 -5
- package/dist/cjs/libs/cache.js +4 -22
- package/dist/cjs/libs/request.d.ts +2 -14
- package/dist/cjs/libs/request.js +19 -442
- package/dist/esm/constants/common.d.ts +1 -0
- package/dist/esm/constants/common.js +6 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +5 -5
- package/dist/esm/libs/cache.js +4 -22
- package/dist/esm/libs/request.d.ts +2 -14
- package/dist/esm/libs/request.js +22 -445
- package/package.json +4 -4
- package/src/constants/common.ts +17 -10
- package/src/index.ts +7 -4
- package/src/libs/cache.ts +22 -23
- package/src/libs/request.ts +16 -352
- package/dist/cjs/constants/events.d.ts +0 -7
- package/dist/cjs/constants/events.js +0 -11
- package/dist/esm/constants/events.d.ts +0 -7
- package/dist/esm/constants/events.js +0 -8
- package/src/constants/events.ts +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
4
|
"description": "cloudbase javascript sdk core",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"license": "ISC",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@cloudbase/adapter-interface": "^0.4.0",
|
|
31
|
-
"@cloudbase/types": "^
|
|
32
|
-
"@cloudbase/utilities": "^
|
|
31
|
+
"@cloudbase/types": "^2.0.0-alpha.0",
|
|
32
|
+
"@cloudbase/utilities": "^2.0.0-alpha.0",
|
|
33
33
|
"cloudbase-adapter-wx_mp": "0.2.0",
|
|
34
34
|
"uuid": "^8.3.2"
|
|
35
35
|
},
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"eslint --fix"
|
|
54
54
|
]
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "4568e598d198896703ac0e204b3211c14bc79861"
|
|
57
57
|
}
|
package/src/constants/common.ts
CHANGED
|
@@ -8,46 +8,53 @@ const { setSdkName: setUtilitiesSdkName, setProtocol: setUtilitiesProtocol } = c
|
|
|
8
8
|
let sdk_version = '';
|
|
9
9
|
let sdk_name = '@cloudbase/js-sdk';
|
|
10
10
|
|
|
11
|
-
export function setSdkVersion(version:string){
|
|
11
|
+
export function setSdkVersion(version: string) {
|
|
12
12
|
sdk_version = version;
|
|
13
13
|
}
|
|
14
|
-
export function getSdkVersion(){
|
|
14
|
+
export function getSdkVersion() {
|
|
15
15
|
return sdk_version;
|
|
16
16
|
}
|
|
17
|
-
export function setSdkName(name:string){
|
|
17
|
+
export function setSdkName(name: string) {
|
|
18
18
|
sdk_name = name;
|
|
19
19
|
setUtilitiesSdkName(name);
|
|
20
20
|
}
|
|
21
|
-
export function getSdkName(){
|
|
21
|
+
export function getSdkName() {
|
|
22
22
|
return sdk_name;
|
|
23
23
|
}
|
|
24
24
|
export const DATA_VERSION = '2020-01-10';
|
|
25
25
|
/**
|
|
26
26
|
* request
|
|
27
27
|
*/
|
|
28
|
-
let PROTOCOL = typeof location !== 'undefined' && location.protocol === 'http:'
|
|
29
|
-
? 'http:'
|
|
28
|
+
let PROTOCOL = typeof location !== 'undefined' && location.protocol === 'http:'
|
|
29
|
+
? 'http:'
|
|
30
30
|
: 'https:';
|
|
31
31
|
let BASE_URL = typeof process !== 'undefined' && process.env.NODE_ENV === 'e2e' && process.env.END_POINT === 'pre'
|
|
32
32
|
? '//tcb-pre.tencentcloudapi.com/web'
|
|
33
33
|
: '//tcb-api.tencentcloudapi.com/web';
|
|
34
|
-
export function setEndPoint(url:string,protocol?:'http'|'https'){
|
|
34
|
+
export function setEndPoint(url: string, protocol?: 'http' | 'https') {
|
|
35
35
|
BASE_URL = url;
|
|
36
|
-
if(protocol){
|
|
36
|
+
if (protocol) {
|
|
37
37
|
PROTOCOL = protocol;
|
|
38
38
|
setUtilitiesProtocol(protocol);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
export function setRegionLevelEndpoint(env:string,region:string,protocol?:'http'|'https') {
|
|
41
|
+
export function setRegionLevelEndpoint(env: string, region: string, protocol?: 'http' | 'https') {
|
|
42
42
|
const endpoiont = region
|
|
43
43
|
? `//${env}.${region}.tcb-api.tencentcloudapi.com/web`
|
|
44
44
|
: `//${env}.ap-shanghai.tcb-api.tencentcloudapi.com/web`
|
|
45
45
|
setEndPoint(endpoiont, protocol)
|
|
46
46
|
}
|
|
47
|
-
export function getEndPoint(){
|
|
47
|
+
export function getEndPoint() {
|
|
48
48
|
return { BASE_URL, PROTOCOL };
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
|
|
52
|
+
export function getBaseEndPoint() {
|
|
53
|
+
const { PROTOCOL, BASE_URL } = getEndPoint()
|
|
54
|
+
const webEndpoint = `${PROTOCOL}${BASE_URL}`
|
|
55
|
+
return `${new URL(webEndpoint).origin}`
|
|
56
|
+
}
|
|
57
|
+
|
|
51
58
|
export enum LOGINTYPE {
|
|
52
59
|
NULL = 'NULL',
|
|
53
60
|
ANONYMOUS = 'ANONYMOUS',
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { initCache, getCacheByEnvId, getLocalCache } from './libs/cache';
|
|
|
11
11
|
import { ICloudbaseRequest } from '@cloudbase/types/request';
|
|
12
12
|
import { initRequest, getRequestByEnvId } from './libs/request';
|
|
13
13
|
import { getSdkName, setSdkVersion, setEndPoint, setRegionLevelEndpoint, setSdkName } from './constants/common';
|
|
14
|
+
export { getBaseEndPoint } from './constants/common'
|
|
14
15
|
const { useAdapters, useDefaultAdapter, RUNTIME } = adapters;
|
|
15
16
|
const { ERRORS, COMMUNITY_SITE_URL } = constants;
|
|
16
17
|
const { printWarn } = utils;
|
|
@@ -33,6 +34,7 @@ const extensionMap: KV<ICloudbaseExtension> = {};
|
|
|
33
34
|
|
|
34
35
|
class Cloudbase implements ICloudbase {
|
|
35
36
|
public authInstance: ICloudbaseAuth;
|
|
37
|
+
public oauthInstance: any;
|
|
36
38
|
public requestClient: any;
|
|
37
39
|
public oauthClient: any
|
|
38
40
|
private _config: ICloudbaseConfig;
|
|
@@ -40,6 +42,7 @@ class Cloudbase implements ICloudbase {
|
|
|
40
42
|
constructor(config?: ICloudbaseConfig) {
|
|
41
43
|
this._config = config ? config : this._config;
|
|
42
44
|
this.authInstance = null;
|
|
45
|
+
this.oauthInstance = null
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
get config() {
|
|
@@ -122,12 +125,12 @@ class Cloudbase implements ICloudbase {
|
|
|
122
125
|
// 初始化cache和request
|
|
123
126
|
const { env, persistence, debug, timeout, appSecret, appSign, oauthClient } = this._config;
|
|
124
127
|
initCache({ env, persistence, debug, platformInfo: this.platform });
|
|
125
|
-
initRequest({ env, region: config.region || '', timeout, appSecret, appSign, oauthClient });
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
|
|
130
|
+
setRegionLevelEndpoint(env, config.region || '')
|
|
131
|
+
|
|
130
132
|
const app = new Cloudbase(this._config);
|
|
133
|
+
initRequest({ env, region: config.region || '', timeout, appSecret, appSign, oauthClient, _fromApp: app });
|
|
131
134
|
app.requestClient = this.requestClient;
|
|
132
135
|
return app;
|
|
133
136
|
}
|
package/src/libs/cache.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { KV } from "@cloudbase/types";
|
|
|
2
2
|
import { cache } from "@cloudbase/utilities";
|
|
3
3
|
import { ICloudbaseCache, ICacheConfig } from "@cloudbase/types/cache";
|
|
4
4
|
|
|
5
|
-
const KEY_ACCESS_TOKEN = 'access_token';
|
|
6
|
-
const KEY_ACCESS_TOKEN_EXPIRE = 'access_token_expire';
|
|
7
|
-
const KEY_REFRESH_TOKEN = 'refresh_token';
|
|
8
|
-
const KEY_ANONYMOUS_UUID = 'anonymous_uuid';
|
|
9
|
-
const KEY_LOGIN_TYPE = 'login_type';
|
|
10
5
|
const USER_INFO_KEY = 'user_info';
|
|
11
|
-
const
|
|
6
|
+
// const KEY_ACCESS_TOKEN = 'access_token';
|
|
7
|
+
// const KEY_ACCESS_TOKEN_EXPIRE = 'access_token_expire';
|
|
8
|
+
// const KEY_REFRESH_TOKEN = 'refresh_token';
|
|
9
|
+
// const KEY_ANONYMOUS_UUID = 'anonymous_uuid';
|
|
10
|
+
// const KEY_LOGIN_TYPE = 'login_type';
|
|
11
|
+
// const DEVICE_INFO = 'device_id';
|
|
12
12
|
|
|
13
13
|
const { CloudbaseCache } = cache;
|
|
14
14
|
|
|
@@ -16,32 +16,31 @@ const cacheMap: KV<ICloudbaseCache> = {};
|
|
|
16
16
|
// 本地存储
|
|
17
17
|
const localCacheMap: KV<ICloudbaseCache> = {};
|
|
18
18
|
|
|
19
|
-
export function initCache(config: ICacheConfig&{env:string}) {
|
|
20
|
-
const { env,
|
|
19
|
+
export function initCache(config: ICacheConfig & { env: string }) {
|
|
20
|
+
const { env, platformInfo } = config;
|
|
21
21
|
|
|
22
|
-
const accessTokenKey
|
|
23
|
-
const accessTokenExpireKey = `${KEY_ACCESS_TOKEN_EXPIRE}_${env}`;
|
|
24
|
-
const refreshTokenKey = `${KEY_REFRESH_TOKEN}_${env}`;
|
|
25
|
-
const anonymousUuidKey = `${KEY_ANONYMOUS_UUID}_${env}`;
|
|
26
|
-
const loginTypeKey = `${KEY_LOGIN_TYPE}_${env}`;
|
|
27
|
-
const userInfoKey
|
|
28
|
-
const deviceIdKey
|
|
22
|
+
// const accessTokenKey = `${KEY_ACCESS_TOKEN}_${env}`;
|
|
23
|
+
// const accessTokenExpireKey = `${KEY_ACCESS_TOKEN_EXPIRE}_${env}`;
|
|
24
|
+
// const refreshTokenKey = `${KEY_REFRESH_TOKEN}_${env}`;
|
|
25
|
+
// const anonymousUuidKey = `${KEY_ANONYMOUS_UUID}_${env}`;
|
|
26
|
+
// const loginTypeKey = `${KEY_LOGIN_TYPE}_${env}`;
|
|
27
|
+
const userInfoKey = `${USER_INFO_KEY}_${env}`;
|
|
28
|
+
// const deviceIdKey = `${DEVICE_INFO}`; // 非环境级别
|
|
29
29
|
|
|
30
30
|
const keys = {
|
|
31
|
-
accessTokenKey,
|
|
32
|
-
accessTokenExpireKey,
|
|
33
|
-
refreshTokenKey,
|
|
34
|
-
anonymousUuidKey,
|
|
35
|
-
loginTypeKey,
|
|
36
31
|
userInfoKey,
|
|
37
|
-
|
|
32
|
+
// accessTokenKey,
|
|
33
|
+
// accessTokenExpireKey,
|
|
34
|
+
// refreshTokenKey,
|
|
35
|
+
// anonymousUuidKey,
|
|
36
|
+
// loginTypeKey,
|
|
37
|
+
// deviceIdKey
|
|
38
38
|
};
|
|
39
39
|
// 若指定env已存在cache则尝试更新persistence
|
|
40
|
-
cacheMap[env]
|
|
40
|
+
cacheMap[env] = cacheMap[env] || (new CloudbaseCache({
|
|
41
41
|
...config,
|
|
42
42
|
keys,
|
|
43
43
|
platformInfo,
|
|
44
|
-
alwaysLocalKeys: ['anonymousUuidKey']
|
|
45
44
|
}));
|
|
46
45
|
localCacheMap[env] = localCacheMap[env] || new CloudbaseCache({
|
|
47
46
|
...config,
|
package/src/libs/request.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DATA_VERSION,
|
|
3
|
-
LOGINTYPE,
|
|
4
3
|
getSdkVersion,
|
|
5
4
|
getEndPoint,
|
|
6
|
-
|
|
5
|
+
getBaseEndPoint
|
|
7
6
|
} from '../constants/common';
|
|
8
7
|
import {
|
|
9
8
|
IRequestOptions,
|
|
@@ -12,20 +11,16 @@ import {
|
|
|
12
11
|
IUploadRequestOptions,
|
|
13
12
|
IRequestConfig
|
|
14
13
|
} from '@cloudbase/adapter-interface';
|
|
15
|
-
import { utils,
|
|
14
|
+
import { utils, adapters, constants } from '@cloudbase/utilities';
|
|
16
15
|
import { KV } from '@cloudbase/types';
|
|
17
16
|
import { IGetAccessTokenResult, ICloudbaseRequestConfig, IAppendedRequestInfo, IRequestBeforeHook } from '@cloudbase/types/request';
|
|
18
17
|
import { ICloudbaseCache } from '@cloudbase/types/cache';
|
|
19
|
-
import {
|
|
20
|
-
import { getCacheByEnvId, getLocalCache } from './cache';
|
|
21
|
-
import { EVENTS } from '../constants/events';
|
|
18
|
+
import { getLocalCache } from './cache';
|
|
22
19
|
import { Platform } from './adapter';
|
|
23
|
-
const {
|
|
20
|
+
const { ERRORS } = constants;
|
|
24
21
|
const { genSeqId, isFormData, formatUrl, createSign } = utils;
|
|
25
22
|
const { RUNTIME } = adapters;
|
|
26
23
|
|
|
27
|
-
import { v4 as uuidv4 } from 'uuid'
|
|
28
|
-
|
|
29
24
|
// import FingerprintJS from '@fingerprintjs/fingerprintjs'
|
|
30
25
|
// const fpPromise = FingerprintJS.load()
|
|
31
26
|
|
|
@@ -87,12 +82,9 @@ function beforeEach(): IAppendedRequestInfo {
|
|
|
87
82
|
};
|
|
88
83
|
}
|
|
89
84
|
export interface ICloudbaseRequest {
|
|
90
|
-
fetch: (urlOrPath: string, init?: RequestInit) => Promise<Response>;
|
|
91
85
|
post: (options: IRequestOptions) => Promise<ResponseObject>;
|
|
92
86
|
upload: (options: IUploadRequestOptions) => Promise<ResponseObject>;
|
|
93
87
|
download: (options: IRequestOptions) => Promise<ResponseObject>;
|
|
94
|
-
refreshAccessToken: () => Promise<IGetAccessTokenResult>;
|
|
95
|
-
getAccessToken: () => Promise<IGetAccessTokenResult>;
|
|
96
88
|
request: (action: string, params: KV<any>, options?: KV<any>) => Promise<ResponseObject>;
|
|
97
89
|
send: (action: string, data: KV<any>) => Promise<any>;
|
|
98
90
|
}
|
|
@@ -107,7 +99,6 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
107
99
|
_reqClass: SDKRequestInterface;
|
|
108
100
|
// 请求失败是否抛出Error
|
|
109
101
|
private _throwWhenRequestFail = false;
|
|
110
|
-
private _cache: ICloudbaseCache;
|
|
111
102
|
// 持久化本地存储
|
|
112
103
|
private _localCache: ICloudbaseCache;
|
|
113
104
|
/**
|
|
@@ -115,6 +106,7 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
115
106
|
* @param config
|
|
116
107
|
*/
|
|
117
108
|
constructor(config: ICloudbaseRequestConfig & { throw?: boolean }) {
|
|
109
|
+
|
|
118
110
|
this.config = config;
|
|
119
111
|
// eslint-disable-next-line
|
|
120
112
|
this._reqClass = new Platform.adapter.reqClass(<IRequestConfig>{
|
|
@@ -123,55 +115,12 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
123
115
|
restrictedMethods: ['post']
|
|
124
116
|
});
|
|
125
117
|
this._throwWhenRequestFail = config.throw || false;
|
|
126
|
-
this._cache = getCacheByEnvId(this.config.env);
|
|
127
118
|
this._localCache = getLocalCache(this.config.env);
|
|
128
119
|
bindHooks(this._reqClass, 'post', [beforeEach]);
|
|
129
120
|
bindHooks(this._reqClass, 'upload', [beforeEach]);
|
|
130
121
|
bindHooks(this._reqClass, 'download', [beforeEach]);
|
|
131
122
|
}
|
|
132
123
|
|
|
133
|
-
/**
|
|
134
|
-
* 套一层 fetch,方便处理请求地址
|
|
135
|
-
* @param {string} urlOrPath
|
|
136
|
-
* @param {RequestInit} init
|
|
137
|
-
* @returns
|
|
138
|
-
*/
|
|
139
|
-
public async fetch(urlOrPath: string, init?: RequestInit): Promise<Response> {
|
|
140
|
-
const deviceId = await this.getDeviceId();
|
|
141
|
-
|
|
142
|
-
const headers = {
|
|
143
|
-
'X-Project-Id': this.config.env,
|
|
144
|
-
'X-SDK-Version': `@cloudbase/js-sdk/${getSdkVersion()}`,
|
|
145
|
-
'X-Request-Id': genSeqId(),
|
|
146
|
-
'X-Request-Timestamp': Date.now(),
|
|
147
|
-
'X-Device-Id': deviceId
|
|
148
|
-
}
|
|
149
|
-
// 非web平台使用凭证检验有效性
|
|
150
|
-
if (Platform.runtime !== RUNTIME.WEB) {
|
|
151
|
-
const { appSign, appSecret } = this.config
|
|
152
|
-
const timestamp = Date.now()
|
|
153
|
-
const { appAccessKey, appAccessKeyId } = appSecret
|
|
154
|
-
const sign = createSign({
|
|
155
|
-
// data: init.body,
|
|
156
|
-
data: {},
|
|
157
|
-
timestamp,
|
|
158
|
-
appAccessKeyId,
|
|
159
|
-
appSign
|
|
160
|
-
}, appAccessKey)
|
|
161
|
-
|
|
162
|
-
headers['X-TCB-App-Source'] = `timestamp=${timestamp};appAccessKeyId=${appAccessKeyId};appSign=${appSign};sign=${sign}`
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
init.headers = Object.assign({}, init.headers, headers)
|
|
166
|
-
|
|
167
|
-
const { PROTOCOL, BASE_URL } = getEndPoint()
|
|
168
|
-
const webEndpoint = `${PROTOCOL}${BASE_URL}`
|
|
169
|
-
const url = urlOrPath.startsWith('http')
|
|
170
|
-
? urlOrPath
|
|
171
|
-
: `${new URL(webEndpoint).origin}${urlOrPath}`
|
|
172
|
-
return await fetch(url, init)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
124
|
public async post(options: IRequestOptions): Promise<ResponseObject> {
|
|
176
125
|
const res = await this._reqClass.post(options);
|
|
177
126
|
return res;
|
|
@@ -185,123 +134,22 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
185
134
|
return res;
|
|
186
135
|
}
|
|
187
136
|
|
|
188
|
-
public
|
|
189
|
-
|
|
190
|
-
if (!this._refreshAccessTokenPromise) {
|
|
191
|
-
// 没有正在刷新,那么正常执行刷新逻辑
|
|
192
|
-
this._refreshAccessTokenPromise = this._refreshAccessToken();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
let result;
|
|
196
|
-
let err;
|
|
197
|
-
try {
|
|
198
|
-
result = await this._refreshAccessTokenPromise;
|
|
199
|
-
} catch (e) {
|
|
200
|
-
err = e;
|
|
201
|
-
}
|
|
202
|
-
this._refreshAccessTokenPromise = null;
|
|
203
|
-
this._shouldRefreshAccessTokenHook = null;
|
|
204
|
-
if (err) {
|
|
205
|
-
throw err;
|
|
206
|
-
}
|
|
207
|
-
return result;
|
|
137
|
+
public getBaseEndPoint() {
|
|
138
|
+
return getBaseEndPoint()
|
|
208
139
|
}
|
|
209
140
|
|
|
210
|
-
public async
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
141
|
+
public async getOauthAccessTokenV2(oauthClient: any): Promise<IGetAccessTokenResult> {
|
|
142
|
+
const validAccessToken = await oauthClient.getAccessToken()
|
|
143
|
+
const credentials = await oauthClient._getCredentials()
|
|
144
|
+
return {
|
|
145
|
+
accessToken: validAccessToken,
|
|
146
|
+
accessTokenExpire: new Date(credentials.expires_at).getTime()
|
|
215
147
|
}
|
|
216
|
-
|
|
217
|
-
let result;
|
|
218
|
-
let err;
|
|
219
|
-
try {
|
|
220
|
-
result = await this._refreshAccessTokenPromise;
|
|
221
|
-
} catch (e) {
|
|
222
|
-
err = e;
|
|
223
|
-
}
|
|
224
|
-
this._refreshAccessTokenPromise = null;
|
|
225
|
-
this._shouldRefreshAccessTokenHook = null;
|
|
226
|
-
if (err) {
|
|
227
|
-
throw err;
|
|
228
|
-
}
|
|
229
|
-
return result;
|
|
230
148
|
}
|
|
231
149
|
|
|
232
|
-
// 获取 OAuth accesstoken
|
|
233
|
-
public async getOauthAccessToken(): Promise<IGetAccessTokenResult> {
|
|
234
|
-
const { oauthClient } = this.config
|
|
235
|
-
if (oauthClient) {
|
|
236
|
-
const validAccessToken = await oauthClient.getAccessToken()
|
|
237
|
-
const credentials = await oauthClient._getCredentials()
|
|
238
|
-
return {
|
|
239
|
-
accessToken: validAccessToken,
|
|
240
|
-
accessTokenExpire: new Date(credentials.expires_at).getTime()
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// 获取 access token
|
|
246
|
-
public async getAccessToken(): Promise<IGetAccessTokenResult> {
|
|
247
|
-
const { loginTypeKey, accessTokenKey, accessTokenExpireKey, refreshTokenKey } = this._cache.keys;
|
|
248
|
-
const loginType = await this._cache.getStoreAsync(loginTypeKey);
|
|
249
|
-
const refreshToken = await this._cache.getStoreAsync(refreshTokenKey);
|
|
250
|
-
if (!refreshToken) {
|
|
251
|
-
// 不该出现的状态:有 access token 却没有 refresh token
|
|
252
|
-
throw new Error(JSON.stringify({
|
|
253
|
-
code: ERRORS.OPERATION_FAIL,
|
|
254
|
-
msg: 'refresh token is not exist, your local data might be messed up, please retry after clear localStorage or sessionStorage'
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
|
-
// 如果没有access token或者过期,那么刷新
|
|
258
|
-
const accessToken = await this._cache.getStoreAsync(accessTokenKey);
|
|
259
|
-
const accessTokenExpire = Number(await this._cache.getStoreAsync(accessTokenExpireKey));
|
|
260
|
-
|
|
261
|
-
// 调用钩子函数
|
|
262
|
-
let shouldRefreshAccessToken = true;
|
|
263
|
-
if (this._shouldRefreshAccessTokenHook && !(await this._shouldRefreshAccessTokenHook(accessToken, accessTokenExpire))) {
|
|
264
|
-
shouldRefreshAccessToken = false;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if ((!accessToken || !accessTokenExpire || accessTokenExpire < Date.now()) && shouldRefreshAccessToken) {
|
|
268
|
-
if (loginType.startsWith(OAUTH2_LOGINTYPE_PREFIX)) {
|
|
269
|
-
// NOTE: 这里需要从 accessToken 解出来部分信息,用于刷新 accessToken
|
|
270
|
-
// 所以过期的 accessToken 不能删除,而是用新 accessToken 覆盖
|
|
271
|
-
if (accessToken) {
|
|
272
|
-
let header = null
|
|
273
|
-
let payload = null
|
|
274
|
-
try {
|
|
275
|
-
header = jwt.decode(accessToken, { header: true })
|
|
276
|
-
payload = jwt.decode(accessToken)
|
|
277
|
-
}
|
|
278
|
-
catch (e) {
|
|
279
|
-
throw new Error(`[DECODE_ACCESS_TOKEN_ERROR] ${e.message}, accesstoken: ${accessToken}`)
|
|
280
|
-
}
|
|
281
|
-
if (header?.kid && payload?.project_id) {
|
|
282
|
-
return await this.refreshAccessTokenFromOauthServer(payload?.project_id)
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
// 这里用 env 试一下
|
|
287
|
-
return await this.refreshAccessTokenFromOauthServer(this.config.env)
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
return await this.refreshAccessToken();
|
|
292
|
-
}
|
|
293
|
-
} else {
|
|
294
|
-
// 返回本地的access token
|
|
295
|
-
return {
|
|
296
|
-
accessToken,
|
|
297
|
-
accessTokenExpire
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
150
|
|
|
302
151
|
/* eslint-disable complexity */
|
|
303
152
|
public async request(action: string, params: KV<any>, options?: KV<any>): Promise<ResponseObject> {
|
|
304
|
-
const { oauthClient } = this.config
|
|
305
153
|
const tcbTraceKey = `x-tcb-trace_${this.config.env}`;
|
|
306
154
|
let contentType = 'application/x-www-form-urlencoded';
|
|
307
155
|
// const webDeviceId = await getTcbFingerprintId();
|
|
@@ -313,19 +161,10 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
313
161
|
...params
|
|
314
162
|
};
|
|
315
163
|
|
|
316
|
-
// 若识别到注册了 Oauth 模块,则使用oauth getAccessToken
|
|
317
|
-
if (oauthClient) {
|
|
318
|
-
tmpObj.access_token = (await this.getOauthAccessToken()).accessToken
|
|
319
|
-
}
|
|
320
|
-
|
|
321
164
|
if (ACTIONS_WITHOUT_ACCESSTOKEN.indexOf(action) === -1) {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const refreshToken = await this._cache.getStoreAsync(refreshTokenKey);
|
|
326
|
-
if (refreshToken) {
|
|
327
|
-
tmpObj.access_token = (await this.getAccessToken()).accessToken;
|
|
328
|
-
}
|
|
165
|
+
const app = this.config._fromApp
|
|
166
|
+
const oauthClient = app.oauthInstance.oauth2client
|
|
167
|
+
tmpObj.access_token = (await this.getOauthAccessTokenV2(oauthClient)).accessToken
|
|
329
168
|
}
|
|
330
169
|
|
|
331
170
|
// 拼body和content-type
|
|
@@ -421,11 +260,6 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
421
260
|
|
|
422
261
|
public async send(action: string, data: KV<any> = {}): Promise<any> {
|
|
423
262
|
let response = await this.request(action, data, { onUploadProgress: data.onUploadProgress });
|
|
424
|
-
if (response.data.code === 'ACCESS_TOKEN_EXPIRED' && ACTIONS_WITHOUT_ACCESSTOKEN.indexOf(action) === -1) {
|
|
425
|
-
// access_token过期,重新获取
|
|
426
|
-
await this.refreshAccessToken();
|
|
427
|
-
response = await this.request(action, data, { onUploadProgress: data.onUploadProgress });
|
|
428
|
-
}
|
|
429
263
|
|
|
430
264
|
if (response.data.code && this._throwWhenRequestFail) {
|
|
431
265
|
throw new Error(JSON.stringify({
|
|
@@ -436,176 +270,6 @@ export class CloudbaseRequest implements ICloudbaseRequest {
|
|
|
436
270
|
|
|
437
271
|
return response.data;
|
|
438
272
|
}
|
|
439
|
-
|
|
440
|
-
// 调用接口刷新access token,并且返回
|
|
441
|
-
private async _refreshAccessToken(retryNum = 1): Promise<IGetAccessTokenResult> {
|
|
442
|
-
const { accessTokenKey, accessTokenExpireKey, refreshTokenKey, loginTypeKey, anonymousUuidKey } = this._cache.keys;
|
|
443
|
-
await this._cache.removeStoreAsync(accessTokenKey);
|
|
444
|
-
await this._cache.removeStoreAsync(accessTokenExpireKey);
|
|
445
|
-
|
|
446
|
-
let refreshToken = await this._cache.getStoreAsync(refreshTokenKey);
|
|
447
|
-
if (!refreshToken) {
|
|
448
|
-
throw new Error(JSON.stringify({
|
|
449
|
-
code: ERRORS.INVALID_OPERATION,
|
|
450
|
-
msg: 'not login'
|
|
451
|
-
}));
|
|
452
|
-
}
|
|
453
|
-
const params: KV<string> = {
|
|
454
|
-
refresh_token: refreshToken
|
|
455
|
-
};
|
|
456
|
-
const response = await this.request('auth.fetchAccessTokenWithRefreshToken', params);
|
|
457
|
-
if (response.data.code) {
|
|
458
|
-
const { code } = response.data;
|
|
459
|
-
if (code === 'SIGN_PARAM_INVALID' || code === 'REFRESH_TOKEN_EXPIRED' || code === 'INVALID_REFRESH_TOKEN') {
|
|
460
|
-
// 这里处理以下逻辑:
|
|
461
|
-
// 匿名登录时,如果刷新access token报错refresh token过期,此时应该:
|
|
462
|
-
// 1. 再用 uuid 拿一次新的refresh token
|
|
463
|
-
// 2. 拿新的refresh token换access token
|
|
464
|
-
const isAnonymous = await this._cache.getStoreAsync(loginTypeKey) === LOGINTYPE.ANONYMOUS;
|
|
465
|
-
if (isAnonymous && code === 'INVALID_REFRESH_TOKEN') {
|
|
466
|
-
// 获取新的 refresh token
|
|
467
|
-
const anonymous_uuid = await this._cache.getStoreAsync(anonymousUuidKey);
|
|
468
|
-
// 此处cache为基类property
|
|
469
|
-
const refresh_token = await this._cache.getStoreAsync(refreshTokenKey);
|
|
470
|
-
const res = await this.send('auth.signInAnonymously', {
|
|
471
|
-
anonymous_uuid,
|
|
472
|
-
refresh_token
|
|
473
|
-
});
|
|
474
|
-
this._setRefreshToken(res.refresh_token);
|
|
475
|
-
if (retryNum >= 1) {
|
|
476
|
-
return this._refreshAccessToken(--retryNum);
|
|
477
|
-
} else {
|
|
478
|
-
throw new Error(
|
|
479
|
-
JSON.stringify({
|
|
480
|
-
code: ERRORS.OPERATION_FAIL,
|
|
481
|
-
message: '重试获取 refresh token 失败'
|
|
482
|
-
})
|
|
483
|
-
)
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
cloudbase.fire(EVENTS.LOGIN_STATE_EXPIRED);
|
|
487
|
-
await this._cache.removeStoreAsync(refreshTokenKey);
|
|
488
|
-
}
|
|
489
|
-
throw new Error(JSON.stringify({
|
|
490
|
-
code: ERRORS.NETWORK_ERROR,
|
|
491
|
-
msg: `refresh access_token failed:${response.data.code}`
|
|
492
|
-
}));
|
|
493
|
-
}
|
|
494
|
-
if (response.data.access_token) {
|
|
495
|
-
cloudbase.fire(EVENTS.ACCESS_TOKEN_REFRESHD);
|
|
496
|
-
await this._cache.setStoreAsync(accessTokenKey, response.data.access_token);
|
|
497
|
-
// 本地时间可能没有同步
|
|
498
|
-
await this._cache.setStoreAsync(accessTokenExpireKey, response.data.access_token_expire + Date.now());
|
|
499
|
-
return {
|
|
500
|
-
accessToken: response.data.access_token,
|
|
501
|
-
accessTokenExpire: response.data.access_token_expire
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
// 匿名登录refresh_token过期情况下返回refresh_token
|
|
505
|
-
// 此场景下使用新的refresh_token获取access_token
|
|
506
|
-
if (response.data.refresh_token) {
|
|
507
|
-
await this._cache.removeStoreAsync(refreshTokenKey);
|
|
508
|
-
await this._cache.setStoreAsync(refreshTokenKey, response.data.refresh_token);
|
|
509
|
-
await this._refreshAccessToken();
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
private async _fetchAccessTokenFromOauthServer(refreshToken: string, clientId: string) {
|
|
514
|
-
const resp = await this.fetch('/auth/v1/token', {
|
|
515
|
-
method: 'POST',
|
|
516
|
-
headers: {
|
|
517
|
-
'Accept': 'application/json',
|
|
518
|
-
'Content-Type': 'application/json'
|
|
519
|
-
},
|
|
520
|
-
body: JSON.stringify({
|
|
521
|
-
grant_type: 'refresh_token',
|
|
522
|
-
client_id: clientId,
|
|
523
|
-
refresh_token: refreshToken
|
|
524
|
-
})
|
|
525
|
-
})
|
|
526
|
-
// Resp:
|
|
527
|
-
// {
|
|
528
|
-
// "token_type": "Bearer",
|
|
529
|
-
// "access_token": "",
|
|
530
|
-
// "refresh_token":"",
|
|
531
|
-
// "expires_in": 259200,
|
|
532
|
-
// "sub": ""
|
|
533
|
-
// }
|
|
534
|
-
// 以下代码重复
|
|
535
|
-
const seqIdFromHeader = resp.headers.get('SeqId') || resp.headers.get('RequestId')
|
|
536
|
-
if (resp.status >= 400 && resp.status < 500) {
|
|
537
|
-
const body: any = await resp.json()
|
|
538
|
-
const seqId = body.request_id || seqIdFromHeader
|
|
539
|
-
throw new Error(`[${getSdkName()}/${getSdkVersion()}][OAuth2AuthProvider][status:${resp.status}][${body.error}(${body.error_code})] ${body.error_description} (${seqId})`)
|
|
540
|
-
}
|
|
541
|
-
else if (resp.status >= 500) {
|
|
542
|
-
const body: any = await resp.json()
|
|
543
|
-
const seqId = body.request_id || seqIdFromHeader
|
|
544
|
-
throw new Error(`[${getSdkName()}/${getSdkVersion()}][OAuth2AuthProvider][status:${resp.status}][${body.error}(${body.error_code})] ${body.error_description} (${seqId})`)
|
|
545
|
-
}
|
|
546
|
-
return resp.json()
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// 调用接口刷新access token,并且返回
|
|
550
|
-
private async _refreshAccessTokenFromOauthServer(clientId: string): Promise<IGetAccessTokenResult> {
|
|
551
|
-
const { accessTokenKey, accessTokenExpireKey, refreshTokenKey } = this._cache.keys;
|
|
552
|
-
const refreshToken = await this._cache.getStoreAsync(refreshTokenKey);
|
|
553
|
-
if (!refreshToken) {
|
|
554
|
-
throw new Error(JSON.stringify({
|
|
555
|
-
code: ERRORS.INVALID_OPERATION,
|
|
556
|
-
msg: 'not login'
|
|
557
|
-
}));
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const token = await this._fetchAccessTokenFromOauthServer(refreshToken, clientId);
|
|
561
|
-
const { refresh_token: newRefreshToken, access_token: accessToken, expires_in: accessTokenExpire } = token
|
|
562
|
-
|
|
563
|
-
// 错误处理
|
|
564
|
-
if (!accessToken || !accessTokenExpire) {
|
|
565
|
-
throw new Error(JSON.stringify({
|
|
566
|
-
code: ERRORS.NETWORK_ERROR,
|
|
567
|
-
msg: 'refresh access_token failed'
|
|
568
|
-
}));
|
|
569
|
-
}
|
|
570
|
-
if (accessToken && accessTokenExpire) {
|
|
571
|
-
if (newRefreshToken === refreshToken) {
|
|
572
|
-
await this._cache.setStoreAsync(refreshTokenKey, newRefreshToken);
|
|
573
|
-
}
|
|
574
|
-
await this._cache.setStoreAsync(accessTokenKey, accessToken);
|
|
575
|
-
await this._cache.setStoreAsync(accessTokenExpireKey, accessTokenExpire * 1000 + Date.now());
|
|
576
|
-
cloudbase.fire(EVENTS.ACCESS_TOKEN_REFRESHD);
|
|
577
|
-
return {
|
|
578
|
-
accessToken: accessToken,
|
|
579
|
-
accessTokenExpire: accessTokenExpire
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
private async _setRefreshToken(refreshToken: string) {
|
|
585
|
-
const { accessTokenKey, accessTokenExpireKey, refreshTokenKey } = this._cache.keys;
|
|
586
|
-
// refresh token设置前,先清掉 access token
|
|
587
|
-
// 设置是直接拉取新 access token 覆盖,而不是 remove
|
|
588
|
-
await this._cache.removeStoreAsync(accessTokenKey);
|
|
589
|
-
await this._cache.removeStoreAsync(accessTokenExpireKey);
|
|
590
|
-
await this._cache.setStoreAsync(refreshTokenKey, refreshToken);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
private async getDeviceId(): Promise<string> {
|
|
594
|
-
const { deviceIdKey } = this._cache.keys
|
|
595
|
-
const deviceId = await this._cache.getStoreAsync(deviceIdKey)
|
|
596
|
-
|
|
597
|
-
if (!deviceId) {
|
|
598
|
-
// const fp = await fpPromise
|
|
599
|
-
// const result = await fp.get()
|
|
600
|
-
// const deviceId = result.visitorId
|
|
601
|
-
const newDeviceId = uuidv4()
|
|
602
|
-
this._cache.setStoreAsync(deviceIdKey, newDeviceId)
|
|
603
|
-
return newDeviceId
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
return deviceId
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
273
|
}
|
|
610
274
|
|
|
611
275
|
const requestMap: KV<CloudbaseRequest> = {};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EVENTS = void 0;
|
|
4
|
-
exports.EVENTS = {
|
|
5
|
-
LOGIN_STATE_CHANGED: 'loginStateChanged',
|
|
6
|
-
LOGIN_STATE_EXPIRED: 'loginStateExpire',
|
|
7
|
-
LOGIN_TYPE_CHANGED: 'loginTypeChanged',
|
|
8
|
-
ANONYMOUS_CONVERTED: 'anonymousConverted',
|
|
9
|
-
ACCESS_TOKEN_REFRESHD: 'refreshAccessToken'
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbnN0YW50cy9ldmVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQWEsUUFBQSxNQUFNLEdBQUc7SUFDcEIsbUJBQW1CLEVBQUksbUJBQW1CO0lBQzFDLG1CQUFtQixFQUFJLGtCQUFrQjtJQUN6QyxrQkFBa0IsRUFBSyxrQkFBa0I7SUFDekMsbUJBQW1CLEVBQUksb0JBQW9CO0lBQzNDLHFCQUFxQixFQUFFLG9CQUFvQjtDQUM1QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IEVWRU5UUyA9IHtcbiAgTE9HSU5fU1RBVEVfQ0hBTkdFRCAgOiAnbG9naW5TdGF0ZUNoYW5nZWQnLFxuICBMT0dJTl9TVEFURV9FWFBJUkVEICA6ICdsb2dpblN0YXRlRXhwaXJlJyxcbiAgTE9HSU5fVFlQRV9DSEFOR0VEICAgOiAnbG9naW5UeXBlQ2hhbmdlZCcsXG4gIEFOT05ZTU9VU19DT05WRVJURUQgIDogJ2Fub255bW91c0NvbnZlcnRlZCcsIC8v5Yy/5ZCN6LSm5oi36KKr6L2s5q2j5ZCO6Kem5Y+RXG4gIEFDQ0VTU19UT0tFTl9SRUZSRVNIRDogJ3JlZnJlc2hBY2Nlc3NUb2tlbidcbn07XG4iXX0=
|