Skip to main content
Glama
index.js10.8 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { createLogger } from '../../utils/logger'; import { isBoolean, isNullish, isNumber, isObject, isUndefined } from '../../utils/type-utils'; import { WEB_VITALS_ALLOWED_METRICS, WEB_VITALS_ENABLED_SERVER_SIDE } from '../../constants'; import { assignableWindow, window } from '../../utils/globals'; var logger = createLogger('[Web Vitals]'); export var DEFAULT_FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS = 5000; var ONE_MINUTE_IN_MILLIS = 60 * 1000; export var FIFTEEN_MINUTES_IN_MILLIS = 15 * ONE_MINUTE_IN_MILLIS; var WebVitalsAutocapture = /** @class */ (function () { function WebVitalsAutocapture(instance) { var _this = this; var _a; this.instance = instance; this._enabledServerSide = false; this._initialized = false; this.buffer = { url: undefined, metrics: [], firstMetricTimestamp: undefined }; this._flushToCapture = function () { clearTimeout(_this._delayedFlushTimer); if (_this.buffer.metrics.length === 0) { return; } _this.instance.capture('$web_vitals', _this.buffer.metrics.reduce(function (acc, metric) { var _a; return (__assign(__assign({}, acc), (_a = {}, _a["$web_vitals_".concat(metric.name, "_event")] = __assign({}, metric), _a["$web_vitals_".concat(metric.name, "_value")] = metric.value, _a))); }, {})); _this.buffer = { url: undefined, metrics: [], firstMetricTimestamp: undefined }; }; this._addToBuffer = function (metric) { var _a; var sessionIds = (_a = _this.instance.sessionManager) === null || _a === void 0 ? void 0 : _a.checkAndGetSessionAndWindowId(true); if (isUndefined(sessionIds)) { logger.error('Could not read session ID. Dropping metrics!'); return; } _this.buffer = _this.buffer || { url: undefined, metrics: [], firstMetricTimestamp: undefined }; var $currentUrl = _this._currentURL(); if (isUndefined($currentUrl)) { return; } if (isNullish(metric === null || metric === void 0 ? void 0 : metric.name) || isNullish(metric === null || metric === void 0 ? void 0 : metric.value)) { logger.error('Invalid metric received', metric); return; } // we observe some very large values sometimes, we'll ignore them // since the likelihood of LCP > 1 hour being correct is very low if (_this._maxAllowedValue && metric.value >= _this._maxAllowedValue) { logger.error('Ignoring metric with value >= ' + _this._maxAllowedValue, metric); return; } var urlHasChanged = _this.buffer.url !== $currentUrl; if (urlHasChanged) { // we need to send what we have _this._flushToCapture(); // poor performance is >4s, we wait twice that time to send // this is in case we haven't received all metrics // we'll at least gather some _this._delayedFlushTimer = setTimeout(_this._flushToCapture, _this.flushToCaptureTimeoutMs); } if (isUndefined(_this.buffer.url)) { _this.buffer.url = $currentUrl; } _this.buffer.firstMetricTimestamp = isUndefined(_this.buffer.firstMetricTimestamp) ? Date.now() : _this.buffer.firstMetricTimestamp; if (metric.attribution && metric.attribution.interactionTargetElement) { // we don't want to send the entire element // they can be very large // TODO we could run this through autocapture code so that we get elements chain info // and can display the element in the UI metric.attribution.interactionTargetElement = undefined; } _this.buffer.metrics.push(__assign(__assign({}, metric), { $current_url: $currentUrl, $session_id: sessionIds.sessionId, $window_id: sessionIds.windowId, timestamp: Date.now() })); if (_this.buffer.metrics.length === _this.allowedMetrics.length) { // we have all allowed metrics _this._flushToCapture(); } }; this._startCapturing = function () { var _a; var onLCP; var onCLS; var onFCP; var onINP; var posthogExtensions = assignableWindow.__PosthogExtensions__; if (!isUndefined(posthogExtensions) && !isUndefined(posthogExtensions.postHogWebVitalsCallbacks)) { ; (_a = posthogExtensions.postHogWebVitalsCallbacks, onLCP = _a.onLCP, onCLS = _a.onCLS, onFCP = _a.onFCP, onINP = _a.onINP); } if (!onLCP || !onCLS || !onFCP || !onINP) { logger.error('web vitals callbacks not loaded - not starting'); return; } // register performance observers if (_this.allowedMetrics.indexOf('LCP') > -1) { onLCP(_this._addToBuffer.bind(_this)); } if (_this.allowedMetrics.indexOf('CLS') > -1) { onCLS(_this._addToBuffer.bind(_this)); } if (_this.allowedMetrics.indexOf('FCP') > -1) { onFCP(_this._addToBuffer.bind(_this)); } if (_this.allowedMetrics.indexOf('INP') > -1) { onINP(_this._addToBuffer.bind(_this)); } _this._initialized = true; }; this._enabledServerSide = !!((_a = this.instance.persistence) === null || _a === void 0 ? void 0 : _a.props[WEB_VITALS_ENABLED_SERVER_SIDE]); this.startIfEnabled(); } Object.defineProperty(WebVitalsAutocapture.prototype, "allowedMetrics", { get: function () { var _a, _b; var clientConfigMetricAllowList = isObject(this.instance.config.capture_performance) ? (_a = this.instance.config.capture_performance) === null || _a === void 0 ? void 0 : _a.web_vitals_allowed_metrics : undefined; return !isUndefined(clientConfigMetricAllowList) ? clientConfigMetricAllowList : ((_b = this.instance.persistence) === null || _b === void 0 ? void 0 : _b.props[WEB_VITALS_ALLOWED_METRICS]) || ['CLS', 'FCP', 'INP', 'LCP']; }, enumerable: false, configurable: true }); Object.defineProperty(WebVitalsAutocapture.prototype, "flushToCaptureTimeoutMs", { get: function () { var clientConfig = isObject(this.instance.config.capture_performance) ? this.instance.config.capture_performance.web_vitals_delayed_flush_ms : undefined; return clientConfig || DEFAULT_FLUSH_TO_CAPTURE_TIMEOUT_MILLISECONDS; }, enumerable: false, configurable: true }); Object.defineProperty(WebVitalsAutocapture.prototype, "_maxAllowedValue", { get: function () { var configured = isObject(this.instance.config.capture_performance) && isNumber(this.instance.config.capture_performance.__web_vitals_max_value) ? this.instance.config.capture_performance.__web_vitals_max_value : FIFTEEN_MINUTES_IN_MILLIS; // you can set to 0 to disable the check or any value over ten seconds // 1 milli to 1 minute will be set to 15 minutes, cos that would be a silly low maximum return 0 < configured && configured <= ONE_MINUTE_IN_MILLIS ? FIFTEEN_MINUTES_IN_MILLIS : configured; }, enumerable: false, configurable: true }); Object.defineProperty(WebVitalsAutocapture.prototype, "isEnabled", { get: function () { var clientConfig = isObject(this.instance.config.capture_performance) ? this.instance.config.capture_performance.web_vitals : undefined; return isBoolean(clientConfig) ? clientConfig : this._enabledServerSide; }, enumerable: false, configurable: true }); WebVitalsAutocapture.prototype.startIfEnabled = function () { if (this.isEnabled && !this._initialized) { logger.info('enabled, starting...'); this.loadScript(this._startCapturing); } }; WebVitalsAutocapture.prototype.onRemoteConfig = function (response) { var _a, _b; var webVitalsOptIn = isObject(response.capturePerformance) && !!response.capturePerformance.web_vitals; var allowedMetrics = isObject(response.capturePerformance) ? response.capturePerformance.web_vitals_allowed_metrics : undefined; if (this.instance.persistence) { this.instance.persistence.register((_a = {}, _a[WEB_VITALS_ENABLED_SERVER_SIDE] = webVitalsOptIn, _a)); this.instance.persistence.register((_b = {}, _b[WEB_VITALS_ALLOWED_METRICS] = allowedMetrics, _b)); } // store this in-memory in case persistence is disabled this._enabledServerSide = webVitalsOptIn; this.startIfEnabled(); }; WebVitalsAutocapture.prototype.loadScript = function (cb) { var _a, _b, _c; if ((_a = assignableWindow.__PosthogExtensions__) === null || _a === void 0 ? void 0 : _a.postHogWebVitalsCallbacks) { // already loaded cb(); } (_c = (_b = assignableWindow.__PosthogExtensions__) === null || _b === void 0 ? void 0 : _b.loadExternalDependency) === null || _c === void 0 ? void 0 : _c.call(_b, this.instance, 'web-vitals', function (err) { if (err) { logger.error('failed to load script', err); return; } cb(); }); }; WebVitalsAutocapture.prototype._currentURL = function () { // TODO you should be able to mask the URL here var href = window ? window.location.href : undefined; if (!href) { logger.error('Could not determine current URL'); } return href; }; return WebVitalsAutocapture; }()); export { WebVitalsAutocapture }; //# sourceMappingURL=index.js.map

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sadiuysal/mem0-mcp-server-ts'

If you have feedback or need assistance with the MCP directory API, please join our Discord server