@cloudbase/oauth 3.0.0 → 3.0.2

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.
Files changed (70) hide show
  1. package/dist/cjs/auth/apis.d.ts +22 -4
  2. package/dist/cjs/auth/apis.js +255 -66
  3. package/dist/cjs/auth/auth-error.d.ts +6 -0
  4. package/dist/cjs/auth/auth-error.js +32 -0
  5. package/dist/cjs/auth/consts.d.ts +22 -0
  6. package/dist/cjs/auth/consts.js +24 -2
  7. package/dist/cjs/auth/models.d.ts +13 -4
  8. package/dist/cjs/auth/models.js +1 -1
  9. package/dist/cjs/captcha/captcha-dom.d.ts +3 -0
  10. package/dist/cjs/captcha/captcha-dom.js +223 -0
  11. package/dist/cjs/captcha/captcha.d.ts +3 -1
  12. package/dist/cjs/captcha/captcha.js +11 -102
  13. package/dist/cjs/index.d.ts +12 -2
  14. package/dist/cjs/index.js +27 -4
  15. package/dist/cjs/oauth2client/interface.d.ts +1 -1
  16. package/dist/cjs/oauth2client/interface.js +1 -1
  17. package/dist/cjs/oauth2client/models.d.ts +15 -1
  18. package/dist/cjs/oauth2client/models.js +1 -1
  19. package/dist/cjs/oauth2client/oauth2client.d.ts +62 -3
  20. package/dist/cjs/oauth2client/oauth2client.js +426 -131
  21. package/dist/cjs/utils/base64.d.ts +5 -0
  22. package/dist/cjs/utils/base64.js +15 -2
  23. package/dist/cjs/utils/encryptlong/index.js +22 -16
  24. package/dist/cjs/utils/index.js +1 -1
  25. package/dist/cjs/utils/mp.js +4 -4
  26. package/dist/cjs/utils/urlSearchParams.js +1 -1
  27. package/dist/esm/auth/apis.d.ts +22 -4
  28. package/dist/esm/auth/apis.js +130 -10
  29. package/dist/esm/auth/auth-error.d.ts +6 -0
  30. package/dist/esm/auth/auth-error.js +9 -0
  31. package/dist/esm/auth/consts.d.ts +22 -0
  32. package/dist/esm/auth/consts.js +22 -0
  33. package/dist/esm/auth/models.d.ts +13 -4
  34. package/dist/esm/captcha/captcha-dom.d.ts +3 -0
  35. package/dist/esm/captcha/captcha-dom.js +129 -0
  36. package/dist/esm/captcha/captcha.d.ts +3 -1
  37. package/dist/esm/captcha/captcha.js +14 -97
  38. package/dist/esm/index.d.ts +12 -2
  39. package/dist/esm/index.js +20 -3
  40. package/dist/esm/oauth2client/interface.d.ts +1 -1
  41. package/dist/esm/oauth2client/models.d.ts +15 -1
  42. package/dist/esm/oauth2client/oauth2client.d.ts +62 -3
  43. package/dist/esm/oauth2client/oauth2client.js +200 -55
  44. package/dist/esm/utils/base64.d.ts +5 -0
  45. package/dist/esm/utils/base64.js +12 -0
  46. package/dist/esm/utils/encryptlong/index.js +21 -15
  47. package/dist/esm/utils/mp.js +3 -3
  48. package/dist/miniprogram/index.js +1 -1
  49. package/package.json +10 -4
  50. package/src/auth/apis.ts +222 -17
  51. package/src/auth/auth-error.ts +21 -0
  52. package/src/auth/consts.ts +28 -0
  53. package/src/auth/models.ts +13 -4
  54. package/src/captcha/captcha-dom.ts +178 -0
  55. package/src/captcha/captcha.ts +25 -114
  56. package/src/index.ts +54 -4
  57. package/src/oauth2client/interface.ts +1 -1
  58. package/src/oauth2client/models.ts +29 -1
  59. package/src/oauth2client/oauth2client.ts +308 -55
  60. package/src/utils/base64.ts +12 -0
  61. package/src/utils/encryptlong/index.js +20 -14
  62. package/src/utils/index.ts +1 -0
  63. package/src/utils/mp.ts +3 -3
  64. package/src/utils/urlSearchParams.ts +2 -0
  65. package/tsconfig.json +1 -0
  66. package/dist/cjs/utils/cloudbase-adapter-wx_mp.d.ts +0 -1
  67. package/dist/cjs/utils/cloudbase-adapter-wx_mp.js +0 -40
  68. package/dist/esm/utils/cloudbase-adapter-wx_mp.d.ts +0 -1
  69. package/dist/esm/utils/cloudbase-adapter-wx_mp.js +0 -35
  70. package/src/utils/cloudbase-adapter-wx_mp.ts +0 -42
