@vendure/core
Version:
A modern, headless ecommerce framework
94 lines • 3.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSelfRefreshingCache = createSelfRefreshingCache;
const vendure_logger_1 = require("../config/logger/vendure-logger");
/**
* @description
* Creates a {@link SelfRefreshingCache} object, which is used to cache a single frequently-accessed value. In this type
* of cache, the function used to populate the value (`refreshFn`) is defined during the creation of the cache, and
* it is immediately used to populate the initial value.
*
* From there, when the `.value` property is accessed, it will return a value from the cache, and if the
* value has expired, it will automatically run the `refreshFn` to update the value and then return the
* fresh value.
*
* @example
* ```ts title="Example of creating a SelfRefreshingCache"
* import { createSelfRefreshingCache } from '@vendure/core';
*
* \@Injectable()
* export class PublicChannelService {
* private publicChannel: SelfRefreshingCache<Channel, [RequestContext]>;
*
* async init() {
* this.publicChannel = await createSelfRefreshingCache<Channel, [RequestContext]>({
* name: 'PublicChannelService.publicChannel',
* ttl: 1000 * 60 * 60, // 1 hour
* refresh: {
* fn: async (ctx: RequestContext) => {
* return this.channelService.getPublicChannel(ctx);
* },
* defaultArgs: [RequestContext.empty()],
* },
* });
* }
* ```
*
* @docsCategory cache
* @docsPage SelfRefreshingCache
*/
async function createSelfRefreshingCache(config, refreshArgs) {
const { ttl, name, refresh, getTimeFn } = config;
const getTimeNow = getTimeFn !== null && getTimeFn !== void 0 ? getTimeFn : (() => new Date().getTime());
const initialValue = await refresh.fn(...(refreshArgs !== null && refreshArgs !== void 0 ? refreshArgs : refresh.defaultArgs));
let value = initialValue;
let expires = getTimeNow() + ttl;
const memoCache = new Map();
const refreshValue = (resetMemoCache = true, args) => {
return refresh
.fn(...args)
.then(newValue => {
value = newValue;
expires = getTimeNow() + ttl;
if (resetMemoCache) {
memoCache.clear();
}
return value;
})
.catch((err) => {
const _message = err.message;
const message = typeof _message === 'string' ? _message : JSON.stringify(err.message);
vendure_logger_1.Logger.error(`Failed to update SelfRefreshingCache "${name}": ${message}`, undefined, err.stack);
return value;
});
};
const getValue = async (_refreshArgs, resetMemoCache = true) => {
const now = getTimeNow();
if (expires < now) {
return refreshValue(resetMemoCache, _refreshArgs !== null && _refreshArgs !== void 0 ? _refreshArgs : refresh.defaultArgs);
}
return value;
};
const memoize = async (args, _refreshArgs, fn) => {
const key = JSON.stringify(args);
const cached = memoCache.get(key);
const now = getTimeNow();
if (cached && now < cached.expires) {
return cached.value;
}
const result = getValue(_refreshArgs, false).then(val => fn(val, ...args));
memoCache.set(key, {
expires: now + ttl,
value: result,
});
return result;
};
return {
value: (...args) => getValue(!args.length || (args.length === 1 && args[0] === undefined)
? undefined
: args),
refresh: (...args) => refreshValue(true, args),
memoize,
};
}
//# sourceMappingURL=self-refreshing-cache.js.map