@sap-cloud-sdk/connectivity
Version:
SAP Cloud SDK for JavaScript connectivity
138 lines • 6.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.destinationCache = exports.DestinationCache = exports.DefaultDestinationCache = void 0;
exports.getDestinationCacheKey = getDestinationCacheKey;
exports.setDestinationCache = setDestinationCache;
exports.getDefaultIsolationStrategy = getDefaultIsolationStrategy;
const util_1 = require("@sap-cloud-sdk/util");
const jwt_1 = require("../jwt");
const async_cache_1 = require("../async-cache");
const logger = (0, util_1.createLogger)({
package: 'connectivity',
messageContext: 'destination-cache'
});
/**
* @internal
* This wrapper class wraps methods of {@link Cache} class as asynchronous methods.
*/
class DefaultDestinationCache extends async_cache_1.AsyncCache {
constructor(defaultValidityTime = 0) {
super(defaultValidityTime);
}
}
exports.DefaultDestinationCache = DefaultDestinationCache;
/**
* DestinationCache constructor.
* @param cache - Cache object which is used in DestinationCache
* @returns A destination cache object.
* @internal
*/
const DestinationCache = (cache = new DefaultDestinationCache(300000)) => ({
retrieveDestinationFromCache: async (token, name, isolation) => cache.get(getDestinationCacheKey(token, name, isolation)),
cacheRetrievedDestination: async (token, destination, isolation) => {
cacheRetrievedDestination(token, destination, isolation, cache);
},
cacheRetrievedDestinations: async (token, retrievedDestinations, isolation) => {
retrievedDestinations.subaccount.forEach(dest => cacheRetrievedDestination(token, dest, isolation, cache));
retrievedDestinations.instance.forEach(dest => cacheRetrievedDestination(token, dest, isolation, cache));
},
clear: async () => {
cache.clear();
},
getCacheInstance: () => cache
});
exports.DestinationCache = DestinationCache;
/**
* Retrieve the token to use for tenant identification.
*
* For subscriber:
* If `iss` or XSUAA user JWT was passed, this is the `serviceJwt`.
* If a custom user JWT was passed, this is used.
*
* For provider: always use the token as passed.
* @param token - Either the subscriber JWTs or one provider JWT.
* @returns The decoded JWT to use for tenant identification.
*/
function getJwtForTenant(token) {
return token?.serviceJwt?.decoded || token;
}
/**
* Retrieve the token to use for user identification.
*
* For subscriber:
* If a user token was passed, this is used.
* If only `iss` was passed try to get the user from the service token.
*
* For provider: always use the token as passed.
* @param token - Either the subscriber JWTs or one provider JWT.
* @returns The decoded JWT to use for user identification.
*/
function getJwtForUser(token) {
return token?.userJwt?.decoded || token;
}
/**
* Calculates a cache key based on the JWT and destination name for the given isolation strategy.
* Cache keys for strategies are non-overlapping, i.e. using a cache key for strategy {@link 'tenant'}
* will not result in a cache hit for a destination that has been cached with strategy {@link 'tenant-user'}.
* @param decodedJwt - The decoded JWT of the current request.
* @param destinationName - The name of the destination.
* @param isolationStrategy - The strategy used to isolate cache entries.
* @returns The cache key.
* @internal
*/
function getDestinationCacheKey(token, destinationName, isolationStrategy = 'tenant-user') {
if (isolationStrategy === 'tenant') {
return getTenantCacheKey(destinationName, (0, jwt_1.getTenantId)(getJwtForTenant(token)));
}
if (isolationStrategy === 'tenant-user') {
return getTenantUserCacheKey(destinationName, (0, jwt_1.getTenantId)(getJwtForTenant(token)), (0, jwt_1.userId)(getJwtForUser(token)));
}
logger.warn(`Could not build destination cache key. Isolation strategy '${isolationStrategy}' is not supported.`);
}
function getTenantCacheKey(destinationName, tenant) {
if (tenant) {
return `${tenant}::${destinationName}`;
}
logger.warn("Could not build destination cache key. Isolation strategy 'tenant' is used, but tenant ID is undefined in JWT.");
}
function getTenantUserCacheKey(destinationName, tenant, user) {
if (tenant && user) {
return `${user}:${tenant}:${destinationName}`;
}
logger.warn("Could not build destination cache key. Isolation strategy 'tenant-user' is used, but tenant id or user id is undefined in JWT.");
}
async function cacheRetrievedDestination(token, destination, isolation, cache) {
if (!destination.name) {
throw new Error('The destination name is undefined.');
}
const key = getDestinationCacheKey(token, destination.name, isolation);
const expiresIn = (0, util_1.first)(destination.authTokens || [])?.expiresIn;
const expirationTime = expiresIn
? Date.now() + parseInt(expiresIn) * 1000
: undefined;
cache.set(key, { entry: destination, expires: expirationTime });
}
/**
* Sets the custom destination cache instance.
* Call this method with an instance of {@link DestinationCacheInterface} to override the default cache instance set by the SDK.
*
* NOTE: This function should be called at the beginning before any calls to either {@link getDestination} or {@link @sap-cloud-sdk/http-client!executeHttpRequest}.
* @param cache - An instance of {@link DestinationCacheInterface}.
*/
function setDestinationCache(cache) {
exports.destinationCache = (0, exports.DestinationCache)(cache);
}
/**
* @internal
*/
exports.destinationCache = (0, exports.DestinationCache)();
/**
* Determine the default isolation strategy if not given as option.
* @param jwt - JWT to determine the default isolation strategy
* @returns The isolation strategy based on the JWT. If no JWT is given it defaults to tenant isolation.
* @internal
*/
function getDefaultIsolationStrategy(jwt) {
return jwt && (0, jwt_1.userId)(jwt) ? 'tenant-user' : 'tenant';
}
//# sourceMappingURL=destination-cache.js.map