@webex/webex-core 3.11.0-webex-services-ready.1 → 3.12.0-auth-prejoin-fetch.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.
Files changed (49) hide show
  1. package/README.md +5 -2
  2. package/dist/config.js +24 -0
  3. package/dist/config.js.map +1 -1
  4. package/dist/credentials-config.js +12 -0
  5. package/dist/credentials-config.js.map +1 -1
  6. package/dist/interceptors/redirect.js +1 -1
  7. package/dist/interceptors/redirect.js.map +1 -1
  8. package/dist/lib/batcher.js +23 -7
  9. package/dist/lib/batcher.js.map +1 -1
  10. package/dist/lib/credentials/credentials.js +48 -4
  11. package/dist/lib/credentials/credentials.js.map +1 -1
  12. package/dist/lib/credentials/token.js +1 -1
  13. package/dist/lib/domains.js +90 -0
  14. package/dist/lib/domains.js.map +1 -0
  15. package/dist/lib/services/service-catalog.js +6 -10
  16. package/dist/lib/services/service-catalog.js.map +1 -1
  17. package/dist/lib/services/services.js +244 -57
  18. package/dist/lib/services/services.js.map +1 -1
  19. package/dist/lib/services-v2/service-catalog.js +6 -12
  20. package/dist/lib/services-v2/service-catalog.js.map +1 -1
  21. package/dist/lib/services-v2/services-v2.js +243 -52
  22. package/dist/lib/services-v2/services-v2.js.map +1 -1
  23. package/dist/plugins/logger.js +1 -1
  24. package/dist/webex-core.js +2 -2
  25. package/dist/webex-core.js.map +1 -1
  26. package/package.json +13 -13
  27. package/src/config.js +27 -0
  28. package/src/credentials-config.js +13 -0
  29. package/src/interceptors/redirect.js +4 -1
  30. package/src/lib/batcher.js +25 -10
  31. package/src/lib/credentials/credentials.js +50 -3
  32. package/src/lib/domains.ts +94 -0
  33. package/src/lib/services/service-catalog.js +6 -10
  34. package/src/lib/services/services.js +218 -46
  35. package/src/lib/services-v2/service-catalog.ts +6 -11
  36. package/src/lib/services-v2/services-v2.ts +218 -42
  37. package/test/fixtures/activation-email.ts +22 -0
  38. package/test/integration/spec/services/service-catalog.js +7 -6
  39. package/test/integration/spec/services/services.js +188 -128
  40. package/test/integration/spec/services-v2/services-v2.js +174 -114
  41. package/test/unit/spec/credentials/credentials.js +133 -2
  42. package/test/unit/spec/interceptors/auth.js +56 -0
  43. package/test/unit/spec/lib/batcher.js +56 -0
  44. package/test/unit/spec/services/service-catalog.js +93 -11
  45. package/test/unit/spec/services/services.js +591 -322
  46. package/test/unit/spec/services-v2/service-catalog.ts +93 -11
  47. package/test/unit/spec/services-v2/services-v2.ts +539 -214
  48. package/test/unit/spec/webex-core.js +0 -2
  49. package/test/unit/spec/webex-internal-core.js +0 -2
@@ -5,7 +5,7 @@
5
5
  import '@webex/internal-plugin-device';
6
6
 
7
7
  import {assert} from '@webex/test-helper-chai';
