@sap-cloud-sdk/connectivity
Version:
SAP Cloud SDK for JavaScript connectivity
162 lines • 6 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cache = void 0;
exports.hashCacheKey = hashCacheKey;
const crypto = __importStar(require("node:crypto"));
const safe_stable_stringify_1 = require("safe-stable-stringify");
/**
* Representation of a cache to transiently store objects locally for faster access.
* @typeParam T - Type of the cache entries.
* @internal
*/
class Cache {
/**
* Creates an instance of Cache.
* @param defaultValidityTime - The default validity time in milliseconds. Use 0 for unlimited cache duration.
* @param capacity - The maximum number of entries in the cache. Use Infinity for unlimited size. Items are evicted based on a least recently used (LRU) strategy.
*/
constructor(defaultValidityTime, capacity = Infinity) {
this.defaultValidityTime = defaultValidityTime;
this.capacity = capacity;
this.cache = new Map();
}
/**
* Clear all cached items.
*/
clear() {
this.cache.clear();
}
/**
* Specifies whether an entry with a given key is defined in cache.
* @param key - The entry's key.
* @returns A boolean value that indicates whether the entry exists in cache.
*/
hasKey(key) {
return this.cache.has(key);
}
/**
* Getter of cached entries.
* @param key - The key of the entry to retrieve.
* @returns The corresponding entry to the provided key if it is still valid, returns `undefined` otherwise.
*/
get(key) {
if (!key) {
return undefined;
}
const entry = this.cache.get(key);
if (!entry) {
return undefined;
}
if (isExpired(entry)) {
this.cache.delete(key);
return undefined;
}
// LRU cache: Move accessed entry to the end of the Map to mark it as recently used
if (this.capacity !== Infinity) {
this.cache.delete(key);
this.cache.set(key, entry);
}
return entry?.entry;
}
/**
* Setter of entries in cache.
* @param key - The entry's key.
* @param item - The entry to cache.
*/
set(key, item) {
if (!key) {
return;
}
if (this.cache.size >= this.capacity &&
this.cache.size &&
!this.cache.has(key)) {
// Evict the least recently used (LRU) entry
const lruKey = this.cache.keys().next().value;
this.cache.delete(lruKey); // SAFETY: size > 0
}
if (this.capacity !== Infinity && this.cache.has(key)) {
// If the key already exists, delete it to update its position in the LRU order
this.cache.delete(key);
}
const expires = item.expires ?? this.inferDefaultExpirationTime();
this.cache.set(key, { entry: item.entry, expires });
}
getOrInsertComputed(key, computeFn) {
const cachedEntry = this.get(key);
if (cachedEntry !== undefined) {
return cachedEntry;
}
const newEntry = computeFn();
this.set(key, newEntry);
return newEntry.entry;
}
inferDefaultExpirationTime() {
const now = new Date();
return this.defaultValidityTime
? now
.setMilliseconds(now.getMilliseconds() + this.defaultValidityTime)
.valueOf()
: undefined;
}
}
exports.Cache = Cache;
/**
* Hashes the given value to create a cache key.
* @internal
* @param value - The value to hash.
* @returns A hash of the given value using a cryptographic hash function.
*/
async function hashCacheKey(value) {
const stringifiedValue = (0, safe_stable_stringify_1.stringify)(value);
const encodedValue = new TextEncoder().encode(stringifiedValue);
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedValue);
// TODO: Supported in Node.js 25 and later + browsers
// if ((Uint8Array.prototype as any).toHex) {
// // Use toHex if supported.
// return (new Uint8Array(hashBuffer) as any).toHex(); // Convert ArrayBuffer to hex string.
// }
// If toHex() is not supported, fall back to an alternative implementation.
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
return hashHex;
}
function isExpired(item) {
if (item.expires === undefined) {
return false;
}
return item.expires < Date.now();
}
//# sourceMappingURL=cache.js.map