UNPKG

@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
"use strict"; 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 };