@bytescale/sdk 3.56.0 → 3.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3196,11 +3196,12 @@ function AuthManagerBrowser_awaitIgnored(value, direct) {
3196
3196
  return value && value.then ? value.then(AuthManagerBrowser_empty) : Promise.resolve();
3197
3197
  }
3198
3198
  }
3199
- function AuthManagerBrowser_invokeIgnored(body) {
3199
+ function AuthManagerBrowser_invoke(body, then) {
3200
3200
  var result = body();
3201
3201
  if (result && result.then) {
3202
- return result.then(AuthManagerBrowser_empty);
3202
+ return result.then(then);
3203
3203
  }
3204
+ return then(result);
3204
3205
  }
3205
3206
  function AuthManagerBrowser_await(value, then, direct) {
3206
3207
  if (direct) {
@@ -3223,12 +3224,11 @@ function AuthManagerBrowser_async(f) {
3223
3224
  }
3224
3225
  };
3225
3226
  }
3226
- function AuthManagerBrowser_invoke(body, then) {
3227
+ function AuthManagerBrowser_invokeIgnored(body) {
3227
3228
  var result = body();
3228
3229
  if (result && result.then) {
3229
- return result.then(then);
3230
+ return result.then(AuthManagerBrowser_empty);
3230
3231
  }
3231
- return then(result);
3232
3232
  }
3233
3233
  function AuthManagerBrowser_catch(body, recover) {
3234
3234
  try {
@@ -3261,14 +3261,29 @@ function AuthManagerBrowser_continueIgnored(value) {
3261
3261
  return value.then(AuthManagerBrowser_empty);
3262
3262
  }
3263
3263
  }
3264
+ function AuthManagerBrowser_call(body, then, direct) {
3265
+ if (direct) {
3266
+ return then ? then(body()) : body();
3267
+ }
3268
+ try {
3269
+ var result = Promise.resolve(body());
3270
+ return then ? result.then(then) : result;
3271
+ } catch (e) {
3272
+ return Promise.reject(e);
3273
+ }
3274
+ }
3264
3275
  function AuthManagerBrowser_continue(value, then) {
3265
3276
  return value && value.then ? value.then(then) : then(value);
3266
3277
  }
3267
- function AuthManagerBrowser_typeof(o) { "@babel/helpers - typeof"; return AuthManagerBrowser_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AuthManagerBrowser_typeof(o); }
3268
3278
  function AuthManagerBrowser_defineProperty(e, r, t) { return (r = AuthManagerBrowser_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
3269
3279
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = AuthManagerBrowser_unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
3280
+ function AuthManagerBrowser_toConsumableArray(r) { return AuthManagerBrowser_arrayWithoutHoles(r) || AuthManagerBrowser_iterableToArray(r) || AuthManagerBrowser_unsupportedIterableToArray(r) || AuthManagerBrowser_nonIterableSpread(); }
3281
+ function AuthManagerBrowser_nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3270
3282
  function AuthManagerBrowser_unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return AuthManagerBrowser_arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? AuthManagerBrowser_arrayLikeToArray(r, a) : void 0; } }
3283
+ function AuthManagerBrowser_iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
3284
+ function AuthManagerBrowser_arrayWithoutHoles(r) { if (Array.isArray(r)) return AuthManagerBrowser_arrayLikeToArray(r); }
3271
3285
  function AuthManagerBrowser_arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
3286
+ function AuthManagerBrowser_typeof(o) { "@babel/helpers - typeof"; return AuthManagerBrowser_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AuthManagerBrowser_typeof(o); }
3272
3287
  function AuthManagerBrowser_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
3273
3288
  function AuthManagerBrowser_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AuthManagerBrowser_toPropertyKey(o.key), o); } }
3274
3289
  function AuthManagerBrowser_createClass(e, r, t) { return r && AuthManagerBrowser_defineProperties(e.prototype, r), t && AuthManagerBrowser_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
@@ -3302,8 +3317,9 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3302
3317
  }, {
3303
3318
  key: "isAuthSessionReady",
3304
3319
  value: function isAuthSessionReady() {
3320
+ var _a;
3305
3321
  var session = AuthSessionState.getSession();
3306
- return (session === null || session === void 0 ? void 0 : session.isReady) === true || (session === null || session === void 0 ? void 0 : session.accessToken) !== undefined;
3322
+ return (_a = session === null || session === void 0 ? void 0 : session.isReady) !== null && _a !== void 0 ? _a : (session === null || session === void 0 ? void 0 : session.accessToken) !== undefined;
3307
3323
  }
3308
3324
  }, {
3309
3325
  key: "beginAuthSession",
@@ -3316,8 +3332,13 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3316
3332
  throw new Error("Auth session already active. Please call 'await endAuthSession()' and then call 'await beginAuthSession(...)' to start a new auth session.");
3317
3333
  }
3318
3334
  var canUseServiceWorkers = _this.serviceWorkerUtils.canUseServiceWorkers();
3319
- if (_this.isV2(params) && !canUseServiceWorkers) {
3320
- throw new Error("This auth session requires service workers, but this browser does not support them.");
3335
+ if (params.serviceWorkerConfig !== undefined) {
3336
+ if (params.serviceWorkerScript === undefined) {
3337
+ throw new Error("The 'serviceWorkerScript' field is required when 'serviceWorkerConfig' is provided.");
3338
+ }
3339
+ if (!canUseServiceWorkers) {
3340
+ throw new Error("The 'serviceWorkerConfig' field requires service workers, but this browser does not support them.");
3341
+ }
3321
3342
  }
3322
3343
  var newSession = {
3323
3344
  accessToken: undefined,
@@ -3328,18 +3349,21 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3328
3349
  authServiceWorker: params.serviceWorkerScript !== undefined && canUseServiceWorkers ? {
3329
3350
  serviceWorkerScript: params.serviceWorkerScript,
3330
3351
  type: "Uninitialized"
3331
- } : undefined
3352
+ } : undefined,
3353
+ primaryAuthSwConfig: undefined,
3354
+ serviceWorkerConfig: undefined,
3355
+ serviceWorkerConfigRefreshHandle: undefined
3332
3356
  };
3333
3357
  AuthSessionState.setSession(newSession);
3334
3358
  return newSession;
