@descope/sdk-mixins
Version:
Descope JavaScript SDK mixins
114 lines (111 loc) • 7.31 kB
JavaScript
import { __classPrivateFieldGet, __classPrivateFieldSet } from 'tslib';
import { createSingletonMixin, compose, pathJoin } from '@descope/sdk-helpers';
import { loggerMixin } from '../loggerMixin/loggerMixin.js';
import { ASSETS_FOLDER, BASE_CONTENT_URL, OVERRIDE_CONTENT_URL, BASE_CONTENT_URL_FALLBACK } from './constants.js';
import { projectIdMixin } from '../projectIdMixin.js';
import { baseUrlMixin } from '../baseUrlMixin.js';
import { fetchWithFallbacks } from './fetchWithFallbacks.js';
function getResourceUrl({ projectId, filename, assetsFolder = ASSETS_FOLDER, baseUrl = BASE_CONTENT_URL, }) {
const url = new URL(baseUrl);
url.pathname = pathJoin(url.pathname, projectId, assetsFolder, filename);
// we want to keep the baseUrl so we can use it later
url.baseUrl = baseUrl;
return url;
}
const staticResourcesMixin = createSingletonMixin((superclass) => {
var _StaticResourcesMixinClass_instances, _StaticResourcesMixinClass_lastBaseUrl, _StaticResourcesMixinClass_workingBaseUrl, _StaticResourcesMixinClass_failedUrls, _StaticResourcesMixinClass_getResourceUrls, _StaticResourcesMixinClass_createResourceUrl, _a;
const BaseClass = compose(loggerMixin, projectIdMixin, baseUrlMixin)(superclass);
// the logic should be as following:
// 1. if there is a local storage override, use it
// 2. otherwise, if there is a base-static-url attribute, use it
// 3. otherwise, try to use base-url
// 4. otherwise, try to use default content url (BASE_CONTENT_URL)
// 5. otherwise, try to use the fallback content url (BASE_CONTENT_URL_FALLBACK)
// For steps 3-5: if the url is valid, keep using it, and if not, don't try it anymore
return _a = class StaticResourcesMixinClass extends BaseClass {
constructor() {
super(...arguments);
_StaticResourcesMixinClass_instances.add(this);
_StaticResourcesMixinClass_lastBaseUrl.set(this, void 0);
_StaticResourcesMixinClass_workingBaseUrl.set(this, void 0);
_StaticResourcesMixinClass_failedUrls.set(this, new Set());
}
async fetchStaticResource(filename, format) {
const resourceUrls = __classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_getResourceUrls).call(this, filename);
// Cache the working URL and mark failed URLs
const onSuccess = !Array.isArray(resourceUrls)
? null
: (index) => {
const { baseUrl } = resourceUrls[index];
__classPrivateFieldSet(this, _StaticResourcesMixinClass_workingBaseUrl, baseUrl, "f");
// Mark all URLs before this one as failed
for (let i = 0; i < index; i++) {
const failedUrl = resourceUrls[i].baseUrl;
__classPrivateFieldGet(this, _StaticResourcesMixinClass_failedUrls, "f").add(failedUrl);
}
};
try {
const res = await fetchWithFallbacks(resourceUrls, { cache: 'default' }, { logger: this.logger, onSuccess });
return {
body: await res[format](),
headers: Object.fromEntries(res.headers.entries()),
};
}
catch (e) {
this.logger.error(e.message);
}
}
get baseStaticUrl() {
return this.getAttribute('base-static-url') || '';
}
},
_StaticResourcesMixinClass_lastBaseUrl = new WeakMap(),
_StaticResourcesMixinClass_workingBaseUrl = new WeakMap(),
_StaticResourcesMixinClass_failedUrls = new WeakMap(),
_StaticResourcesMixinClass_instances = new WeakSet(),
_StaticResourcesMixinClass_getResourceUrls = function _StaticResourcesMixinClass_getResourceUrls(filename) {
const overrideUrl = OVERRIDE_CONTENT_URL || this.baseStaticUrl;
// Steps 1-2: Override URL or base-static-url takes precedence
if (overrideUrl) {
return __classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, overrideUrl);
}
// Reset state if base-url changed
if (__classPrivateFieldGet(this, _StaticResourcesMixinClass_lastBaseUrl, "f") !== this.baseUrl) {
__classPrivateFieldSet(this, _StaticResourcesMixinClass_lastBaseUrl, this.baseUrl, "f");
__classPrivateFieldSet(this, _StaticResourcesMixinClass_workingBaseUrl, undefined, "f");
__classPrivateFieldGet(this, _StaticResourcesMixinClass_failedUrls, "f").clear();
}
// Build URL list based on cached state or fallback chain
const urls = [];
if (__classPrivateFieldGet(this, _StaticResourcesMixinClass_workingBaseUrl, "f")) {
// Use cached working URL
urls.push(__classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, __classPrivateFieldGet(this, _StaticResourcesMixinClass_workingBaseUrl, "f")));
// Add fallback only for BASE_CONTENT_URL (for resilience)
if (__classPrivateFieldGet(this, _StaticResourcesMixinClass_workingBaseUrl, "f") === BASE_CONTENT_URL) {
urls.push(__classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, BASE_CONTENT_URL_FALLBACK));
}
}
else {
// Build fallback chain: try URLs that haven't failed yet
const baseUrlWithPages = this.baseUrl + '/pages';
if (this.baseUrl && !__classPrivateFieldGet(this, _StaticResourcesMixinClass_failedUrls, "f").has(baseUrlWithPages)) {
urls.push(__classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, baseUrlWithPages));
}
if (!__classPrivateFieldGet(this, _StaticResourcesMixinClass_failedUrls, "f").has(BASE_CONTENT_URL)) {
urls.push(__classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, BASE_CONTENT_URL));
}
urls.push(__classPrivateFieldGet(this, _StaticResourcesMixinClass_instances, "m", _StaticResourcesMixinClass_createResourceUrl).call(this, filename, BASE_CONTENT_URL_FALLBACK));
}
return urls.length === 1 ? urls[0] : urls;
},
_StaticResourcesMixinClass_createResourceUrl = function _StaticResourcesMixinClass_createResourceUrl(filename, baseUrl) {
return getResourceUrl({
projectId: this.projectId,
filename,
baseUrl,
});
},
_a;
});
export { getResourceUrl, staticResourcesMixin };
//# sourceMappingURL=staticResourcesMixin.js.map