8
- import {flaky} from '@webex/test-helper-mocha';
8
+ import {flaky, retryOn429} from '@webex/test-helper-mocha';
9
9
  import WebexCore, {
10
10
  ServiceCatalog,
11
11
  ServiceRegistry,
@@ -20,6 +20,7 @@ import WebexCore, {
20
20
  import testUsers from '@webex/test-helper-test-users';
21
21
  import uuid from 'uuid';
22
22
  import sinon from 'sinon';
23
+ import {createActivationEmail} from '../../../fixtures/activation-email';
23
24
 
24
25
  /* eslint-disable no-underscore-dangle */
25
26
  describe('webex-core', () => {
@@ -404,28 +405,19 @@ describe('webex-core', () => {
404
405
  assert.isTrue(catalog.isReady);
405
406
  });
406
407
 
407
- it('should call services#initServiceCatalogs() on webex loaded', async () => {
408
+ it('should call services#initServiceCatalogs() on webex ready', async () => {
409
+ services._loadCatalogFromCache = sinon.stub().resolves(false);
408
410
  services.initServiceCatalogs = sinon.stub().resolves();
409
411
  services.initialize();
410
- webex.trigger('loaded');
411
- // Wait for the async callback to execute
412
- await new Promise((resolve) => setTimeout(resolve, 10));
412
+ // The mode-specific ('ready'/'loaded') listener is registered inside the
413
+ // change:config handler, so fire change:config first, then 'ready'.
414
+ webex.trigger('change:config');
415
+ webex.trigger('ready');
416
+ // Wait for the async 'ready' handler to complete
417
+ await new Promise((resolve) => setTimeout(resolve, 50));
413
418
  assert.called(services.initServiceCatalogs);
414
419
  });
415
420
 
416
- it('should set services.ready to true after initialization completes', async () => {
417
- // services.ready starts as false
418
- const newWebex = new WebexCore({credentials: {supertoken: webexUser.token}});
419
- const newServices = newWebex.internal.services;
420
-
421
- // Wait for initialization to complete
422
- await new Promise((resolve) => {
423
- newServices.on('services:initialized', resolve);
424
- });
425
-
426
- assert.isTrue(newServices.ready);
427
- });
428
-
429
421
  it('should collect different catalogs based on OrgId region', () =>
430
422
  assert.notDeepEqual(services.list(true), servicesEU.list(true)));
431
423
 
@@ -441,6 +433,45 @@ describe('webex-core', () => {
441
433
  done();
442
434
  }, 2000);
443
435
  });
436
+
437
+ it('blocks webex.ready until services.ready flips when waitForCatalogInit is enabled', async () => {
438
+ const gatedWebex = new WebexCore({
439
+ credentials: {supertoken: webexUser.token},
440
+ config: {services: {waitForCatalogInit: true}},
441
+ });
442
+
443
+ // Before init settles, webex.ready must be false because services.ready
444
+ // is a dependency and starts false in the gated path.
445
+ assert.isFalse(gatedWebex.internal.services.ready, 'services.ready should start false');
446
+ assert.isFalse(
447
+ gatedWebex.ready,
448
+ 'webex.ready should not fire while services.ready is false'
449
+ );
450
+
451
+ // Wait up to 30s for services init to complete and flip ready.
452
+ await new Promise((resolve, reject) => {
453
+ if (gatedWebex.internal.services.ready) {
454
+ resolve();
455
+
456
+ return;
457
+ }
458
+ const timer = setTimeout(
459
+ () => reject(new Error('timed out waiting for services.ready')),
460
+ 30_000
461
+ );
462
+
463
+ gatedWebex.internal.services.once('change:ready', () => {
464
+ clearTimeout(timer);
465
+ resolve();
466
+ });
467
+ });
468
+
469
+ assert.isTrue(
470
+ gatedWebex.internal.services.ready,
471
+ 'services.ready should flip true after init settles'
472
+ );
473
+ assert.isTrue(gatedWebex.ready, 'webex.ready should fire once services.ready flips');
474
+ });
444
475
  });
445
476
 
446
477
  describe('#initServiceCatalogs()', () => {
@@ -878,18 +909,22 @@ describe('webex-core', () => {
878
909
  }));
879
910
 
880
911
  it('validates an authorized user and webex instance', () =>
881
- services.validateUser({email: webexUser.email}).then((r) => {
882
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
883
- assert.equal(r.activated, true);
884
- assert.equal(r.exists, true);
885
- }));
912
+ retryOn429(() =>
913
+ services.validateUser({email: webexUser.email}).then((r) => {
914
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
915
+ assert.equal(r.activated, true);
916
+ assert.equal(r.exists, true);
917
+ })
918
+ ));
886
919
 
887
920
  it('validates an authorized EU user and webex instance', () =>
888
- servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
889
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
890
- assert.equal(r.activated, true);
891
- assert.equal(r.exists, true);
892
- }));
921
+ retryOn429(() =>
922
+ servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
923
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
924
+ assert.equal(r.activated, true);
925
+ assert.equal(r.exists, true);
926
+ })
927
+ ));
893
928
 
894
929
  it("returns a rejected promise if the provided email isn't valid", () =>
895
930
  unauthServices
@@ -902,131 +937,152 @@ describe('webex-core', () => {
902
937
  }));
903
938
 
