@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/app",
3
- "version": "1.5.1-alpha.0",
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": "^1.2.1-alpha.0",
32
- "@cloudbase/utilities": "^1.4.1-alpha.0",
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": "c462902b6702463670d27acb88ebccf93dbd51cd"
56
+ "gitHead": "4568e598d198896703ac0e204b3211c14bc79861"
57
57
  }
@@ -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
- if (config.region) {
128
- setRegionLevelEndpoint(env, config.region || '')
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 DEVICE_INFO = 'device_id';
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,persistence,platformInfo } = config;
19
+ export function initCache(config: ICacheConfig & { env: string }) {
20
+ const { env, platformInfo } = config;
21
21
 
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}`; // 非环境级别
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
- deviceIdKey
32
+ // accessTokenKey,
33
+ // accessTokenExpireKey,
34
+ // refreshTokenKey,
35
+ // anonymousUuidKey,
36
+ // loginTypeKey,
37
+ // deviceIdKey
38
38
  };
39
39
  // 若指定env已存在cache则尝试更新persistence
40
- cacheMap[env]?cacheMap[env].updatePersistence(persistence):(cacheMap[env] = new CloudbaseCache({
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,
@@ -1,9 +1,8 @@
1
1
  import {
2
2
  DATA_VERSION,
3
- LOGINTYPE,
4
3
  getSdkVersion,
5
4
  getEndPoint,
6
- OAUTH2_LOGINTYPE_PREFIX
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, jwt, adapters, constants } from '@cloudbase/utilities';
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 { cloudbase } from '..';
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 { getSdkName, ERRORS } = constants;
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 async refreshAccessToken(): Promise<IGetAccessTokenResult> {
189
- // 可能会同时调用多次刷新access token,这里把它们合并成一个
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 refreshAccessTokenFromOauthServer(clientId: string): Promise<IGetAccessTokenResult> {
211
- // 可能会同时调用多次刷新 access token,这里把它们合并成一个
212
- if (!this._refreshAccessTokenPromise) {
213
- // 没有正在刷新,那么正常执行刷新逻辑
214
- this._refreshAccessTokenPromise = this._refreshAccessTokenFromOauthServer(clientId);
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 { refreshTokenKey } = this._cache.keys;
323
-
324
- // 若有 refreshToken 则任务有登录态 刷 accessToken
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,7 +0,0 @@
1
- export declare const EVENTS: {
2
- LOGIN_STATE_CHANGED: string;
3
- LOGIN_STATE_EXPIRED: string;
4
- LOGIN_TYPE_CHANGED: string;
5
- ANONYMOUS_CONVERTED: string;
6
- ACCESS_TOKEN_REFRESHD: string;
7
- };
@@ -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=