3335
3359
  })), function (session) {
3336
3360
  // IMPORTANT: must be called outside the above, else re-entrant deadlock will occur.
3337
- return AuthManagerBrowser_invokeIgnored(function () {
3338
- if (_this.isV2(session.params)) {
3361
+ return AuthManagerBrowser_invoke(function () {
3362
+ if (session.params.serviceWorkerConfig !== undefined) {
3339
3363
  return AuthManagerBrowser_awaitIgnored(_this.refreshServiceWorkerConfig(session, session.params));
3340
- } else {
3341
- return AuthManagerBrowser_awaitIgnored(_this.refreshAccessToken(session, session.params));
3342
3364
  }
3365
+ }, function () {
3366
+ return AuthManagerBrowser_awaitIgnored(_this.refreshAccessToken(session, session.params));
3343
3367
  });
3344
3368
  });
3345
3369
  } catch (e) {
@@ -3361,8 +3385,13 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3361
3385
  if (session.accessTokenRefreshHandle !== undefined) {
3362
3386
  _this2.scheduler.unschedule(session.accessTokenRefreshHandle);
3363
3387
  }
3388
+ if (session.serviceWorkerConfigRefreshHandle !== undefined) {
3389
+ _this2.scheduler.unschedule(session.serviceWorkerConfigRefreshHandle);
3390
+ }
3391
+ // AuthSessionState is shared between bundled SDK versions. Service-worker-only sessions from 3.56.0 did not
3392
+ // contain an accountId, so allow a newer SDK instance to tear those sessions down without calling this endpoint.
3364
3393
  return AuthManagerBrowser_invoke(function () {
3365
- if (!_this2.isV2(session.params)) {
3394
+ if (typeof session.params.accountId === "string") {
3366
3395
  return AuthManagerBrowser_awaitIgnored(_this2.deleteAccessToken(session.params));
3367
3396
  }
3368
3397
  }, function () {
@@ -3404,21 +3433,24 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3404
3433
  return AuthManagerBrowser_await(_this3.setAccessToken(params, jwt, setCookie), function (setTokenResult) {
3405
3434
  return AuthManagerBrowser_invoke(function () {
3406
3435
  if (session.authServiceWorker !== undefined) {
3407
- return AuthManagerBrowser_await(_this3.sendServiceWorkerConfig(session, [{
3436
+ var primaryAuthSwConfig = {
3408
3437
  headers: [{
3409
3438
  key: "Authorization",
3410
3439
  value: "Bearer ".concat(jwt)
3411
3440
  }],
3412
3441
  expires: secondsFromNow(setTokenResult.ttlSeconds),
3413
- sourceUrlPrefixes: params.sourceUrlPrefixes,
3414
3442
  urlPrefix: "".concat(_this3.getCdnUrl(params), "/").concat(params.accountId, "/")
3415
- }]), function () {
3416
- // Allow time for the service worker to receive and process the message. Since this is asynchronous and not
3417
- // synchronized, we need to wait for a sufficient amount of time to ensure the service worker is ready to
3418
- // authenticate requests, so that after 'beginAuthSession' completes, users can start making requests.
3419
- return AuthManagerBrowser_awaitIgnored(new Promise(function (resolve) {
3420
- return setTimeout(resolve, 100);
3421
- }));
3443
+ };
3444
+ // Fail closed until the initial serviceWorkerConfig callback succeeds: without its result, we do not know
3445
+ // the source-page restrictions intended for the primary JWT.
3446
+ return AuthManagerBrowser_invoke(function () {
3447
+ if (params.serviceWorkerConfig === undefined || session.serviceWorkerConfig !== undefined) {
3448
+ return AuthManagerBrowser_await(_this3.sendMergedServiceWorkerConfig(session, primaryAuthSwConfig, session.serviceWorkerConfig), function () {
3449
+ return AuthManagerBrowser_awaitIgnored(_this3.waitForServiceWorker());
3450
+ });
3451
+ }
3452
+ }, function () {
3453
+ session.primaryAuthSwConfig = primaryAuthSwConfig;
3422
3454
  });
3423
3455
  }
3424
3456
  }, function () {
@@ -3430,7 +3462,7 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3430
3462
  expires = secondsFromNow(actualTtl);
3431
3463
  // Set this at the end, as it's also used to signal 'isAuthSessionReady', so must be set after configuring the Service Worker, etc.
3432
3464
  session.accessToken = setTokenResult.accessToken;
3433
- session.isReady = true;
3465
+ _this3.updateSessionReadiness(session);
3434
3466
  });
3435
3467
  });
3436
3468
  });
@@ -3461,6 +3493,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3461
3493
  value: function refreshServiceWorkerConfig(session, params) {
3462
3494
  try {
3463
3495
  var _this4 = this;
3496
+ var getServiceWorkerConfig = params.serviceWorkerConfig;
3497
+ if (getServiceWorkerConfig === undefined) {
3498
+ return AuthManagerBrowser_await();
3499
+ }
3464
3500
  return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(_this4.authSessionMutex.safe(AuthManagerBrowser_async(function () {
3465
3501
  var _exit = false;
3466
3502
  if (!session.isActive) {
@@ -3468,17 +3504,29 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3468
3504
  }
3469
3505
  var refreshAt;
3470
3506
  return AuthManagerBrowser_continue(AuthManagerBrowser_catch(function () {
3471
- return AuthManagerBrowser_await(params.getServiceWorkerConfig(), function (config) {
3472
- if (!Array.isArray(config)) {
3473
- throw new Error("The 'getServiceWorkerConfig' callback must return an array.");
3507
+ return AuthManagerBrowser_call(getServiceWorkerConfig, function (result) {
3508
+ if (result === null || AuthManagerBrowser_typeof(result) !== "object" || !Array.isArray(result.additionalConfig)) {
3509
+ throw new Error("The 'serviceWorkerConfig' callback must return an object containing 'additionalConfig'.");
3474
3510
  }
3475
- return AuthManagerBrowser_await(_this4.sendServiceWorkerConfig(session, config), function () {
3476
- return AuthManagerBrowser_await(new Promise(function (resolve) {
3477
- return setTimeout(resolve, 100);
3478
- }), function () {
3479
- session.isReady = true;
3480
- refreshAt = _this4.getServiceWorkerConfigRefreshEpoch(config);
3481
- });
3511
+ if (result.sourceUrlPrefixes !== undefined && (!Array.isArray(result.sourceUrlPrefixes) || !result.sourceUrlPrefixes.every(function (prefix) {
3512
+ return typeof prefix === "string";
3513
+ }))) {
3514
+ throw new Error("The 'sourceUrlPrefixes' field returned by 'serviceWorkerConfig' must be an array of strings.");
3515
+ }
3516
+ var config = {
3517
+ additionalConfig: result.additionalConfig,
3518
+ sourceUrlPrefixes: result.sourceUrlPrefixes
3519
+ };
3520
+ return AuthManagerBrowser_invoke(function () {
3521
+ if (session.primaryAuthSwConfig !== undefined) {
3522
+ return AuthManagerBrowser_await(_this4.sendMergedServiceWorkerConfig(session, session.primaryAuthSwConfig, config), function () {
3523
+ return AuthManagerBrowser_awaitIgnored(_this4.waitForServiceWorker());
3524
+ });
3525
+ }
3526
+ }, function () {
3527
+ session.serviceWorkerConfig = config;
3528
+ _this4.updateSessionReadiness(session);
3529
+ refreshAt = _this4.getServiceWorkerConfigRefreshEpoch(config.additionalConfig);
3482
3530
  });
3483
3531
  });
3484
3532
  }, function (e) {
@@ -3487,7 +3535,7 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3487
3535
  }), function (_result2) {
3488
3536
  if (_exit) return _result2;
3489
3537
  if (refreshAt !== undefined) {
3490
- session.accessTokenRefreshHandle = _this4.scheduler.schedule(refreshAt, function () {
3538
+ session.serviceWorkerConfigRefreshHandle = _this4.scheduler.schedule(refreshAt, function () {
3491
3539
  _this4.refreshServiceWorkerConfig(session, params).then(function () {}, function (e) {
3492
3540
  return ConsoleUtils.error("Unexpected error when refreshing service worker auth config: ".concat(e));
3493
3541
  });
@@ -3499,6 +3547,19 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3499
3547
  return Promise.reject(e);
3500
3548
  }
3501
3549
  }
3550
+ }, {
3551
+ key: "sendMergedServiceWorkerConfig",
3552
+ value: function sendMergedServiceWorkerConfig(session, primaryConfig, serviceWorkerConfig) {
3553
+ try {
3554
+ var _this5 = this;
3555
+ var _a;
3556
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(_this5.sendServiceWorkerConfig(session, [Object.assign(Object.assign({}, primaryConfig), {
3557
+ sourceUrlPrefixes: serviceWorkerConfig === null || serviceWorkerConfig === void 0 ? void 0 : serviceWorkerConfig.sourceUrlPrefixes
3558
+ })].concat(AuthManagerBrowser_toConsumableArray((_a = serviceWorkerConfig === null || serviceWorkerConfig === void 0 ? void 0 : serviceWorkerConfig.additionalConfig) !== null && _a !== void 0 ? _a : [])))));
3559
+ } catch (e) {
3560
+ return Promise.reject(e);
3561
+ }
3562
+ }
3502
3563
  }, {
3503
3564
  key: "getServiceWorkerConfigRefreshEpoch",
3504
3565
  value: function getServiceWorkerConfigRefreshEpoch(config) {
@@ -3523,24 +3584,42 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3523
3584
  key: "sendServiceWorkerConfig",
3524
3585
  value: function sendServiceWorkerConfig(session, config) {
3525
3586
  try {
3526
- var _this5 = this;
3587
+ var _this6 = this;
3527
3588
  if (session.authServiceWorker === undefined) {
3528
3589
  throw new Error("Service worker configuration cannot be applied because service workers are unavailable.");
3529
3590
  }
3530
- return AuthManagerBrowser_await(_this5.serviceWorkerUtils.sendMessage({
3591
+ return AuthManagerBrowser_await(_this6.serviceWorkerUtils.sendMessage({
3531
3592
  type: "SET_BYTESCALE_AUTH_CONFIG",
3532
3593
  config: config.map(function (entry) {
3533
3594
  return Object.assign(Object.assign({}, entry), {
3534
- urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this5.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
3595
+ urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this6.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
3535
3596
  });
3536
3597
  })
3537
- }, session.authServiceWorker, _this5.serviceWorkerScriptFieldName), function (_this5$serviceWorkerU) {
3538
- session.authServiceWorker = _this5$serviceWorkerU;
3598
+ }, session.authServiceWorker, _this6.serviceWorkerScriptFieldName), function (_this6$serviceWorkerU) {
3599
+ session.authServiceWorker = _this6$serviceWorkerU;
3539
3600
  });
3540
3601
  } catch (e) {
3541
3602
  return Promise.reject(e);
3542
3603
  }
3543
3604
  }
3605
+ }, {
3606
+ key: "updateSessionReadiness",
3607
+ value: function updateSessionReadiness(session) {
3608
+ session.isReady = session.accessToken !== undefined && (session.params.serviceWorkerConfig === undefined || session.serviceWorkerConfig !== undefined);
3609
+ }
3610
+ }, {
3611
+ key: "waitForServiceWorker",
3612
+ value: function waitForServiceWorker() {
3613
+ try {
3614
+ // Message delivery is asynchronous and has no acknowledgement, so allow the worker time to apply the config before
3615
+ // beginAuthSession reports that authenticated requests are ready.
3616
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(new Promise(function (resolve) {
3617
+ return setTimeout(resolve, 100);
3618
+ })));
3619
+ } catch (e) {
3620
+ return Promise.reject(e);
3621
+ }
3622
+ }
3544
3623
  }, {
3545
3624
  key: "getAccessTokenUrl",
3546
3625
  value: function getAccessTokenUrl(params, setCookie) {
@@ -3556,9 +3635,9 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3556
3635
  key: "deleteAccessToken",
3557
3636
  value: function deleteAccessToken(params) {
3558
3637
  try {
3559
- var _this6 = this;
3638
+ var _this7 = this;
3560
3639
  var _a;
3561
- return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(_this6.getAccessTokenUrl(params, true), {
3640
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(_this7.getAccessTokenUrl(params, true), {
3562
3641
  method: "DELETE",
3563
3642
  credentials: "include",
3564
3643
  headers: {}
@@ -3574,15 +3653,15 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3574
3653
  key: "setAccessToken",
3575
3654
  value: function setAccessToken(params, jwt, setCookie) {
3576
3655
  try {
3577
- var _this7 = this;
3656
+ var _this8 = this;
3578
3657
  var _a;
3579
3658
  var request = {
3580
3659
  accessToken: jwt
3581
3660
  };
3582
- return AuthManagerBrowser_await(BaseAPI.fetch(_this7.getAccessTokenUrl(params, setCookie), {
3661
+ return AuthManagerBrowser_await(BaseAPI.fetch(_this8.getAccessTokenUrl(params, setCookie), {
3583
3662
  method: "PUT",
3584
3663
  credentials: "include",
3585
- headers: AuthManagerBrowser_defineProperty({}, _this7.contentType, _this7.contentTypeJson),
3664
+ headers: AuthManagerBrowser_defineProperty({}, _this8.contentType, _this8.contentTypeJson),
3586
3665
  body: JSON.stringify(request)
3587
3666
  }, {
3588
3667
  isBytescaleApi: true,
@@ -3598,10 +3677,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3598
3677
  key: "getAccessToken",
3599
3678
  value: function getAccessToken(params, headers) {
3600
3679
  try {
3601
- var _this8 = this;
3680
+ var _this9 = this;
3602
3681
  var _a, _b;
3603
3682
  var endpointName = "Your auth API endpoint";
3604
- var requiredContentType = _this8.contentTypeText;
3683
+ var requiredContentType = _this9.contentTypeText;
3605
3684
  return AuthManagerBrowser_await(BaseAPI.fetch(params.authUrl, {
3606
3685
  method: "GET",
3607
3686
  headers: headers
@@ -3609,10 +3688,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3609
3688
  isBytescaleApi: false,
3610
3689
  fetchApi: (_a = params.options) === null || _a === void 0 ? void 0 : _a.fetchApi
3611
3690
  }), function (result) {
3612
- var actualContentType = (_b = result.headers.get(_this8.contentType)) !== null && _b !== void 0 ? _b : "";
3691
+ var actualContentType = (_b = result.headers.get(_this9.contentType)) !== null && _b !== void 0 ? _b : "";
3613
3692
  // Support content types like "text/plain; charset=utf-8" and "text/plain"
3614
3693
  if (actualContentType.split(";")[0] !== requiredContentType) {
3615
- throw new Error("".concat(endpointName, " returned \"").concat(actualContentType, "\" for the ").concat(_this8.contentType, " response header, but the Bytescale SDK requires \"").concat(requiredContentType, "\"."));
3694
+ throw new Error("".concat(endpointName, " returned \"").concat(actualContentType, "\" for the ").concat(_this9.contentType, " response header, but the Bytescale SDK requires \"").concat(requiredContentType, "\"."));
3616
3695
  }
3617
3696
  return AuthManagerBrowser_await(result.text(), function (jwt) {
3618
3697
  if (jwt.length === 0) {
@@ -3629,11 +3708,6 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3629
3708
  return Promise.reject(e);
3630
3709
  }
3631
3710
  }
3632
- }, {
3633
- key: "isV2",
3634
- value: function isV2(params) {
3635
- return "getServiceWorkerConfig" in params;
3636
- }
3637
3711
  }]);
3638
3712
  }();
3639
3713
  /**
@@ -3156,11 +3156,12 @@ function AuthManagerBrowser_awaitIgnored(value, direct) {
3156
3156
  return value && value.then ? value.then(AuthManagerBrowser_empty) : Promise.resolve();
3157
3157
  }
3158
3158
  }
3159
- function AuthManagerBrowser_invokeIgnored(body) {
3159
+ function AuthManagerBrowser_invoke(body, then) {
3160
3160
  var result = body();
3161
3161
  if (result && result.then) {
3162
- return result.then(AuthManagerBrowser_empty);
3162
+ return result.then(then);
3163
3163
  }
3164
+ return then(result);
3164
3165
  }
3165
3166
  function AuthManagerBrowser_await(value, then, direct) {
3166
3167
  if (direct) {
@@ -3183,12 +3184,11 @@ function AuthManagerBrowser_async(f) {
3183
3184
  }
3184
3185
  };
3185
3186
  }
3186
- function AuthManagerBrowser_invoke(body, then) {
3187
+ function AuthManagerBrowser_invokeIgnored(body) {
3187
3188
  var result = body();
3188
3189
  if (result && result.then) {
3189
- return result.then(then);
3190
+ return result.then(AuthManagerBrowser_empty);
3190
3191
  }
3191
- return then(result);
3192
3192
  }
3193
3193
  function AuthManagerBrowser_catch(body, recover) {
3194
3194
  try {
@@ -3221,14 +3221,29 @@ function AuthManagerBrowser_continueIgnored(value) {
3221
3221
  return value.then(AuthManagerBrowser_empty);
3222
3222
  }
3223
3223
  }
3224
+ function AuthManagerBrowser_call(body, then, direct) {
3225
+ if (direct) {
3226
+ return then ? then(body()) : body();
3227
+ }
3228
+ try {
3229
+ var result = Promise.resolve(body());
3230
+ return then ? result.then(then) : result;
3231
+ } catch (e) {
3232
+ return Promise.reject(e);
3233
+ }
3234
+ }
3224
3235
  function AuthManagerBrowser_continue(value, then) {
3225
3236
  return value && value.then ? value.then(then) : then(value);
3226
3237
  }
3227
- function AuthManagerBrowser_typeof(o) { "@babel/helpers - typeof"; return AuthManagerBrowser_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AuthManagerBrowser_typeof(o); }
3228
3238
  function AuthManagerBrowser_defineProperty(e, r, t) { return (r = AuthManagerBrowser_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
3229
3239
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = AuthManagerBrowser_unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
3240
+ function AuthManagerBrowser_toConsumableArray(r) { return AuthManagerBrowser_arrayWithoutHoles(r) || AuthManagerBrowser_iterableToArray(r) || AuthManagerBrowser_unsupportedIterableToArray(r) || AuthManagerBrowser_nonIterableSpread(); }
3241
+ function AuthManagerBrowser_nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3230
3242
  function AuthManagerBrowser_unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return AuthManagerBrowser_arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? AuthManagerBrowser_arrayLikeToArray(r, a) : void 0; } }
3243
+ function AuthManagerBrowser_iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
3244
+ function AuthManagerBrowser_arrayWithoutHoles(r) { if (Array.isArray(r)) return AuthManagerBrowser_arrayLikeToArray(r); }
3231
3245
  function AuthManagerBrowser_arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
3246
+ function AuthManagerBrowser_typeof(o) { "@babel/helpers - typeof"; return AuthManagerBrowser_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AuthManagerBrowser_typeof(o); }
3232
3247
  function AuthManagerBrowser_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
3233
3248
  function AuthManagerBrowser_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AuthManagerBrowser_toPropertyKey(o.key), o); } }
3234
3249
  function AuthManagerBrowser_createClass(e, r, t) { return r && AuthManagerBrowser_defineProperties(e.prototype, r), t && AuthManagerBrowser_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
@@ -3262,8 +3277,9 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3262
3277
  }, {
3263
3278
  key: "isAuthSessionReady",
3264
3279
  value: function isAuthSessionReady() {
3280
+ var _a;
3265
3281
  var session = AuthSessionState.getSession();
3266
- return (session === null || session === void 0 ? void 0 : session.isReady) === true || (session === null || session === void 0 ? void 0 : session.accessToken) !== undefined;
3282
+ return (_a = session === null || session === void 0 ? void 0 : session.isReady) !== null && _a !== void 0 ? _a : (session === null || session === void 0 ? void 0 : session.accessToken) !== undefined;
3267
3283
  }
3268
3284
  }, {
3269
3285
  key: "beginAuthSession",
@@ -3276,8 +3292,13 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3276
3292
  throw new Error("Auth session already active. Please call 'await endAuthSession()' and then call 'await beginAuthSession(...)' to start a new auth session.");
3277
3293
  }
3278
3294
  var canUseServiceWorkers = _this.serviceWorkerUtils.canUseServiceWorkers();
3279
- if (_this.isV2(params) && !canUseServiceWorkers) {
3280
- throw new Error("This auth session requires service workers, but this browser does not support them.");
3295
+ if (params.serviceWorkerConfig !== undefined) {
3296
+ if (params.serviceWorkerScript === undefined) {
3297
+ throw new Error("The 'serviceWorkerScript' field is required when 'serviceWorkerConfig' is provided.");
3298
+ }
3299
+ if (!canUseServiceWorkers) {
3300
+ throw new Error("The 'serviceWorkerConfig' field requires service workers, but this browser does not support them.");
3301
+ }
3281
3302
  }
3282
3303
  var newSession = {
3283
3304
  accessToken: undefined,
@@ -3288,18 +3309,21 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3288
3309
  authServiceWorker: params.serviceWorkerScript !== undefined && canUseServiceWorkers ? {
3289
3310
  serviceWorkerScript: params.serviceWorkerScript,
3290
3311
  type: "Uninitialized"
3291
- } : undefined
3312
+ } : undefined,
3313
+ primaryAuthSwConfig: undefined,
3314
+ serviceWorkerConfig: undefined,
3315
+ serviceWorkerConfigRefreshHandle: undefined
3292
3316
  };
3293
3317
  AuthSessionState.setSession(newSession);
3294
3318
  return newSession;
3295
3319
  })), function (session) {
3296
3320
  // IMPORTANT: must be called outside the above, else re-entrant deadlock will occur.
3297
- return AuthManagerBrowser_invokeIgnored(function () {
3298
- if (_this.isV2(session.params)) {
3321
+ return AuthManagerBrowser_invoke(function () {
3322
+ if (session.params.serviceWorkerConfig !== undefined) {
3299
3323
  return AuthManagerBrowser_awaitIgnored(_this.refreshServiceWorkerConfig(session, session.params));
3300
- } else {
3301
- return AuthManagerBrowser_awaitIgnored(_this.refreshAccessToken(session, session.params));
3302
3324
  }
3325
+ }, function () {
3326
+ return AuthManagerBrowser_awaitIgnored(_this.refreshAccessToken(session, session.params));
3303
3327
  });
3304
3328
  });
3305
3329
  } catch (e) {
@@ -3321,8 +3345,13 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3321
3345
  if (session.accessTokenRefreshHandle !== undefined) {
3322
3346
  _this2.scheduler.unschedule(session.accessTokenRefreshHandle);
3323
3347
  }
3348
+ if (session.serviceWorkerConfigRefreshHandle !== undefined) {
3349
+ _this2.scheduler.unschedule(session.serviceWorkerConfigRefreshHandle);
3350
+ }
3351
+ // AuthSessionState is shared between bundled SDK versions. Service-worker-only sessions from 3.56.0 did not
3352
+ // contain an accountId, so allow a newer SDK instance to tear those sessions down without calling this endpoint.
3324
3353
  return AuthManagerBrowser_invoke(function () {
3325
- if (!_this2.isV2(session.params)) {
3354
+ if (typeof session.params.accountId === "string") {
3326
3355
  return AuthManagerBrowser_awaitIgnored(_this2.deleteAccessToken(session.params));
3327
3356
  }
3328
3357
  }, function () {
@@ -3364,21 +3393,24 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3364
3393
  return AuthManagerBrowser_await(_this3.setAccessToken(params, jwt, setCookie), function (setTokenResult) {
3365
3394
  return AuthManagerBrowser_invoke(function () {
3366
3395
  if (session.authServiceWorker !== undefined) {
3367
- return AuthManagerBrowser_await(_this3.sendServiceWorkerConfig(session, [{
3396
+ var primaryAuthSwConfig = {
3368
3397
  headers: [{
3369
3398
  key: "Authorization",
3370
3399
  value: "Bearer ".concat(jwt)
3371
3400
  }],
3372
3401
  expires: secondsFromNow(setTokenResult.ttlSeconds),
3373
- sourceUrlPrefixes: params.sourceUrlPrefixes,
3374
3402
  urlPrefix: "".concat(_this3.getCdnUrl(params), "/").concat(params.accountId, "/")
3375
- }]), function () {
3376
- // Allow time for the service worker to receive and process the message. Since this is asynchronous and not
3377
- // synchronized, we need to wait for a sufficient amount of time to ensure the service worker is ready to
3378
- // authenticate requests, so that after 'beginAuthSession' completes, users can start making requests.
3379
- return AuthManagerBrowser_awaitIgnored(new Promise(function (resolve) {
3380
- return setTimeout(resolve, 100);
3381
- }));
3403
+ };
3404
+ // Fail closed until the initial serviceWorkerConfig callback succeeds: without its result, we do not know
3405
+ // the source-page restrictions intended for the primary JWT.
3406
+ return AuthManagerBrowser_invoke(function () {
3407
+ if (params.serviceWorkerConfig === undefined || session.serviceWorkerConfig !== undefined) {
3408
+ return AuthManagerBrowser_await(_this3.sendMergedServiceWorkerConfig(session, primaryAuthSwConfig, session.serviceWorkerConfig), function () {
3409
+ return AuthManagerBrowser_awaitIgnored(_this3.waitForServiceWorker());
3410
+ });
3411
+ }
3412
+ }, function () {
3413
+ session.primaryAuthSwConfig = primaryAuthSwConfig;
3382
3414
  });
3383
3415
  }
3384
3416
  }, function () {
@@ -3390,7 +3422,7 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3390
3422
  expires = secondsFromNow(actualTtl);
3391
3423
  // Set this at the end, as it's also used to signal 'isAuthSessionReady', so must be set after configuring the Service Worker, etc.
3392
3424
  session.accessToken = setTokenResult.accessToken;
3393
- session.isReady = true;
3425
+ _this3.updateSessionReadiness(session);
3394
3426
  });
3395
3427
  });
3396
3428
  });
@@ -3421,6 +3453,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3421
3453
  value: function refreshServiceWorkerConfig(session, params) {
3422
3454
  try {
3423
3455
  var _this4 = this;
3456
+ var getServiceWorkerConfig = params.serviceWorkerConfig;
3457
+ if (getServiceWorkerConfig === undefined) {
3458
+ return AuthManagerBrowser_await();
3459
+ }
3424
3460
  return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(_this4.authSessionMutex.safe(AuthManagerBrowser_async(function () {
3425
3461
  var _exit = false;
3426
3462
  if (!session.isActive) {
@@ -3428,17 +3464,29 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3428
3464
  }
3429
3465
  var refreshAt;
3430
3466
  return AuthManagerBrowser_continue(AuthManagerBrowser_catch(function () {
3431
- return AuthManagerBrowser_await(params.getServiceWorkerConfig(), function (config) {
3432
- if (!Array.isArray(config)) {
3433
- throw new Error("The 'getServiceWorkerConfig' callback must return an array.");
3467
+ return AuthManagerBrowser_call(getServiceWorkerConfig, function (result) {
3468
+ if (result === null || AuthManagerBrowser_typeof(result) !== "object" || !Array.isArray(result.additionalConfig)) {
3469
+ throw new Error("The 'serviceWorkerConfig' callback must return an object containing 'additionalConfig'.");
3434
3470
  }
3435
- return AuthManagerBrowser_await(_this4.sendServiceWorkerConfig(session, config), function () {
3436
- return AuthManagerBrowser_await(new Promise(function (resolve) {
3437
- return setTimeout(resolve, 100);
3438
- }), function () {
3439
- session.isReady = true;
3440
- refreshAt = _this4.getServiceWorkerConfigRefreshEpoch(config);
3441
- });
3471
+ if (result.sourceUrlPrefixes !== undefined && (!Array.isArray(result.sourceUrlPrefixes) || !result.sourceUrlPrefixes.every(function (prefix) {
3472
+ return typeof prefix === "string";
3473
+ }))) {
3474
+ throw new Error("The 'sourceUrlPrefixes' field returned by 'serviceWorkerConfig' must be an array of strings.");
3475
+ }
3476
+ var config = {
3477
+ additionalConfig: result.additionalConfig,
3478
+ sourceUrlPrefixes: result.sourceUrlPrefixes
3479
+ };
3480
+ return AuthManagerBrowser_invoke(function () {
3481
+ if (session.primaryAuthSwConfig !== undefined) {
3482
+ return AuthManagerBrowser_await(_this4.sendMergedServiceWorkerConfig(session, session.primaryAuthSwConfig, config), function () {
3483
+ return AuthManagerBrowser_awaitIgnored(_this4.waitForServiceWorker());
3484
+ });
3485
+ }
3486
+ }, function () {
3487
+ session.serviceWorkerConfig = config;
3488
+ _this4.updateSessionReadiness(session);
3489
+ refreshAt = _this4.getServiceWorkerConfigRefreshEpoch(config.additionalConfig);
3442
3490
  });
3443
3491
  });
3444
3492
  }, function (e) {
@@ -3447,7 +3495,7 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3447
3495
  }), function (_result2) {
3448
3496
  if (_exit) return _result2;
3449
3497
  if (refreshAt !== undefined) {
3450
- session.accessTokenRefreshHandle = _this4.scheduler.schedule(refreshAt, function () {
3498
+ session.serviceWorkerConfigRefreshHandle = _this4.scheduler.schedule(refreshAt, function () {
3451
3499
  _this4.refreshServiceWorkerConfig(session, params).then(function () {}, function (e) {
3452
3500
  return ConsoleUtils.error("Unexpected error when refreshing service worker auth config: ".concat(e));
3453
3501
  });
@@ -3459,6 +3507,19 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3459
3507
  return Promise.reject(e);
3460
3508
  }
3461
3509
  }
3510
+ }, {
3511
+ key: "sendMergedServiceWorkerConfig",
3512
+ value: function sendMergedServiceWorkerConfig(session, primaryConfig, serviceWorkerConfig) {
3513
+ try {
3514
+ var _this5 = this;
3515
+ var _a;
3516
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(_this5.sendServiceWorkerConfig(session, [Object.assign(Object.assign({}, primaryConfig), {
3517
+ sourceUrlPrefixes: serviceWorkerConfig === null || serviceWorkerConfig === void 0 ? void 0 : serviceWorkerConfig.sourceUrlPrefixes
3518
+ })].concat(AuthManagerBrowser_toConsumableArray((_a = serviceWorkerConfig === null || serviceWorkerConfig === void 0 ? void 0 : serviceWorkerConfig.additionalConfig) !== null && _a !== void 0 ? _a : [])))));
3519
+ } catch (e) {
3520
+ return Promise.reject(e);
3521
+ }
3522
+ }
3462
3523
  }, {
3463
3524
  key: "getServiceWorkerConfigRefreshEpoch",
3464
3525
  value: function getServiceWorkerConfigRefreshEpoch(config) {
@@ -3483,24 +3544,42 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3483
3544
  key: "sendServiceWorkerConfig",
3484
3545
  value: function sendServiceWorkerConfig(session, config) {
3485
3546
  try {
3486
- var _this5 = this;
3547
+ var _this6 = this;
3487
3548
  if (session.authServiceWorker === undefined) {
3488
3549
  throw new Error("Service worker configuration cannot be applied because service workers are unavailable.");
3489
3550
  }
3490
- return AuthManagerBrowser_await(_this5.serviceWorkerUtils.sendMessage({
3551
+ return AuthManagerBrowser_await(_this6.serviceWorkerUtils.sendMessage({
3491
3552
  type: "SET_BYTESCALE_AUTH_CONFIG",
3492
3553
  config: config.map(function (entry) {
3493
3554
  return Object.assign(Object.assign({}, entry), {
3494
- urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this5.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
3555
+ urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this6.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
3495
3556
  });
3496
3557
  })
3497
- }, session.authServiceWorker, _this5.serviceWorkerScriptFieldName), function (_this5$serviceWorkerU) {
3498
- session.authServiceWorker = _this5$serviceWorkerU;
3558
+ }, session.authServiceWorker, _this6.serviceWorkerScriptFieldName), function (_this6$serviceWorkerU) {
3559
+ session.authServiceWorker = _this6$serviceWorkerU;
3499
3560
  });
3500
3561
  } catch (e) {
3501
3562
  return Promise.reject(e);
3502
3563
  }
3503
3564
  }
3565
+ }, {
3566
+ key: "updateSessionReadiness",
3567
+ value: function updateSessionReadiness(session) {
3568
+ session.isReady = session.accessToken !== undefined && (session.params.serviceWorkerConfig === undefined || session.serviceWorkerConfig !== undefined);
3569
+ }
3570
+ }, {
3571
+ key: "waitForServiceWorker",
3572
+ value: function waitForServiceWorker() {
3573
+ try {
3574
+ // Message delivery is asynchronous and has no acknowledgement, so allow the worker time to apply the config before
3575
+ // beginAuthSession reports that authenticated requests are ready.
3576
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(new Promise(function (resolve) {
3577
+ return setTimeout(resolve, 100);
3578
+ })));
3579
+ } catch (e) {
3580
+ return Promise.reject(e);
3581
+ }
3582
+ }
3504
3583
  }, {
3505
3584
  key: "getAccessTokenUrl",
3506
3585
  value: function getAccessTokenUrl(params, setCookie) {
@@ -3516,9 +3595,9 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3516
3595
  key: "deleteAccessToken",
3517
3596
  value: function deleteAccessToken(params) {
3518
3597
  try {
3519
- var _this6 = this;
3598
+ var _this7 = this;
3520
3599
  var _a;
3521
- return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(_this6.getAccessTokenUrl(params, true), {
3600
+ return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(_this7.getAccessTokenUrl(params, true), {
3522
3601
  method: "DELETE",
3523
3602
  credentials: "include",
3524
3603
  headers: {}
@@ -3534,15 +3613,15 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3534
3613
  key: "setAccessToken",
3535
3614
  value: function setAccessToken(params, jwt, setCookie) {
3536
3615
  try {
3537
- var _this7 = this;
3616
+ var _this8 = this;
3538
3617
  var _a;
3539
3618
  var request = {
3540
3619
  accessToken: jwt
3541
3620
  };
3542
- return AuthManagerBrowser_await(BaseAPI.fetch(_this7.getAccessTokenUrl(params, setCookie), {
3621
+ return AuthManagerBrowser_await(BaseAPI.fetch(_this8.getAccessTokenUrl(params, setCookie), {
3543
3622
  method: "PUT",
3544
3623
  credentials: "include",
3545
- headers: AuthManagerBrowser_defineProperty({}, _this7.contentType, _this7.contentTypeJson),
3624
+ headers: AuthManagerBrowser_defineProperty({}, _this8.contentType, _this8.contentTypeJson),
3546
3625
  body: JSON.stringify(request)
3547
3626
  }, {
3548
3627
  isBytescaleApi: true,
@@ -3558,10 +3637,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3558
3637
  key: "getAccessToken",
3559
3638
  value: function getAccessToken(params, headers) {
3560
3639
  try {
3561
- var _this8 = this;
3640
+ var _this9 = this;
3562
3641
  var _a, _b;
3563
3642
  var endpointName = "Your auth API endpoint";
3564
- var requiredContentType = _this8.contentTypeText;
3643
+ var requiredContentType = _this9.contentTypeText;
3565
3644
  return AuthManagerBrowser_await(BaseAPI.fetch(params.authUrl, {
3566
3645
  method: "GET",
3567
3646
  headers: headers
@@ -3569,10 +3648,10 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3569
3648
  isBytescaleApi: false,
3570
3649
  fetchApi: (_a = params.options) === null || _a === void 0 ? void 0 : _a.fetchApi
3571
3650
  }), function (result) {
3572
- var actualContentType = (_b = result.headers.get(_this8.contentType)) !== null && _b !== void 0 ? _b : "";
3651
+ var actualContentType = (_b = result.headers.get(_this9.contentType)) !== null && _b !== void 0 ? _b : "";
3573
3652
  // Support content types like "text/plain; charset=utf-8" and "text/plain"
3574
3653
  if (actualContentType.split(";")[0] !== requiredContentType) {
3575
- throw new Error("".concat(endpointName, " returned \"").concat(actualContentType, "\" for the ").concat(_this8.contentType, " response header, but the Bytescale SDK requires \"").concat(requiredContentType, "\"."));
3654
+ throw new Error("".concat(endpointName, " returned \"").concat(actualContentType, "\" for the ").concat(_this9.contentType, " response header, but the Bytescale SDK requires \"").concat(requiredContentType, "\"."));
3576
3655
  }
3577
3656
  return AuthManagerBrowser_await(result.text(), function (jwt) {
3578
3657
  if (jwt.length === 0) {
@@ -3589,11 +3668,6 @@ var AuthManagerImpl = /*#__PURE__*/function () {
3589
3668
  return Promise.reject(e);
3590
3669
  }
3591
3670
  }
3592
- }, {
3593
- key: "isV2",
3594
- value: function isV2(params) {
3595
- return "getServiceWorkerConfig" in params;
3596
- }
3597
3671
  }]);
3598
3672
  }();
3599
3673
  /**
@@ -1,7 +1,19 @@
1
1
  import { BytescaleApiClientConfig } from "../../public/shared";
2
2
  import { AuthSwConfigEntryDto } from "../dtos/AuthSwConfigEntryDto";
3
- export type BeginAuthSessionParams = BeginAuthSessionParamsV1 | BeginAuthSessionParamsV2;
4
- export interface BeginAuthSessionParamsV1 {
3
+ export interface AuthManagerServiceWorkerConfig {
4
+ /**
5
+ * Additional download-only service-worker authorization rules.
6
+ * An empty array clears all additional rules.
7
+ */
8
+ additionalConfig: AuthSwConfigEntryDto[];
9
+ /**
10
+ * Restricts the primary JWT to pages and iframes whose URL starts with one of these prefixes.
11
+ * An empty array matches no clients. Omit this field to preserve the existing service-worker behavior.
12
+ * History API changes do not update the matched client URL.
13
+ */
14
+ sourceUrlPrefixes?: string[];
15
+ }
16
+ export interface BeginAuthSessionParams {
5
17
  /**
6
18
  * The account ID to authorize requests for.
7
19
  */
@@ -20,6 +32,18 @@ export interface BeginAuthSessionParamsV1 {
20
32
  * Optional configuration.
21
33
  */
22
34
  options?: Pick<BytescaleApiClientConfig, "fetchApi" | "cdnUrl">;
35
+ /**
36
+ * Returns configuration for service-worker authorization. The primary JWT returned by `authUrl` is restricted using
37
+ * `sourceUrlPrefixes`; `additionalConfig` contains download-only rules and never authenticates SDK API operations.
38
+ * Called when the session begins and again 20 seconds before the earliest additional entry expires. Entries without
39
+ * an expiry do not trigger a refresh.
40
+ *
41
+ * Requires `serviceWorkerScript` and browser service-worker support. Additional rules cannot use the CDN cookie
42
+ * fallback.
43
+ *
44
+ * IMPORTANT: do not call 'AuthManager.beginAuthSession' or 'AuthManager.endAuthSession' inside this callback, as this will cause a deadlock.
45
+ */
46
+ serviceWorkerConfig?: () => Promise<AuthManagerServiceWorkerConfig>;
23
47
  /**
24
48
  * Enables support for modern browsers that block third-party cookies (like Safari).
25
49
  *
@@ -66,35 +90,13 @@ export interface BeginAuthSessionParamsV1 {
66
90
  * script must be hosted on your website's domain in the root directory.
67
91
  */
68
92
  serviceWorkerScript?: string;
69
- /**
70
- * Restricts service-worker authorization to pages and iframes whose URL starts with one of these prefixes.
71
- * An empty array matches no clients. Omit this field to preserve the existing service-worker behavior.
72
- * Applies only with `serviceWorkerScript`; History API changes do not update the matched client URL.
73
- */
74
- sourceUrlPrefixes?: string[];
75
- }
76
- export interface BeginAuthSessionParamsV2 {
77
- /**
78
- * Returns the complete replacement service-worker authorization config. Called when the session begins and again
79
- * 20 seconds before the earliest configured expiry. Entries without an expiry do not trigger a refresh.
80
- *
81
- * IMPORTANT: do not call 'AuthManager.beginAuthSession' or 'AuthManager.endAuthSession' inside this callback, as this will cause a deadlock.
82
- */
83
- getServiceWorkerConfig: () => Promise<AuthSwConfigEntryDto[]>;
84
- /**
85
- * The path to the service worker JavaScript file hosted at the root of your website.
86
- *
87
- * Unlike V1 sessions, V2 sessions require service-worker support and do not create an SDK API access token or use
88
- * CDN cookies as a fallback.
89
- */
90
- serviceWorkerScript: string;
91
93
  }
92
94
  export interface AuthManagerInterface {
93
95
  /**
94
96
  * Begins a JWT auth session with the Bytescale API and Bytescale CDN.
95
97
  *
96
- * V1 sessions fetch and refresh a JWT using the supplied auth endpoint. V2 sessions instead refresh the complete
97
- * service-worker configuration using `getServiceWorkerConfig`.
98
+ * The primary JWT authenticates Bytescale API operations and downloads for `accountId`. Optional additional
99
+ * service-worker rules authenticate downloads only.
98
100
  *
99
101
  * Specifically, calling this method will cause the SDK to periodically acquire a JWT from your JWT endpoint. The SDK will then automatically include this JWT in all subsequent Bytescale API requests (via the 'authorization-token' request header) and also in all Bytescale CDN download requests (via a session cookie, or an 'authorization' header if service workers are being used).
100
102
  *
@@ -1,4 +1,5 @@
1
- import { BeginAuthSessionParams } from "./AuthManagerInterface";
1
+ import { AuthManagerServiceWorkerConfig, BeginAuthSessionParams } from "./AuthManagerInterface";
2
+ import { AuthSwConfigEntryDto } from "../dtos/AuthSwConfigEntryDto";
2
3
  import { ServiceWorkerConfig } from "./ServiceWorkerConfig";
3
4
  export interface AuthSession {
4
5
  accessToken: string | undefined;
@@ -7,4 +8,7 @@ export interface AuthSession {
7
8
  isActive: boolean;
8
9
  isReady?: boolean;
9
10
  params: BeginAuthSessionParams;
11
+ primaryAuthSwConfig: AuthSwConfigEntryDto | undefined;
12
+ serviceWorkerConfig: AuthManagerServiceWorkerConfig | undefined;
13
+ serviceWorkerConfigRefreshHandle: number | undefined;
10
14
  }
@@ -3,7 +3,7 @@ import { AuthSwSetConfigDto } from "../../private/dtos/AuthSwSetConfigDto";
3
3
  import { ServiceWorkerUtils } from "../../private/ServiceWorkerUtils";
4
4
  export type { AuthSwConfigEntryDto } from "../../private/dtos/AuthSwConfigEntryDto";
5
5
  export type { AuthSwHeaderDto } from "../../private/dtos/AuthSwHeaderDto";
6
- export type { BeginAuthSessionParams, BeginAuthSessionParamsV1, BeginAuthSessionParamsV2 } from "../../private/model/AuthManagerInterface";
6
+ export type { AuthManagerServiceWorkerConfig, BeginAuthSessionParams } from "../../private/model/AuthManagerInterface";
7
7
  declare class AuthManagerImpl implements AuthManagerInterface {
8
8
  private readonly serviceWorkerUtils;
9
9
  private readonly authSessionMutex;
@@ -23,14 +23,16 @@ declare class AuthManagerImpl implements AuthManagerInterface {
23
23
  endAuthSession(): Promise<void>;
24
24
  private refreshAccessToken;
25
25
  private refreshServiceWorkerConfig;
26
+ private sendMergedServiceWorkerConfig;
26
27
  private getServiceWorkerConfigRefreshEpoch;
27
28
  private sendServiceWorkerConfig;
29
+ private updateSessionReadiness;
30
+ private waitForServiceWorker;
28
31
  private getAccessTokenUrl;
29
32
  private getCdnUrl;
30
33
  private deleteAccessToken;
31
34
  private setAccessToken;
32
35
  private getAccessToken;
33
- private isV2;
34
36
  }
35
37
  /**
36
38
  * Alternative way of implementing a static class (i.e. all methods static). We do this so we can use a interface on the class (interfaces can't define static methods).
@@ -1,7 +1,7 @@
1
1
  import { AuthManagerInterface, BeginAuthSessionParams } from "../../private/model/AuthManagerInterface";
2
2
  export type { AuthSwConfigEntryDto } from "../../private/dtos/AuthSwConfigEntryDto";
3
3
  export type { AuthSwHeaderDto } from "../../private/dtos/AuthSwHeaderDto";
4
- export type { BeginAuthSessionParams, BeginAuthSessionParamsV1, BeginAuthSessionParamsV2 } from "../../private/model/AuthManagerInterface";
4
+ export type { AuthManagerServiceWorkerConfig, BeginAuthSessionParams } from "../../private/model/AuthManagerInterface";
5
5
  declare class AuthManagerImpl implements AuthManagerInterface {
6
6
  beginAuthSession(_params: BeginAuthSessionParams): Promise<void>;
7
7
  endAuthSession(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytescale/sdk",
3
- "version": "3.56.0",
3
+ "version": "3.57.0",
4
4
  "description": "Bytescale JavaScript SDK",
5
5
  "author": "Bytescale <hello@bytescale.com> (https://www.bytescale.com)",
6
6
  "license": "MIT",
@@ -1,14 +1,29 @@
1
1
  import { jest } from "@jest/globals";
2
2
  import { Response as NodeFetchResponse } from "node-fetch";
3
- import type { AuthSwConfigEntryDto, BeginAuthSessionParamsV1, BeginAuthSessionParamsV2 } from "../src/index.browser";
3
+ import { AuthSessionState } from "../src/private/AuthSessionState";
4
+ import type {
5
+ AuthManagerServiceWorkerConfig,
6
+ AuthSwConfigEntryDto,
7
+ BeginAuthSessionParams
8
+ } from "../src/index.browser";
9
+
10
+ type FetchApi = NonNullable<NonNullable<BeginAuthSessionParams["options"]>["fetchApi"]>;
4
11
 
5
12
  interface AuthManagerApi {
6
- beginAuthSession: (params: BeginAuthSessionParamsV1 | BeginAuthSessionParamsV2) => Promise<void>;
13
+ beginAuthSession: (params: BeginAuthSessionParams) => Promise<void>;
7
14
  endAuthSession: () => Promise<void>;
8
15
  isAuthSessionActive: () => boolean;
9
16
  isAuthSessionReady: () => boolean;
10
17
  }
11
18
 
19
+ interface AuthManagerInternals extends AuthManagerApi {
20
+ refreshAccessToken: (
21
+ session: NonNullable<ReturnType<typeof AuthSessionState.getSession>>,
22
+ params: BeginAuthSessionParams
23
+ ) => Promise<void>;
24
+ scheduler: { unschedule: (handle: number) => void };
25
+ }
26
+
12
27
  describe("AuthManager browser service-worker config", () => {
13
28
  const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, "navigator");
14
29
  const originalFetch = Object.getOwnPropertyDescriptor(globalThis, "fetch");
@@ -67,168 +82,261 @@ describe("AuthManager browser service-worker config", () => {
67
82
  jest.restoreAllMocks();
68
83
  });
69
84
 
70
- test("V2 applies multiple entries and refreshes before the earliest expiry", async () => {
71
- const firstConfig: AuthSwConfigEntryDto[] = [
72
- {
73
- expires: Date.now() + 21_000,
74
- headers: [{ key: "Authorization", value: "Bearer account-a" }],
75
- sourceUrlPrefixes: ["https://app.example.com/account-a/"],
76
- urlPrefix: "https://upcdn.io/account-a/"
77
- },
85
+ test("retains the existing cookie fallback when no additional config is requested", async () => {
86
+ delete navigatorValue.serviceWorker;
87
+ const fetchApi = createPrimaryFetchApi();
88
+
89
+ await AuthManager.beginAuthSession(createParams(fetchApi));
90
+
91
+ expect((fetchApi.mock.calls[1][0] as string).endsWith("?set-cookie=true")).toBe(true);
92
+ expect(postMessage).not.toHaveBeenCalled();
93
+ expect(AuthManager.isAuthSessionReady()).toBe(true);
94
+ });
95
+
96
+ test("retains the existing primary-only service-worker flow", async () => {
97
+ const fetchApi = createPrimaryFetchApi();
98
+
99
+ await AuthManager.beginAuthSession({
100
+ ...createParams(fetchApi),
101
+ serviceWorkerScript: "/bytescale-auth-sw.js"
102
+ });
103
+
104
+ expect(AuthManager.isAuthSessionReady()).toBe(true);
105
+ expect(postMessage.mock.calls[0][0]).toEqual({
106
+ config: [
107
+ {
108
+ expires: expect.any(Number),
109
+ headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
110
+ urlPrefix: "https://upcdn.io/account-a/"
111
+ }
112
+ ],
113
+ type: "SET_BYTESCALE_AUTH_CONFIG"
114
+ });
115
+ expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
116
+ });
117
+
118
+ test("merges the primary API/download context with additional download-only contexts", async () => {
119
+ const fetchApi = createPrimaryFetchApi();
120
+ const additionalConfig: AuthSwConfigEntryDto[] = [
78
121
  {
79
122
  expires: Date.now() + 60_000,
80
- headers: [{ key: "Authorization", value: "Bearer account-b" }],
123
+ headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
124
+ sourceUrlPrefixes: ["https://app.example.com/account-b/"],
81
125
  urlPrefix: "https://upcdn.io/account-b/"
82
- }
83
- ];
84
- const refreshedConfig: AuthSwConfigEntryDto[] = [
126
+ },
85
127
  {
86
128
  expires: undefined,
87
- headers: [{ key: "Authorization", value: "Bearer refreshed" }],
88
- urlPrefix: "https://upcdn.io/account-a/"
129
+ headers: [{ key: "Authorization", value: "Bearer jwt-c" }],
130
+ urlPrefix: "https://upcdn.io/account-c/"
89
131
  }
90
132
  ];
91
- const getServiceWorkerConfig = jest
92
- .fn<BeginAuthSessionParamsV2["getServiceWorkerConfig"]>()
93
- .mockResolvedValueOnce(firstConfig)
94
- .mockResolvedValueOnce(refreshedConfig);
133
+ const serviceWorkerConfig = jest.fn(
134
+ async (): Promise<AuthManagerServiceWorkerConfig> => ({
135
+ additionalConfig,
136
+ sourceUrlPrefixes: ["https://app.example.com/"]
137
+ })
138
+ );
95
139
 
96
140
  await AuthManager.beginAuthSession({
97
- getServiceWorkerConfig,
141
+ ...createParams(fetchApi),
142
+ serviceWorkerConfig,
98
143
  serviceWorkerScript: "/bytescale-auth-sw.js"
99
144
  });
100
145
 
101
- expect(AuthManager.isAuthSessionActive()).toBe(true);
102
146
  expect(AuthManager.isAuthSessionReady()).toBe(true);
147
+ expect(serviceWorkerConfig).toHaveBeenCalledTimes(1);
103
148
  expect(postMessage.mock.calls[0][0]).toEqual({
104
149
  config: [
105
150
  {
106
- ...firstConfig[0],
151
+ expires: expect.any(Number),
152
+ headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
153
+ sourceUrlPrefixes: ["https://app.example.com/"],
107
154
  urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
108
155
  },
109
- firstConfig[1]
156
+ {
157
+ ...additionalConfig[0],
158
+ urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-b/"
159
+ },
160
+ additionalConfig[1]
110
161
  ],
111
162
  type: "SET_BYTESCALE_AUTH_CONFIG"
112
163
  });
113
- expect(firstConfig[0].urlPrefix).toBe("https://upcdn.io/account-a/");
114
-
115
- await new Promise(resolve => setTimeout(resolve, 1_500));
116
-
117
- expect(getServiceWorkerConfig).toHaveBeenCalledTimes(2);
118
- expect(postMessage.mock.calls[1][0]).toEqual({
119
- config: refreshedConfig,
120
- type: "SET_BYTESCALE_AUTH_CONFIG"
121
- });
122
- });
164
+ expect(additionalConfig[0].urlPrefix).toBe("https://upcdn.io/account-b/");
165
+ expect(AuthSessionState.getSession()?.accessToken).toBe("access-a");
166
+ expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
123
167
 
124
- test("V2 clears service-worker config without calling access-token endpoints", async () => {
125
- await AuthManager.beginAuthSession({
126
- getServiceWorkerConfig: async () => [
127
- {
128
- expires: undefined,
129
- headers: [{ key: "Authorization", value: "Bearer account-a" }],
130
- urlPrefix: "https://upcdn.io/account-a/"
131
- }
132
- ],
133
- serviceWorkerScript: "/bytescale-auth-sw.js"
134
- });
135
168
  await AuthManager.endAuthSession();
136
169
 
137
- expect(globalFetch).not.toHaveBeenCalled();
170
+ expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT", "DELETE"]);
138
171
  expect(postMessage.mock.calls[1][0]).toEqual({ config: [], type: "SET_BYTESCALE_AUTH_CONFIG" });
139
- expect(AuthManager.isAuthSessionActive()).toBe(false);
140
- expect(AuthManager.isAuthSessionReady()).toBe(false);
141
- });
142
-
143
- test("V2 rejects instead of falling back to cookies when service workers are unavailable", async () => {
144
- delete navigatorValue.serviceWorker;
145
- const getServiceWorkerConfig = jest.fn(async (): Promise<AuthSwConfigEntryDto[]> => []);
146
-
147
- await expect(
148
- AuthManager.beginAuthSession({ getServiceWorkerConfig, serviceWorkerScript: "/bytescale-auth-sw.js" })
149
- ).rejects.toThrow("requires service workers");
150
-
151
- expect(getServiceWorkerConfig).not.toHaveBeenCalled();
152
- expect(AuthManager.isAuthSessionActive()).toBe(false);
153
172
  });
154
173
 
155
- test("V1 retains cookie fallback when service workers are unavailable", async () => {
156
- delete navigatorValue.serviceWorker;
157
- const fetchApi = jest.fn(async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
158
- switch (init?.method) {
159
- case "GET":
160
- return new NodeFetchResponse("jwt-a", {
161
- headers: { "Content-Type": "text/plain" }
162
- }) as unknown as Response;
163
- case "PUT":
164
- return new NodeFetchResponse(
165
- JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
166
- ) as unknown as Response;
167
- case "DELETE":
168
- return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
169
- default:
170
- throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
174
+ test("refreshes additional rules independently while retaining the primary context", async () => {
175
+ const fetchApi = createPrimaryFetchApi();
176
+ const initialAdditionalConfig: AuthSwConfigEntryDto[] = [
177
+ {
178
+ expires: Date.now() + 21_000,
179
+ headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
180
+ urlPrefix: "https://upcdn.io/account-b/"
171
181
  }
172
- });
182
+ ];
183
+ const serviceWorkerConfig = jest
184
+ .fn<() => Promise<AuthManagerServiceWorkerConfig>>()
185
+ .mockResolvedValueOnce({
186
+ additionalConfig: initialAdditionalConfig,
187
+ sourceUrlPrefixes: ["https://app.example.com/initial/"]
188
+ })
189
+ .mockResolvedValueOnce({
190
+ additionalConfig: [],
191
+ sourceUrlPrefixes: ["https://app.example.com/refreshed/"]
192
+ });
173
193
 
174
194
  await AuthManager.beginAuthSession({
175
- accountId: "account-a",
176
- authHeaders: async (): Promise<Record<string, string>> => ({}),
177
- authUrl: "https://app.example.com/auth",
178
- options: { fetchApi },
195
+ ...createParams(fetchApi),
196
+ serviceWorkerConfig,
179
197
  serviceWorkerScript: "/bytescale-auth-sw.js"
180
198
  });
199
+ await new Promise(resolve => setTimeout(resolve, 1_500));
181
200
 
182
- expect((fetchApi.mock.calls[1][0] as string).endsWith("?set-cookie=true")).toBe(true);
183
- expect(postMessage).not.toHaveBeenCalled();
201
+ expect(serviceWorkerConfig).toHaveBeenCalledTimes(2);
202
+ expect(postMessage.mock.calls[1][0]).toEqual({
203
+ config: [
204
+ {
205
+ expires: expect.any(Number),
206
+ headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
207
+ sourceUrlPrefixes: ["https://app.example.com/refreshed/"],
208
+ urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
209
+ }
210
+ ],
211
+ type: "SET_BYTESCALE_AUTH_CONFIG"
212
+ });
213
+ expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
184
214
  expect(AuthManager.isAuthSessionReady()).toBe(true);
185
215
  });
186
216
 
187
- test("V1 retains the existing JWT, access-token, and single-entry service-worker flow", async () => {
188
- const fetchApi = jest.fn(async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
189
- switch (init?.method) {
190
- case "GET":
191
- return new NodeFetchResponse("jwt-a", {
192
- headers: { "Content-Type": "text/plain" }
193
- }) as unknown as Response;
194
- case "PUT":
195
- return new NodeFetchResponse(
196
- JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
197
- ) as unknown as Response;
198
- case "DELETE":
199
- return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
200
- default:
201
- throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
217
+ test("retains additional rules when the primary JWT refreshes", async () => {
218
+ const fetchApi = createPrimaryFetchApi();
219
+ const additionalConfig: AuthSwConfigEntryDto[] = [
220
+ {
221
+ expires: undefined,
222
+ headers: [{ key: "Authorization", value: "Bearer jwt-b" }],
223
+ urlPrefix: "https://upcdn.io/account-b/"
202
224
  }
225
+ ];
226
+ const serviceWorkerConfig = jest.fn(
227
+ async (): Promise<AuthManagerServiceWorkerConfig> => ({
228
+ additionalConfig
229
+ })
230
+ );
231
+
232
+ await AuthManager.beginAuthSession({
233
+ ...createParams(fetchApi),
234
+ serviceWorkerConfig,
235
+ serviceWorkerScript: "/bytescale-auth-sw.js"
203
236
  });
204
- const params: BeginAuthSessionParamsV1 = {
205
- accountId: "account-a",
206
- authHeaders: async (): Promise<Record<string, string>> => ({ "X-App-Authorization": "app-token" }),
207
- authUrl: "https://app.example.com/auth",
208
- options: { fetchApi },
209
- serviceWorkerScript: "/bytescale-auth-sw.js",
210
- sourceUrlPrefixes: ["https://app.example.com/"]
211
- };
212
237
 
213
- await AuthManager.beginAuthSession(params);
238
+ const session = AuthSessionState.getSession();
239
+ if (session?.accessTokenRefreshHandle === undefined) {
240
+ throw new Error("Expected the primary access-token refresh to be scheduled.");
241
+ }
242
+ const authManagerInternals = AuthManager as AuthManagerInternals;
243
+ authManagerInternals.scheduler.unschedule(session.accessTokenRefreshHandle);
244
+ await authManagerInternals.refreshAccessToken(session, session.params);
214
245
 
215
- expect(AuthManager.isAuthSessionReady()).toBe(true);
216
- expect(postMessage.mock.calls[0][0]).toEqual({
246
+ expect(serviceWorkerConfig).toHaveBeenCalledTimes(1);
247
+ expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT", "GET", "PUT"]);
248
+ expect(postMessage.mock.calls[1][0]).toEqual({
217
249
  config: [
218
250
  {
219
251
  expires: expect.any(Number),
220
252
  headers: [{ key: "Authorization", value: "Bearer jwt-a" }],
221
- sourceUrlPrefixes: params.sourceUrlPrefixes,
222
- urlPrefix: "!bytescale-source-scoped!https://upcdn.io/account-a/"
223
- }
253
+ urlPrefix: "https://upcdn.io/account-a/"
254
+ },
255
+ additionalConfig[0]
224
256
  ],
225
257
  type: "SET_BYTESCALE_AUTH_CONFIG"
226
258
  });
259
+ });
260
+
261
+ test("fails closed until the initial service-worker config callback succeeds", async () => {
262
+ jest.spyOn(console, "warn").mockImplementation(() => {});
263
+ const fetchApi = createPrimaryFetchApi();
264
+
265
+ await AuthManager.beginAuthSession({
266
+ ...createParams(fetchApi),
267
+ serviceWorkerConfig: async () => null as unknown as AuthManagerServiceWorkerConfig,
268
+ serviceWorkerScript: "/bytescale-auth-sw.js"
269
+ });
270
+
227
271
  expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT"]);
272
+ expect(postMessage).not.toHaveBeenCalled();
273
+ expect(AuthManager.isAuthSessionReady()).toBe(false);
274
+ });
228
275
 
229
- await AuthManager.endAuthSession();
276
+ test("requires a service-worker script for additional configuration", async () => {
277
+ const fetchApi = createPrimaryFetchApi();
278
+ const serviceWorkerConfig = jest.fn(
279
+ async (): Promise<AuthManagerServiceWorkerConfig> => ({
280
+ additionalConfig: []
281
+ })
282
+ );
230
283
 
231
- expect(fetchApi.mock.calls.map(([, init]) => init?.method)).toEqual(["GET", "PUT", "DELETE"]);
232
- expect(postMessage.mock.calls[1][0]).toEqual({ config: [], type: "SET_BYTESCALE_AUTH_CONFIG" });
284
+ await expect(AuthManager.beginAuthSession({ ...createParams(fetchApi), serviceWorkerConfig })).rejects.toThrow(
285
+ "'serviceWorkerScript' field is required"
286
+ );
287
+
288
+ expect(serviceWorkerConfig).not.toHaveBeenCalled();
289
+ expect(fetchApi).not.toHaveBeenCalled();
290
+ expect(AuthManager.isAuthSessionActive()).toBe(false);
291
+ });
292
+
293
+ test("rejects additional configuration when service workers are unavailable", async () => {
294
+ delete navigatorValue.serviceWorker;
295
+ const fetchApi = createPrimaryFetchApi();
296
+ const serviceWorkerConfig = jest.fn(
297
+ async (): Promise<AuthManagerServiceWorkerConfig> => ({
298
+ additionalConfig: []
299
+ })
300
+ );
301
+
302
+ await expect(
303
+ AuthManager.beginAuthSession({
304
+ ...createParams(fetchApi),
305
+ serviceWorkerConfig,
306
+ serviceWorkerScript: "/bytescale-auth-sw.js"
307
+ })
308
+ ).rejects.toThrow("requires service workers");
309
+
310
+ expect(serviceWorkerConfig).not.toHaveBeenCalled();
311
+ expect(fetchApi).not.toHaveBeenCalled();
312
+ expect(AuthManager.isAuthSessionActive()).toBe(false);
233
313
  });
234
314
  });
315
+
316
+ function createParams(fetchApi: FetchApi): BeginAuthSessionParams {
317
+ return {
318
+ accountId: "account-a",
319
+ authHeaders: async (): Promise<Record<string, string>> => ({ "X-App-Authorization": "app-token" }),
320
+ authUrl: "https://app.example.com/auth",
321
+ options: { fetchApi }
322
+ };
323
+ }
324
+
325
+ function createPrimaryFetchApi(): jest.MockedFunction<FetchApi> {
326
+ return jest.fn<FetchApi>(async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
327
+ switch (init?.method) {
328
+ case "GET":
329
+ return new NodeFetchResponse("jwt-a", {
330
+ headers: { "Content-Type": "text/plain" }
331
+ }) as unknown as Response;
332
+ case "PUT":
333
+ return new NodeFetchResponse(
334
+ JSON.stringify({ accessToken: "access-a", ttlSeconds: 3600 })
335
+ ) as unknown as Response;
336
+ case "DELETE":
337
+ return new NodeFetchResponse(null, { status: 204 }) as unknown as Response;
338
+ default:
339
+ throw new Error(`Unexpected method: ${init?.method ?? "undefined"}`);
340
+ }
341
+ });
342
+ }