"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetchTimingMetricsBuilderType = exports.FetchTimingMetricsBuilder = void 0; const optional_1 = require("../types/optional"); const metatype_1 = require("../util/metatype"); const promise_1 = require("../util/promise"); /** Object to collect `FetchTimingMetrics`, in order to decorate a model object with these metrics. */ class FetchTimingMetricsBuilder { constructor() { this.metrics = []; } /** * Collects the timing metrics from the response, * then execute code for parsing while capturing timing points around it, * adding those parse times to the first timing metrics. */ measureParsing(response, body) { const responseTimingMetrics = response.metrics.length > 0 ? [...response.metrics] : []; const parseStartTime = Date.now(); const result = body(response); const parseEndTime = Date.now(); // MAINTAINERS NOTE: // Follows app store approach to add additional timing points to the first item. // This may not be strictly correct, and we should revisit this later. if (responseTimingMetrics.length > 0) { responseTimingMetrics[0].parseStartTime = parseStartTime; responseTimingMetrics[0].parseEndTime = parseEndTime; } this.metrics.push(...responseTimingMetrics); return result; } /** * Execute code for model construction while capturing timing points around it, * adding those model construction times to the first timing metrics. * * Use this method when model construction is a synchronous operation. * Use `measureModelConstructionAsync()` when model construction is an asynchronous operation. */ measureModelConstruction(body) { const buildModelStartTime = Date.now(); const result = body(); const buildModelEndTime = Date.now(); this.saveModelConstructionTimes(buildModelStartTime, buildModelEndTime); return result; } /** * Execute and await code for an asynchronous model construction operation while capturing timing points around it, * adding those model construction times to the first timing metrics. * * Use this method when model construction is an asynchronous operation. * Use `measureModelConstruction()` when model construction is a synchronous operation. */ async measureModelConstructionAsync(body) { const buildModelStartTime = Date.now(); const result = await body(); const buildModelEndTime = Date.now(); this.saveModelConstructionTimes(buildModelStartTime, buildModelEndTime); return result; } saveModelConstructionTimes(startTime, endTime) { // MAINTAINERS NOTE: // Follows app store approach to add additional timing points to the first item. // This may not be strictly correct, and we should revisit this later. if (this.metrics.length > 0) { this.metrics[0].modelConstructionStartTime = startTime; this.metrics[0].modelConstructionEndTime = endTime; } else { this.metrics.push({ modelConstructionStartTime: startTime, modelConstructionEndTime: endTime, }); } } /** Add the recorded `FetchTimingMetrics` as an additional property on the model. */ decorate(model) { if ((0, optional_1.isNothing)(model)) { throw new Error("Cannot decorate null or undefined"); } if (typeof model !== "object") { throw new Error("View model to decorate must be an object"); } if ((0, promise_1.isPromise)(model)) { // TypeScript compiler may be able to enforce this at compile time. // A newer version of TypeScript which supports `Awaited` type may help. throw new Error("Cannot decorate a Promise object"); } if (this.metrics.length > 0) { model["$networkPerformance"] = this.metrics; } } } exports.FetchTimingMetricsBuilder = FetchTimingMetricsBuilder; /** Metatype for the `FetchTimingMetricsBuilder`, for adding to an object graph. */ exports.fetchTimingMetricsBuilderType = (0, metatype_1.makeMetatype)("jet-engine:fetchTimingMetricsBuilder"); //# sourceMappingURL=fetch-timing-metrics-builder.js.map