@podium/client
Version:
Client for fetching podium component fragments over HTTP.
106 lines (95 loc) • 3.12 kB
JavaScript
import Metrics from '@metrics/client';
import abslog from 'abslog';
import assert from 'assert';
import HTTP from './http.js';
import Manifest from './resolver.manifest.js';
import Fallback from './resolver.fallback.js';
import Content from './resolver.content.js';
import Cache from './resolver.cache.js';
/**
* @typedef {object} PodletClientResolverOptions
* @property {string} clientName
* @property {import('abslog').AbstractLoggerOptions} [logger]
* @property {boolean} [earlyHints]
*/
export default class PodletClientResolver {
#cache;
#manifest;
#fallback;
#content;
#metrics;
/**
* @constructor
* @param {import('ttl-mem-cache').default} registry
* @param {PodletClientResolverOptions} options
*/
// @ts-expect-error Deliberate default empty options for better error messages
constructor(registry, options = {}) {
assert(
registry,
'you must pass a "registry" object to the PodletClientResolver constructor',
);
const log = abslog(options.logger);
const http = new HTTP();
this.#cache = new Cache(registry, options);
this.#manifest = new Manifest({
clientName: options.clientName,
logger: options.logger,
http,
});
this.#fallback = new Fallback({ ...options, http });
this.#content = new Content({
...options,
http,
});
this.#metrics = new Metrics();
this.#metrics.on('error', (error) => {
log.error(
'Error emitted by metric stream in @podium/client module',
error,
);
});
this.#content.metrics.pipe(this.#metrics);
this.#fallback.metrics.pipe(this.#metrics);
this.#manifest.metrics.pipe(this.#metrics);
}
get metrics() {
return this.#metrics;
}
/**
* Resolve the podlet's manifest, fallback and content
*
* @param {import('./http-outgoing.js').default} outgoing
* @returns {Promise<import('./http-outgoing.js').default>}
*/
resolve(outgoing) {
return this.#cache
.load(outgoing)
.then((obj) => this.#manifest.resolve(obj))
.then((obj) => this.#fallback.resolve(obj))
.then((obj) => this.#content.resolve(obj))
.then((obj) => this.#cache.save(obj))
.then((obj) => {
if (obj.success) {
return obj;
}
return this.resolve(obj);
});
}
/**
* Refresh the podlet's cached manifest and fallback
*
* @param {import('./http-outgoing.js').default} outgoing
* @returns {Promise<boolean>} `true` if successful
*/
refresh(outgoing) {
return this.#manifest
.resolve(outgoing)
.then((obj) => this.#fallback.resolve(obj))
.then((obj) => this.#cache.save(obj))
.then((obj) => !!obj.manifest.name);
}
get [Symbol.toStringTag]() {
return 'PodletClientResolver';
}
}