@trap_stevo/ventry
Version:
The universal engine for creating, tracking, and evolving interactive content — from posts, comments, and likes to offers, auctions, events, and beyond. Define, extend, and analyze content objects in real time. Turn anything into user-driven content.
159 lines (158 loc) • 5.81 kB
JavaScript
;
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
const MetricTide = require("@trap_stevo/metrictide");
var _prefix = /*#__PURE__*/new WeakMap();
var _ContalyticsInstanceManager_brand = /*#__PURE__*/new WeakSet();
class ContalyticsInstanceManager {
constructor(instance, options = {}) {
_classPrivateMethodInitSpec(this, _ContalyticsInstanceManager_brand);
_classPrivateFieldInitSpec(this, _prefix, "ventry");
this.contalyticsEngine = instance || new MetricTide({
dbPath: options && options.dbPath || "./.ventry-metrics",
persistence: {
alwaysOn: true
},
loadMetricsOnLaunch: true,
...(options ?? {})
});
_classPrivateFieldSet(_prefix, this, options.metricPrefix || "ugc");
}
setPrefix(prefix = "ugc") {
_classPrivateFieldSet(_prefix, this, prefix || "ugc");
}
track(name, value, tags, metadata) {
this.contalyticsEngine.track(`${_classPrivateFieldGet(_prefix, this)}.${name}`, {
value: value == null ? 1 : value,
metadata: metadata || {},
tags: tags || {}
});
}
readWindows(itemID) {
const all = this.contalyticsEngine.searchByTagValue("itemID", itemID) || [];
const sum = (arr, fn) => arr.reduce((s, r) => s + (fn(r) || 0), 0);
const pick = metric => r => r.name === `${_classPrivateFieldGet(_prefix, this)}.${metric}` ? r.value?.value || r.value || 0 : 0;
const likes7d = sum(all, pick("like"));
const favorites7d = sum(all, pick("favorite"));
const visits24h = sum(all, pick("visit"));
return {
likes7d,
favorites7d,
visits24h
};
}
async getAllMetrics(options = {}) {
const {
source = "storage",
since = "7d",
name,
tags
} = options;
const metricSearchOptions = {
name,
tags
};
const containsMetricSearchOptions = Object.values(metricSearchOptions).filter(option => option !== undefined && option !== null);
const metrics = await this.contalyticsEngine.getMetricsSince(since, source, containsMetricSearchOptions > 0 ? metricSearchOptions : {});
return _assertClassBrand(_ContalyticsInstanceManager_brand, this, _dedupeByID).call(this, metrics, true, name);
}
async getItemMetrics(itemID, options = {}) {
const {
since,
source = "storage"
} = options;
const metrics = this.contalyticsEngine.searchByTagValue("itemID", itemID) || [];
if (!since) {
return metrics;
}
const storedMetrics = since ? await this.contalyticsEngine.getMetricsSince(since, source, {
tags: {
itemID
}
}) : [];
return _assertClassBrand(_ContalyticsInstanceManager_brand, this, _dedupeByID).call(this, metrics.concat(storedMetrics), true);
}
async getItemAnalyticsSummary(itemID, options = {}) {
const metrics = await this.getItemMetrics(itemID, options);
const calc = n => metrics.filter(r => r.name === `${_classPrivateFieldGet(_prefix, this)}.${n}`).reduce((s, r) => s + (r.value?.value ?? r.value ?? 0), 0);
return {
itemID,
offers: calc("offer.created"),
favorites: calc("favorite"),
bids: calc("bid.placed"),
reports: calc("report"),
visits: calc("visit"),
likes: calc("like")
};
}
getItemMetricTimeSeries(itemID, metric, options = {}) {
const {
interval = "hour",
range = 7 * 24 * 3600 * 1000,
aggregate = "sum"
} = options;
return this.contalyticsEngine.getTimeSeries(`${_classPrivateFieldGet(_prefix, this)}.${metric}`, {
interval,
range,
aggregate
});
}
async getTopItemsByMetric(metric = "visit", options = {}) {
const {
since = "7d",
source = "storage",
limit = 50,
whereTag = {}
} = options;
const metrics = await this.contalyticsEngine.getMetricsSince(since, source, {
name: `${_classPrivateFieldGet(_prefix, this)}.${metric}`,
tags: whereTag
});
const deduped = _assertClassBrand(_ContalyticsInstanceManager_brand, this, _dedupeByID).call(this, metrics, false, `${_classPrivateFieldGet(_prefix, this)}.${metric}`);
const score = new Map();
for (const metric of deduped) {
const t = metric.value?.tags || metric.tags || {};
const id = t.itemID;
if (!id) {
continue;
}
const v = metric.value?.value ?? metric.value ?? 0;
if (typeof v !== "number") {
continue;
}
score.set(id, (score.get(id) || 0) + v);
}
return [...score.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit).map(([itemID, total]) => ({
itemID,
total
}));
}
}
function _dedupeByID(records, filterPrefix = true, forceName) {
if (!Array.isArray(records)) {
return [];
}
const seen = new Set();
const out = [];
for (const r of records) {
const id = r.metricID || r.id;
if (id && seen.has(id)) {
continue;
}
seen.add(id);
if (forceName) {
if (r?.name === forceName) out.push(r);
} else if (!filterPrefix || r?.name?.startsWith(_classPrivateFieldGet(_prefix, this) + ".")) {
out.push(r);
}
}
return out;
}
;
module.exports = {
ContalyticsInstanceManager
};