904
939
  it('validates a non-existing user', () =>
905
- unauthServices
906
- .validateUser({email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`})
907
- .then((r) => {
940
+ retryOn429(() =>
941
+ unauthServices.validateUser({email: createActivationEmail()}).then((r) => {
908
942
  assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
909
943
  assert.equal(r.activated, false);
910
944
  assert.equal(r.exists, false);
911
945
  assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
912
946
  assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
913
947
  assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
914
- }));
948
+ })
949
+ ));
915
950
 
916
951
  it('validates new user with activationOptions suppressEmail false', () =>
917
- unauthServices
918
- .validateUser({
919
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
920
- activationOptions: {suppressEmail: false},
921
- })
922
- .then((r) => {
923
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
924
- assert.equal(r.activated, false);
925
- assert.equal(r.exists, false);
926
- assert.equal(r.user.verificationEmailTriggered, true);
927
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
928
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
929
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
930
- }));
952
+ retryOn429(() =>
953
+ unauthServices
954
+ .validateUser({
955
+ email: createActivationEmail(),
956
+ activationOptions: {suppressEmail: false},
957
+ })
958
+ .then((r) => {
959
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
960
+ assert.equal(r.activated, false);
961
+ assert.equal(r.exists, false);
962
+ assert.equal(r.user.verificationEmailTriggered, true);
963
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
964
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
965
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
966
+ })
967
+ ));
931
968
 
932
969
  it('validates new user with activationOptions suppressEmail true', () =>
933
- unauthServices
934
- .validateUser({
935
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
936
- activationOptions: {suppressEmail: true},
937
- })
938
- .then((r) => {
939
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
940
- assert.equal(r.activated, false);
941
- assert.equal(r.exists, false);
942
- assert.equal(r.user.verificationEmailTriggered, false);
943
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
944
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
945
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
946
- }));
970
+ retryOn429(() =>
971
+ unauthServices
972
+ .validateUser({
973
+ email: createActivationEmail(),
974
+ activationOptions: {suppressEmail: true},
975
+ })
976
+ .then((r) => {
977
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
978
+ assert.equal(r.activated, false);
979
+ assert.equal(r.exists, false);
980
+ assert.equal(r.user.verificationEmailTriggered, false);
981
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
982
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
983
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
984
+ })
985
+ ));
947
986
 
948
987
  it('validates an inactive user', () => {
949
988
  const inactive = 'webex.web.client+nonactivated@gmail.com';
950
989
 
951
- return unauthServices
952
- .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
953
- .then((r) => {
990
+ return retryOn429(() =>
991
+ unauthServices
992
+ .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
993
+ .then((r) => {
994
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
995
+ assert.equal(r.activated, false, 'activated');
996
+ assert.equal(r.exists, true, 'exists');
997
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
998
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
999
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
1000
+ })
1001
+ ).catch(() => {
1002
+ assert(true);
1003
+ });
1004
+ });
1005
+
1006
+ it('validates an existing user', () =>
1007
+ retryOn429(() =>
1008
+ unauthServices.validateUser({email: webexUser.email}).then((r) => {
954
1009
  assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
955
- assert.equal(r.activated, false, 'activated');
956
- assert.equal(r.exists, true, 'exists');
1010
+ assert.equal(r.activated, true);
1011
+ assert.equal(r.exists, true);
957
1012
  assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
958
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
1013
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
959
1014
  assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
960
1015
  })
961
- .catch(() => {
962
- assert(true);
963
- });
964
- });
965
-
966
- it('validates an existing user', () =>
967
- unauthServices.validateUser({email: webexUser.email}).then((r) => {
968
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
969
- assert.equal(r.activated, true);
970
- assert.equal(r.exists, true);
971
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
972
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
973
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
974
- }));
1016
+ ));
975
1017
 
976
1018
  it('validates an existing EU user', () =>
977
- unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
978
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
979
- assert.equal(r.activated, true);
980
- assert.equal(r.exists, true);
981
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
982
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
983
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
984
- }));
1019
+ retryOn429(() =>
1020
+ unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
1021
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
1022
+ assert.equal(r.activated, true);
1023
+ assert.equal(r.exists, true);
1024
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
1025
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
1026
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
1027
+ })
1028
+ ));
985
1029
 
986
1030
  it('sends the prelogin user id as undefined when not specified', () => {
987
1031
  const requestStub = sandbox.spy(unauthServices, 'request');
988
1032
 
989
- return unauthServices
990
- .validateUser({
991
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
992
- activationOptions: {suppressEmail: true},
993
- })
994
- .then(() => {
995
- assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
996
- });
1033
+ return retryOn429(() => {
1034
+ requestStub.resetHistory();
1035
+
1036
+ return unauthServices
1037
+ .validateUser({
1038
+ email: createActivationEmail(),
1039
+ activationOptions: {suppressEmail: true},
1040
+ })
1041
+ .then(() => {
1042
+ assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
1043
+ });
1044
+ });
997
1045
  });
998
1046
 
999
1047
  it('sends the prelogin user id as provided when specified', () => {
1000
1048
  const requestStub = sandbox.spy(unauthServices, 'request');
1001
1049
  const preloginUserId = uuid.v4();
1002
1050
 
1003
- return unauthServices
1004
- .validateUser({
1005
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
1006
- activationOptions: {suppressEmail: true},
1007
- preloginUserId,
1008
- })
1009
- .then(() => {
1010
- assert.strictEqual(
1011
- getActivationRequest(requestStub).headers['x-prelogin-userid'],
1012
- preloginUserId
1013
- );
1014
- });
1051
+ return retryOn429(() => {
1052
+ requestStub.resetHistory();
1053
+
1054
+ return unauthServices
1055
+ .validateUser({
1056
+ email: createActivationEmail(),
1057
+ activationOptions: {suppressEmail: true},
1058
+ preloginUserId,
1059
+ })
1060
+ .then(() => {
1061
+ assert.strictEqual(
1062
+ getActivationRequest(requestStub).headers['x-prelogin-userid'],
1063
+ preloginUserId
1064
+ );
1065
+ });
1066
+ });
1015
1067
  });
1016
1068
 
1017
1069
  it('uses the license service by default', () => {
1018
1070
  const requestStub = sandbox.spy(unauthServices, 'request');
1019
1071
 
1020
- return unauthServices
1021
- .validateUser({
1022
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
1023
- activationOptions: {suppressEmail: true},
1024
- })
1025
- .then(() => {
1026
- const request = getActivationRequest(requestStub, false);
1027
- assert.strictEqual(request.service, 'license');
1028
- assert.strictEqual(request.resource, 'users/activations');
1029
- });
1072
+ return retryOn429(() => {
1073
+ requestStub.resetHistory();
1074
+
1075
+ return unauthServices
1076
+ .validateUser({
1077
+ email: createActivationEmail(),
1078
+ activationOptions: {suppressEmail: true},
1079
+ })
1080
+ .then(() => {
1081
+ const request = getActivationRequest(requestStub, false);
1082
+ assert.strictEqual(request.service, 'license');
1083
+ assert.strictEqual(request.resource, 'users/activations');
1084
+ });
1085
+ });
1030
1086
  });
1031
1087
 
1032
1088
  it('uses the user-onboarding service when useUserOnboardingServiceForActivations config is true', () => {
@@ -1040,16 +1096,20 @@ describe('webex-core', () => {
1040
1096
  const userOnboardingServices = userOnboardingWebex.internal.services;
1041
1097
  const requestStub = sandbox.spy(userOnboardingServices, 'request');
1042
1098
 
1043
- return userOnboardingServices
1044
- .validateUser({
1045
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
1046
- activationOptions: {suppressEmail: true},
1047
- })
1048
- .then(() => {
1049
- const request = getActivationRequest(requestStub, true);
1050
- assert.strictEqual(request.service, 'user-onboarding');
1051
- assert.strictEqual(request.resource, 'api/v1/users/activations');
1052
- });
1099
+ return retryOn429(() => {
1100
+ requestStub.resetHistory();
1101
+
1102
+ return userOnboardingServices
1103
+ .validateUser({
1104
+ email: createActivationEmail(),
1105
+ activationOptions: {suppressEmail: true},
1106
+ })
1107
+ .then(() => {
1108
+ const request = getActivationRequest(requestStub, true);
1109
+ assert.strictEqual(request.service, 'user-onboarding');
1110
+ assert.strictEqual(request.resource, 'api/v1/users/activations');
1111
+ });
1112
+ });
1053
1113
  });
1054
1114
  });
1055
1115