@@ -1,5 +1,5 @@
1
1
  import { ErrorType } from './consts'
2
- import { ApiUrls, ApiUrlsV2, AUTH_API_PREFIX } from '../auth/consts'
2
+ import { ApiUrls, ApiUrlsV2, AUTH_API_PREFIX, AUTH_STATE_CHANGED_TYPE, EVENTS } from '../auth/consts'
3
3
 
4
4
  import { AuthClient, SimpleStorage } from './interface'
5
5
 
@@ -17,7 +17,7 @@ import { getPathName } from '../utils/index'
17
17
 
18
18
  import { SinglePromise } from '../utils/function/single-promise'
19
19
  import { weBtoa } from '../utils/base64'
20
- import { isMatch } from '../utils/cloudbase-adapter-wx_mp'
20
+ import { isMp } from '../utils/mp'
21
21
  import { AuthOptions } from '../auth/apis'
22
22
  import { ICloudbaseConfig } from '@cloudbase/types'
23
23
  import { langEvent } from '@cloudbase/utilities'
@@ -106,6 +106,7 @@ class DefaultStorage implements SimpleStorage {
106
106
  /**
107
107
  * 缓存key统一使用后缀区分
108
108
  */
109
+ // eslint-disable-next-line @typescript-eslint/naming-convention
109
110
  private readonly _env: string
110
111
 
111
112
  constructor(opts?: { env: string }) {
@@ -197,6 +198,8 @@ class LocalCredentials {
197
198
  private clientId: string
198
199
 
199
200
  private credentials: Credentials | null = null
201
+ // 来自accessKey的身份,不持久化
202
+ private accessKeyCredentials: Credentials | null = null
200
203
 
201
204
  private singlePromise: SinglePromise = null
202
205
 
@@ -210,9 +213,6 @@ class LocalCredentials {
210
213
  this.clientId = options.clientId
211
214
  this.singlePromise = new SinglePromise({ clientId: this.clientId })
212
215
  this.credentials = options.credentials || null
213
- if (this.credentials) {
214
- this.setCredentials(this.credentials)
215
- }
216
216
  }
217
217
 
218
218
  public getStorageCredentialsSync(): Credentials | null {
@@ -254,6 +254,14 @@ class LocalCredentials {
254
254
  }
255
255
  }
256
256
 
257
+ /**
258
+ * set credentials from accessKey
259
+ * @param {Credentials} credentials
260
+ */
261
+ public setAccessKeyCredentials(credentials?: Credentials) {
262
+ this.accessKeyCredentials = credentials
263
+ }
264
+
257
265
  /**
258
266
  * Get credentials.
259
267
  * @return {Promise<Credentials | null>}
@@ -261,7 +269,11 @@ class LocalCredentials {
261
269
  public async getCredentials(): Promise<Credentials | null> {
262
270
  return this.singlePromise.run('getCredentials', async () => {
263
271
  if (isCredentialsExpired(this.credentials)) {
264
- this.credentials = await this.getStorageCredentials()
272
+ const { credentials, isAccessKeyCredentials } = await this.getStorageCredentials()
273
+ if (isAccessKeyCredentials) {
274
+ return credentials
275
+ }
276
+ this.credentials = credentials
265
277
  }
266
278
  return this.credentials
267
279
  })
@@ -270,11 +282,12 @@ class LocalCredentials {
270
282
  /**
271
283
  * Get storage credentials.
272
284
  */
273
- private async getStorageCredentials(): Promise<Credentials | null> {
285
+ private async getStorageCredentials(): Promise<{ credentials: Credentials | null; isAccessKeyCredentials: boolean }> {
274
286
  return this.singlePromise.run('_getStorageCredentials', async () => {
275
287
  let credentials: Credentials = null
288
+ let isAccessKeyCredentials = false
276
289
  const tokenStr: string = await this.storage.getItem(this.tokenSectionName)
277
- if (tokenStr !== undefined && tokenStr !== null) {
290
+ if (!!tokenStr) {
278
291
  try {
279
292
  credentials = JSON.parse(tokenStr)
280
293
  if (credentials?.expires_at) {
@@ -284,8 +297,11 @@ class LocalCredentials {
284
297
  await this.storage.removeItem(this.tokenSectionName)
285
298
  credentials = null
286
299
  }
300
+ } else {
301
+ credentials = this.accessKeyCredentials || null
302
+ isAccessKeyCredentials = true
287
303
  }
288
- return credentials
304
+ return { credentials, isAccessKeyCredentials }
289
305
  })
290
306
  }
291
307
  }
@@ -299,6 +315,20 @@ export class OAuth2Client implements AuthClient {
299
315
  private static maxRetry = 5
300
316
  private static retryInterval = 1000
301
317
 
318
+ public localCredentials: LocalCredentials
319
+ /**
320
+ * Keeps track of the async client initialization.
321
+ * When null or not yet resolved the auth state is `unknown`
322
+ * Once resolved the auth state is known and it's safe to call any further client methods.
323
+ */
324
+ public initializePromise: Promise<{ error: Error | null }> | null = null
325
+ protected lockAcquired = false
326
+ protected pendingInLock: Promise<any>[] = []
327
+ protected logDebugMessages: boolean
328
+ protected getInitialSession?: () => Promise<{
329
+ data: { session: Credentials; user?: any } | null
330
+ error: Error | null
331
+ }>
302
332
  private apiOrigin: string
303
333
  private apiPath: string
304
334
  private clientId: string
@@ -306,7 +336,6 @@ export class OAuth2Client implements AuthClient {
306
336
  private retry: number
307
337
  private clientSecret?: string
308
338
  private baseRequest: <T>(url: string, options?: RequestOptions) => Promise<T>
309
- private localCredentials: LocalCredentials
310
339
  private storage: SimpleStorage
311
340
  private deviceID?: string
312
341
  private tokenInURL?: boolean
@@ -315,9 +344,11 @@ export class OAuth2Client implements AuthClient {
315
344
  private singlePromise: SinglePromise = null
316
345
  private anonymousSignInFunc: (Credentials) => Promise<Credentials | void>
317
346
  private wxCloud: any
347
+ private useWxCloud: boolean
348
+ private eventBus: any
318
349
  private basicAuth: string
319
350
  private onCredentialsError: AuthOptions['onCredentialsError'] | undefined
320
- private publishable_key: ICloudbaseConfig['publishable_key']
351
+ private onInitialSessionObtained?: (data: { session: Credentials; user?: any }, error?: any) => void | Promise<void>
321
352
 
322
353
  /**
323
354
  * constructor
@@ -336,7 +367,7 @@ export class OAuth2Client implements AuthClient {
336
367
  this.apiPath = options.apiPath || AUTH_API_PREFIX
337
368
  this.clientId = options.clientId
338
369
  this.i18n = options.i18n
339
- this.publishable_key = options.publishable_key
370
+ this.eventBus = options.eventBus
340
371
  this.singlePromise = new SinglePromise({ clientId: this.clientId })
341
372
  this.retry = this.formatRetry(options.retry, OAuth2Client.defaultRetry)
342
373
  if (options.baseRequest) {
@@ -352,13 +383,6 @@ export class OAuth2Client implements AuthClient {
352
383
  tokenSectionName: `credentials_${options.clientId}`,
353
384
  storage: this.storage,
354
385
  clientId: options.clientId,
355
- credentials: this.publishable_key ? {
356
- access_token: this.publishable_key,
357
- token_type: 'Bearer',
358
- scope: 'publishable_key',
359
- expires_at: new Date(+new Date() + +new Date()),
360
- expires_in: +new Date() + +new Date(),
361
- } : null,
362
386
  })
363
387
 
364
388
  this.clientSecret = options.clientSecret
@@ -367,9 +391,12 @@ export class OAuth2Client implements AuthClient {
367
391
  }
368
392
  this.wxCloud = options.wxCloud
369
393
  try {
370
- if (isMatch() && this.wxCloud === undefined && options.env) {
371
- wx.cloud.init({ env: options.env })
372
- this.wxCloud = wx.cloud
394
+ if (isMp()) {
395
+ this.useWxCloud = options.useWxCloud
396
+ if (this.wxCloud === undefined && options.env) {
397
+ wx.cloud.init({ env: options.env })
398
+ this.wxCloud = wx.cloud
399
+ }
373
400
  }
374
401
  } catch (error) {
375
402
  //
@@ -378,9 +405,61 @@ export class OAuth2Client implements AuthClient {
378
405
  this.anonymousSignInFunc = options.anonymousSignInFunc
379
406
  this.onCredentialsError = options.onCredentialsError
380
407
 
381
- langEvent.bus.on(langEvent.LANG_CHANGE_EVENT, (params) => {
408
+ // New options for session detection
409
+ this.getInitialSession = options.getInitialSession
410
+ this.onInitialSessionObtained = options.onInitialSessionObtained
411
+ this.logDebugMessages = options.debug ?? false
412
+
413
+ langEvent.bus.on(langEvent.LANG_CHANGE_EVENT, (params: any) => {
382
414
  this.i18n = params.data?.i18n || this.i18n
383
415
  })
416
+
417
+ // Note: Auto-initialize is NOT called here to allow CloudbaseOAuth to set getInitialSession first
418
+ // CloudbaseOAuth.constructor will call initialize() after setting up the callback
419
+ }
420
+
421
+ /**
422
+ * Sets the getInitialSession callback.
423
+ * This callback is called during initialize() to get the initial session (e.g., from OAuth callback in URL).
424
+ * @param callback The callback function to get initial session
425
+ */
426
+ public setGetInitialSession(callback: () => Promise<{
427
+ data: { session: Credentials; user?: any } | null
428
+ error: Error | null
429
+ }>,): void {
430
+ this.getInitialSession = callback
431
+ }
432
+
433
+ /**
434
+ * Sets the onInitialSessionObtained callback.
435
+ * This callback is invoked after initial session is obtained and stored,
436
+ * allowing upper layers to handle user info storage.
437
+ * @param callback The callback function to handle session and user data
438
+ */
439
+ public setOnInitialSessionObtained(callback: (data: { session: Credentials; user?: any }) => void | Promise<void>,): void {
440
+ this.onInitialSessionObtained = callback
441
+ }
442
+
443
+ /**
444
+ * Initializes the client session either from the url or from storage.
445
+ * This method is automatically called when instantiating the client with detectSessionInUrl=true,
446
+ * but should also be called manually when checking for an error from an auth redirect.
447
+ * @param onInitialSessionObtained Optional callback to set before initialization starts
448
+ */
449
+ async initialize(func?: Promise<{ error: Error | null }>): Promise<{ error: Error | null }> {
450
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
451
+ if (this.initializePromise) {
452
+ return await this.initializePromise
453
+ }
454
+
455
+ if (func !== undefined) {
456
+ this.initializePromise = func
457
+ return await this.initializePromise
458
+ }
459
+
460
+ this.initializePromise = (async () => await this._acquireLock(-1, async () => await this._initialize()))()
461
+
462
+ return await this.initializePromise
384
463
  }
385
464
 
386
465
  /**
@@ -388,14 +467,26 @@ export class OAuth2Client implements AuthClient {
388
467
  * @param {Credentials} credentials
389
468
  * @return {Promise<void>}
390
469
  */
391
- public setCredentials(credentials?: Credentials): Promise<void> {
392
- return this.localCredentials.setCredentials(credentials)
470
+ public async setCredentials(credentials?: Credentials): Promise<void> {
471
+ // If initialization is in progress, wait for it first
472
+ await this.initializePromise
473
+ return this._acquireLock(-1, async () => this.localCredentials.setCredentials(credentials))
474
+ }
475
+
476
+ /**
477
+ * set credentials from accessKey
478
+ * @param {Credentials} credentials
479
+ */
480
+ public setAccessKeyCredentials(credentials?: Credentials) {
481
+ return this.localCredentials.setAccessKeyCredentials(credentials)
393
482
  }
394
483
 
395
484
  /**
396
485
  * getAccessToken return a validate access token
397
486
  */
398
487
  public async getAccessToken(): Promise<string> {
488
+ // If initialization is in progress, wait for it first
489
+ await this.initializePromise
399
490
  const credentials: Credentials = await this.getCredentials()
400
491
  if (credentials?.access_token) {
401
492
  return Promise.resolve(credentials.access_token)
@@ -432,7 +523,9 @@ export class OAuth2Client implements AuthClient {
432
523
  options.headers.Authorization = this.basicAuth
433
524
  }
434
525
  if (options?.withCredentials) {
435
- const credentials = await this.getCredentials()
526
+ // Use custom getCredentials function if provided, otherwise use default
527
+ // Custom getCredentials avoids default getCredentials() call which may cause deadlock during initialization
528
+ const credentials = options.getCredentials ? await options.getCredentials() : await this.getCredentials()
436
529
  if (credentials) {
437
530
  if (this.tokenInURL) {
438
531
  if (url.indexOf('?') < 0) {
@@ -456,11 +549,20 @@ export class OAuth2Client implements AuthClient {
456
549
  const maxRequestTimes: number = retry + 1
457
550
  for (let requestTime = 0; requestTime < maxRequestTimes; requestTime++) {
458
551
  try {
459
- if (options.useWxCloud) {
552
+ if (options.useWxCloud || this.useWxCloud) {
460
553
  response = await this.wxCloudCallFunction<T>(url, options)
461
554
  } else {
462
555
  response = await this.baseRequest<T>(url, options)
463
556
  }
557
+
558
+ if (!!(response as any)?.code) {
559
+ throw ({
560
+ error: (response as any).code,
561
+ error_description: (response as any).message,
562
+ error_uri: new URL(url).pathname,
563
+ })
564
+ }
565
+
464
566
  break
465
567
  } catch (responseError) {
466
568
  if (options.withCredentials && responseError && responseError.error === ErrorType.UNAUTHENTICATED) {
@@ -524,33 +626,10 @@ export class OAuth2Client implements AuthClient {
524
626
  * Get credentials.
525
627
  */
526
628
  public async getCredentials(): Promise<Credentials | null> {
527
- let credentials: Credentials = await this.localCredentials.getCredentials()
528
- if (!credentials) {
529
- const msg = 'credentials not found'
530
- this.onCredentialsError?.({ msg })
531
- return this.unAuthenticatedError(msg)
532
- }
533
- if (isCredentialsExpired(credentials)) {
534
- if (credentials.refresh_token) {
535
- try {
536
- credentials = await this.refreshToken(credentials)
537
- } catch (error) {
538
- if (credentials.scope === 'anonymous') {
539
- credentials = await this.anonymousLogin(credentials)
540
- } else {
541
- this.onCredentialsError?.({ msg: error.error_description })
542
- return Promise.reject(error)
543
- }
544
- }
545
- } else if (credentials.scope === 'anonymous') {
546
- credentials = await this.anonymousLogin(credentials)
547
- } else {
548
- const msg = 'no refresh token found in credentials'
549
- this.onCredentialsError?.({ msg })
550
- return this.unAuthenticatedError(msg)
551
- }
552
- }
553
- return credentials
629
+ // If initialization is in progress, wait for it first
630
+ await this.initializePromise
631
+
632
+ return this._acquireLock(-1, async () => this._getCredentials())
554
633
  }
555
634
 
556
635
  /**
@@ -590,7 +669,17 @@ export class OAuth2Client implements AuthClient {
590
669
  * @param {Credentials} credentials
591
670
  * @return {Promise<Credentials>}
592
671
  */
593
- public async refreshToken(credentials: Credentials): Promise<Credentials> {
672
+ public async refreshToken(credentials: Credentials, options?: { throwError?: boolean }): Promise<Credentials> {
673
+ // If initialization is in progress, wait for it first
674
+ await this.initializePromise
675
+
676
+ return this._acquireLock(-1, async () => this._refreshToken(credentials, options))
677
+ }
678
+
679
+ /**
680
+ * Internal refresh token method (called within lock)
681
+ */
682
+ private async _refreshToken(credentials: Credentials, options?: { throwError?: boolean }): Promise<Credentials> {
594
683
  return this.singlePromise.run('_refreshToken', async () => {
595
684
  if (!credentials || !credentials.refresh_token) {
596
685
  const msg = 'no refresh token found in credentials'
@@ -600,8 +689,14 @@ export class OAuth2Client implements AuthClient {
600
689
  try {
601
690
  const newCredentials: Credentials = await this.refreshTokenFunc(credentials.refresh_token, credentials)
602
691
  await this.localCredentials.setCredentials(newCredentials)
692
+
693
+ this.eventBus?.fire(EVENTS.AUTH_STATE_CHANGED, { event: AUTH_STATE_CHANGED_TYPE.TOKEN_REFRESHED })
694
+
603
695
  return newCredentials
604
696
  } catch (error) {
697
+ if (options?.throwError) {
698
+ throw error
699
+ }
605
700
  if (error.error === ErrorType.INVALID_GRANT) {
606
701
  await this.localCredentials.setCredentials(null)
607
702
  const msg = error.error_description
@@ -758,4 +853,162 @@ export class OAuth2Client implements AuthClient {
758
853
  }
759
854
  return Promise.reject(respErr)
760
855
  }
856
+
857
+ /**
858
+ * Debug logging helper
859
+ */
860
+ private _debug(...args: any[]): void {
861
+ if (this.logDebugMessages) {
862
+ console.log('[OAuth2Client]', ...args)
863
+ }
864
+ }
865
+
866
+ /**
867
+ * IMPORTANT:
868
+ * 1. Never throw in this method, as it is called from the constructor
869
+ * 2. Never return a session from this method as it would be cached over
870
+ * the whole lifetime of the client
871
+ */
872
+ private async _initialize(): Promise<{ error: Error | null }> {
873
+ try {
874
+ // If no getInitialSession callback is set, nothing to do
875
+ if (!this.getInitialSession) {
876
+ this._debug('#_initialize()', 'no getInitialSession callback set, skipping')
877
+ return { error: null }
878
+ }
879
+
880
+ this._debug('#_initialize()', 'calling getInitialSession callback')
881
+
882
+ try {
883
+ const { data, error } = await this.getInitialSession()
884
+
885
+ if (data?.session) {
886
+ this._debug('#_initialize()', 'session obtained from getInitialSession', data.session)
887
+ await this.localCredentials.setCredentials(data?.session)
888
+ }
889
+
890
+ // Invoke callback for upper layer to handle user storage
891
+ // This is called BEFORE lock is released so user storage is atomic with session
892
+ if (this.onInitialSessionObtained) {
893
+ this._debug('#_initialize()', 'calling onInitialSessionObtained callback')
894
+ try {
895
+ await this.onInitialSessionObtained(data, error)
896
+ } catch (callbackError) {
897
+ this._debug('#_initialize()', 'error in onInitialSessionObtained', callbackError)
898
+ // Don't fail initialization if callback fails
899
+ }
900
+ }
901
+ if (error) {
902
+ this._debug('#_initialize()', 'error from getInitialSession', error)
903
+ return { error }
904
+ }
905
+
906
+ return { error: null }
907
+ } catch (err) {
908
+ this._debug('#_initialize()', 'exception during getInitialSession', err)
909
+ return { error: err instanceof Error ? err : new Error(String(err)) }
910
+ }
911
+ } catch (error) {
912
+ this._debug('#_initialize()', 'unexpected error', error)
913
+ return { error: error instanceof Error ? error : new Error(String(error)) }
914
+ } finally {
915
+ this._debug('#_initialize()', 'end')
916
+ }
917
+ }
918
+
919
+ /**
920
+ * Acquires a global lock based on the client ID.
921
+ * This ensures that only one operation can modify credentials at a time.
922
+ */
923
+ private async _acquireLock<R>(acquireTimeout: number, fn: () => Promise<R>): Promise<R> {
924
+ this._debug('#_acquireLock', 'begin', acquireTimeout)
925
+
926
+ try {
927
+ if (this.lockAcquired) {
928
+ // Lock is already acquired, queue the operation
929
+ const last = this.pendingInLock.length ? this.pendingInLock[this.pendingInLock.length - 1] : Promise.resolve()
930
+
931
+ const result = (async () => {
932
+ await last
933
+ return await fn()
934
+ })()
935
+
936
+ this.pendingInLock.push((async () => {
937
+ try {
938
+ await result
939
+ } catch (_e: any) {
940
+ // we just care if it finished
941
+ }
942
+ })(),)
943
+
944
+ return result
945
+ }
946
+
947
+ // Acquire the lock
948
+ this._debug('#_acquireLock', 'acquiring lock for client', this.clientId)
949
+
950
+ try {
951
+ this.lockAcquired = true
952
+
953
+ const result = fn()
954
+
955
+ this.pendingInLock.push((async () => {
956
+ try {
957
+ await result
958
+ } catch (_e: any) {
959
+ // we just care if it finished
960
+ }
961
+ })(),)
962
+
963
+ await result
964
+
965
+ // keep draining the queue until there's nothing to wait on
966
+ while (this.pendingInLock.length) {
967
+ const waitOn = [...this.pendingInLock]
968
+ await Promise.all(waitOn)
969
+ this.pendingInLock.splice(0, waitOn.length)
970
+ }
971
+
972
+ return await result
973
+ } finally {
974
+ this._debug('#_acquireLock', 'releasing lock for client', this.clientId)
975
+ this.lockAcquired = false
976
+ }
977
+ } finally {
978
+ this._debug('#_acquireLock', 'end')
979
+ }
980
+ }
981
+
982
+ /**
983
+ * Internal method to get credentials (called within lock)
984
+ */
985
+ private async _getCredentials(): Promise<Credentials | null> {
986
+ let credentials: Credentials = await this.localCredentials.getCredentials()
987
+ if (!credentials) {
988
+ const msg = 'credentials not found'
989
+ this.onCredentialsError?.({ msg })
990
+ return this.unAuthenticatedError(msg)
991
+ }
992
+ if (isCredentialsExpired(credentials)) {
993
+ if (credentials.refresh_token) {
994
+ try {
995
+ credentials = await this._refreshToken(credentials)
996
+ } catch (error) {
997
+ if (credentials.scope === 'anonymous') {
998
+ credentials = await this.anonymousLogin(credentials)
999
+ } else {
1000
+ this.onCredentialsError?.({ msg: error.error_description })
1001
+ return Promise.reject(error)
1002
+ }
1003
+ }
1004
+ } else if (credentials.scope === 'anonymous') {
1005
+ credentials = await this.anonymousLogin(credentials)
1006
+ } else {
1007
+ const msg = 'no refresh token found in credentials'
1008
+ this.onCredentialsError?.({ msg })
1009
+ return this.unAuthenticatedError(msg)
1010
+ }
1011
+ }
1012
+ return credentials
1013
+ }
761
1014
  }
@@ -98,3 +98,15 @@ export function weappJwtDecode(token: string, options?: any) {
98
98
  throw new Error(`Invalid token specified: ${e}` ? (e as any).message : '')
99
99
  }
100
100
  }
101
+
102
+ export function weAppJwtDecodeAll(token: string) {
103
+ if (typeof token !== 'string') {
104
+ throw new Error('Invalid token specified')
105
+ }
106
+ try {
107
+ const parts = token.split('.').map((segment, i) => i === 2 ? segment : JSON.parse(base64_url_decode(segment)))
108
+ return { claims: parts[1], header: parts[0], signature: parts[2]}
109
+ } catch (e) {
110
+ throw new Error(`Invalid token specified: ${e}` ? (e as any).message : '')
111
+ }
112
+ }
@@ -2697,12 +2697,14 @@ and limitations under the License.
2697
2697
  rng_pool = []
2698
2698
  rng_pptr = 0
2699
2699
  var t = void 0
2700
- if (window?.crypto && window?.crypto.getRandomValues) {
2701
- // Extract entropy (2048 bits) from RNG if available
2702
- var z = new Uint32Array(256)
2703
- window?.crypto.getRandomValues(z)
2704
- for (t = 0; t < z.length; ++t) {
2705
- rng_pool[rng_pptr++] = z[t] & 255
2700
+ if (typeof window !== 'undefined') {
2701
+ if (window?.crypto && window?.crypto.getRandomValues) {
2702
+ // Extract entropy (2048 bits) from RNG if available
2703
+ var z = new Uint32Array(256)
2704
+ window?.crypto.getRandomValues(z)
2705
+ for (t = 0; t < z.length; ++t) {
2706
+ rng_pool[rng_pptr++] = z[t] & 255
2707
+ }
2706
2708
  }
2707
2709
  }
2708
2710
  // Use mouse events for entropy, if we do not have enough entropy by the time
@@ -2710,10 +2712,12 @@ and limitations under the License.
2710
2712
  var onMouseMoveListener_1 = function (ev) {
2711
2713
  this.count = this.count || 0
2712
2714
  if (this.count >= 256 || rng_pptr >= rng_psize) {
2713
- if (window?.removeEventListener) {
2714
- window?.removeEventListener('mousemove', onMouseMoveListener_1, false)
2715
- } else if (window?.detachEvent) {
2716
- window?.detachEvent('onmousemove', onMouseMoveListener_1)
2715
+ if (typeof window !== 'undefined') {
2716
+ if (window?.removeEventListener) {
2717
+ window?.removeEventListener('mousemove', onMouseMoveListener_1, false)
2718
+ } else if (window?.detachEvent) {
2719
+ window?.detachEvent('onmousemove', onMouseMoveListener_1)
2720
+ }
2717
2721
  }
2718
2722
  return
2719
2723
  }
@@ -2725,10 +2729,12 @@ and limitations under the License.
2725
2729
  // Sometimes Firefox will deny permission to access event properties for some reason. Ignore.
2726
2730
  }
2727
2731
  }
2728
- if (window?.addEventListener) {
2729
- window?.addEventListener('mousemove', onMouseMoveListener_1, false)
2730
- } else if (window?.attachEvent) {
2731
- window?.attachEvent('onmousemove', onMouseMoveListener_1)
2732
+ if (typeof window !== 'undefined') {
2733
+ if (window?.addEventListener) {
2734
+ window?.addEventListener('mousemove', onMouseMoveListener_1, false)
2735
+ } else if (window?.attachEvent) {
2736
+ window?.attachEvent('onmousemove', onMouseMoveListener_1)
2737
+ }
2732
2738
  }
2733
2739
  }
2734
2740
  function rng_get_byte() {
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export const deepClone = (value: any) => {
10
10
  const clone = (copiedValue: any) => {
11
+ // eslint-disable-next-line no-restricted-syntax
11
12
  for (const key in value) {
12
13
  // eslint-disable-next-line no-prototype-builtins
13
14
  if (value.hasOwnProperty(key)) {
package/src/utils/mp.ts CHANGED
@@ -10,7 +10,7 @@ export function isMp() {
10
10
  if ((globalThis as any).Page === undefined) {
11
11
  return false
12
12
  }
13
- if (!wx.getSystemInfoSync) {
13
+ if (!wx.getDeviceInfo) {
14
14
  return false
15
15
  }
16
16
  if (!wx.getStorageSync) {
@@ -27,11 +27,11 @@ export function isMp() {
27
27
  }
28
28
 
29
29
  try {
30
- if (!wx.getSystemInfoSync()) {
30
+ if (!wx.getDeviceInfo()) {
31
31
  return false
32
32
  }
33
33
 
34
- if (wx.getSystemInfoSync().AppPlatform === 'qq') {
34
+ if (wx.getDeviceInfo().platform === 'qq') {
35
35
  return false
36
36
  }
37
37
  } catch (e) {
@@ -9,6 +9,7 @@ class MyURLSearchParams {
9
9
  if (typeof init === 'string') {
10
10
  this.parse(init)
11
11
  } else if (init && typeof init === 'object') {
12
+ // eslint-disable-next-line no-restricted-syntax
12
13
  for (const key in init) {
13
14
  if (Object.prototype.hasOwnProperty.call(init, key)) {
14
15
  this.append(key, init[key])
@@ -63,6 +64,7 @@ class MyURLSearchParams {
63
64
  // 返回查询字符串
64
65
  toString() {
65
66
  const items = []
67
+ // eslint-disable-next-line no-restricted-syntax
66
68
  for (const key in this.params) {
67
69
  if (Object.prototype.hasOwnProperty.call(this.params, key)) {
68
70
  this.params[key].forEach((value) => {
package/tsconfig.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
+ "module": "node16",
4
5
  "outDir": "dist/cjs",
5
6
  "rootDir": "src",
6
7
  "noImplicitAny": false,
@@ -1 +0,0 @@
1
- export declare function isMatch(): boolean;