@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.
- package/dist/browser/cjs/main.js +129 -55
- package/dist/browser/esm/main.mjs +129 -55
- package/dist/types/private/model/AuthManagerInterface.d.ts +28 -26
- package/dist/types/private/model/AuthSession.d.ts +5 -1
- package/dist/types/public/browser/AuthManagerBrowser.d.ts +4 -2
- package/dist/types/public/node/AuthManagerNode.d.ts +1 -1
- package/package.json +1 -1
- package/tests/AuthManagerBrowser.test.ts +223 -115
package/dist/browser/cjs/main.js
CHANGED
|
@@ -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
|
|
3199
|
+
function AuthManagerBrowser_invoke(body, then) {
|
|
3200
3200
|
var result = body();
|
|
3201
3201
|
if (result && result.then) {
|
|
3202
|
-
return result.then(
|
|
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
|
|
3227
|
+
function AuthManagerBrowser_invokeIgnored(body) {
|
|
3227
3228
|
var result = body();
|
|
3228
3229
|
if (result && result.then) {
|
|
3229
|
-
return result.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)
|
|
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 (
|
|
3320
|
-
|
|
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
|
|
3338
|
-
if (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
}
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
return
|
|
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
|
|
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
|
|
3472
|
-
if (!Array.isArray(
|
|
3473
|
-
throw new Error("The '
|
|
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
|
-
|
|
3476
|
-
return
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
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.
|
|
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
|
|
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(
|
|
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 ? "" :
|
|
3595
|
+
urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this6.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
|
|
3535
3596
|
});
|
|
3536
3597
|
})
|
|
3537
|
-
}, session.authServiceWorker,
|
|
3538
|
-
session.authServiceWorker =
|
|
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
|
|
3638
|
+
var _this7 = this;
|
|
3560
3639
|
var _a;
|
|
3561
|
-
return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(
|
|
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
|
|
3656
|
+
var _this8 = this;
|
|
3578
3657
|
var _a;
|
|
3579
3658
|
var request = {
|
|
3580
3659
|
accessToken: jwt
|
|
3581
3660
|
};
|
|
3582
|
-
return AuthManagerBrowser_await(BaseAPI.fetch(
|
|
3661
|
+
return AuthManagerBrowser_await(BaseAPI.fetch(_this8.getAccessTokenUrl(params, setCookie), {
|
|
3583
3662
|
method: "PUT",
|
|
3584
3663
|
credentials: "include",
|
|
3585
|
-
headers: AuthManagerBrowser_defineProperty({},
|
|
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
|
|
3680
|
+
var _this9 = this;
|
|
3602
3681
|
var _a, _b;
|
|
3603
3682
|
var endpointName = "Your auth API endpoint";
|
|
3604
|
-
var requiredContentType =
|
|
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(
|
|
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(
|
|
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
|
|
3159
|
+
function AuthManagerBrowser_invoke(body, then) {
|
|
3160
3160
|
var result = body();
|
|
3161
3161
|
if (result && result.then) {
|
|
3162
|
-
return result.then(
|
|
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
|
|
3187
|
+
function AuthManagerBrowser_invokeIgnored(body) {
|
|
3187
3188
|
var result = body();
|
|
3188
3189
|
if (result && result.then) {
|
|
3189
|
-
return result.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)
|
|
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 (
|
|
3280
|
-
|
|
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
|
|
3298
|
-
if (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
}
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
return
|
|
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
|
|
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
|
|
3432
|
-
if (!Array.isArray(
|
|
3433
|
-
throw new Error("The '
|
|
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
|
-
|
|
3436
|
-
return
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
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.
|
|
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
|
|
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(
|
|
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 ? "" :
|
|
3555
|
+
urlPrefix: "".concat(entry.sourceUrlPrefixes === undefined ? "" : _this6.sourceScopedUrlPrefixMarker).concat(entry.urlPrefix)
|
|
3495
3556
|
});
|
|
3496
3557
|
})
|
|
3497
|
-
}, session.authServiceWorker,
|
|
3498
|
-
session.authServiceWorker =
|
|
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
|
|
3598
|
+
var _this7 = this;
|
|
3520
3599
|
var _a;
|
|
3521
|
-
return AuthManagerBrowser_await(AuthManagerBrowser_awaitIgnored(BaseAPI.fetch(
|
|
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
|
|
3616
|
+
var _this8 = this;
|
|
3538
3617
|
var _a;
|
|
3539
3618
|
var request = {
|
|
3540
3619
|
accessToken: jwt
|
|
3541
3620
|
};
|
|
3542
|
-
return AuthManagerBrowser_await(BaseAPI.fetch(
|
|
3621
|
+
return AuthManagerBrowser_await(BaseAPI.fetch(_this8.getAccessTokenUrl(params, setCookie), {
|
|
3543
3622
|
method: "PUT",
|
|
3544
3623
|
credentials: "include",
|
|
3545
|
-
headers: AuthManagerBrowser_defineProperty({},
|
|
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
|
|
3640
|
+
var _this9 = this;
|
|
3562
3641
|
var _a, _b;
|
|
3563
3642
|
var endpointName = "Your auth API endpoint";
|
|
3564
|
-
var requiredContentType =
|
|
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(
|
|
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(
|
|
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
|
|
4
|
-
|
|
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
|
-
*
|
|
97
|
-
* service-worker
|
|
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 {
|
|
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 {
|
|
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,14 +1,29 @@
|
|
|
1
1
|
import { jest } from "@jest/globals";
|
|
2
2
|
import { Response as NodeFetchResponse } from "node-fetch";
|
|
3
|
-
import
|
|
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:
|
|
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("
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
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
|
|
88
|
-
urlPrefix: "https://upcdn.io/account-
|
|
129
|
+
headers: [{ key: "Authorization", value: "Bearer jwt-c" }],
|
|
130
|
+
urlPrefix: "https://upcdn.io/account-c/"
|
|
89
131
|
}
|
|
90
132
|
];
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
114
|
-
|
|
115
|
-
|
|
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(
|
|
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("
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
176
|
-
|
|
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(
|
|
183
|
-
expect(postMessage).
|
|
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("
|
|
188
|
-
const fetchApi =
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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(
|
|
216
|
-
expect(
|
|
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
|
-
|
|
222
|
-
|
|
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
|
-
|
|
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(
|
|
232
|
-
|
|
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
|
+
}
|