summaryrefslogtreecommitdiff
path: root/node_modules/@jet/environment/metrics
diff options
context:
space:
mode:
authorrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
committerrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
commitbce557cc2dc767628bed6aac87301a1be7c5431b (patch)
treeb51a051228d01fe3306cd7626d4a96768aadb944 /node_modules/@jet/environment/metrics
init commit
Diffstat (limited to 'node_modules/@jet/environment/metrics')
-rw-r--r--node_modules/@jet/environment/metrics/builder.js456
-rw-r--r--node_modules/@jet/environment/metrics/cookies.js46
-rw-r--r--node_modules/@jet/environment/metrics/event-linter.js155
-rw-r--r--node_modules/@jet/environment/metrics/fetch-timing-metrics-builder.js96
-rw-r--r--node_modules/@jet/environment/metrics/helpers/index.js21
-rw-r--r--node_modules/@jet/environment/metrics/helpers/location.js213
-rw-r--r--node_modules/@jet/environment/metrics/helpers/models.js3
-rw-r--r--node_modules/@jet/environment/metrics/helpers/numerics.js23
-rw-r--r--node_modules/@jet/environment/metrics/helpers/util.js76
-rw-r--r--node_modules/@jet/environment/metrics/index.js23
-rw-r--r--node_modules/@jet/environment/metrics/parse-and-build-model.js116
11 files changed, 1228 insertions, 0 deletions
diff --git a/node_modules/@jet/environment/metrics/builder.js b/node_modules/@jet/environment/metrics/builder.js
new file mode 100644
index 0000000..935dd50
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/builder.js
@@ -0,0 +1,456 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.createMetricsMediaClickData = exports.createMetricsMediaData = exports.createMetricsImpressionsData = exports.createMetricsSearchData = exports.createMetricsPageData = exports.createMetricsBackClickData = exports.createMetricsClickData = exports.MediaClickEventBuilder = exports.MediaEventBuilder = exports.ImpressionsEventBuilder = exports.SearchEventBuilder = exports.PageEventBuilder = exports.BackClickEventBuilder = exports.ClickEventBuilder = exports.EventBuilder = void 0;
+const optional_1 = require("../types/optional");
+// region Builders
+/**
+ * Base event builder.
+ */
+class EventBuilder {
+ /**
+ * Create base event builder with metrics configuration.
+ *
+ * @param configuration - Metrics configuration used to build metrics events.
+ */
+ constructor(configuration) {
+ this.configuration = configuration;
+ this.eventFields = {};
+ }
+ /**
+ * Updates event builder with given event fields.
+ * @param eventFields - The events fields to update in builder.
+ * @returns Event builder with updated event fields.
+ */
+ withEventFields(eventFields) {
+ this.eventFields = eventFields;
+ return this;
+ }
+ /**
+ * Updates event builder with given configuration.
+ * @param configuration - The configuration to update in builder.
+ * @returns Event builder with updated configuration.
+ */
+ withConfiguration(configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+ /**
+ * Updates event builder with given default topic.
+ * @param topic - The default topic to update in builder.
+ * @returns Event builder with updated default topic.
+ */
+ withDefaultTopic(topic) {
+ this.configuration = {
+ ...this.configuration,
+ defaultTopic: topic,
+ };
+ return this;
+ }
+ /**
+ * Updates event builder with given include fields requests.
+ * @param includeRequests - The include fields requests to update in builder.
+ * @returns Event builder with updated include fields requests.
+ */
+ withDefaultIncludeRequests(includeRequests) {
+ this.configuration = {
+ ...this.configuration,
+ defaultIncludeRequests: includeRequests,
+ };
+ return this;
+ }
+ /**
+ * Updates event builder with given exclude fields requests.
+ * @param excludeRequests - The exclude fields requests to update in builder.
+ * @returns Event builder with updated exclude fields requests.
+ */
+ withDefaultExcludeRequests(excludeRequests) {
+ this.configuration = {
+ ...this.configuration,
+ defaultExcludeRequests: excludeRequests,
+ };
+ return this;
+ }
+ /**
+ * Updates event builder with given flush behavior.
+ * @param shouldFlush - The flush behavior to update in builder.
+ * @returns Event builder with updated flush behavior.
+ */
+ withShouldFlush(shouldFlush) {
+ this.configuration = {
+ ...this.configuration,
+ shouldFlush: shouldFlush,
+ };
+ return this;
+ }
+}
+exports.EventBuilder = EventBuilder;
+/**
+ * Builder for click events.
+ */
+class ClickEventBuilder extends EventBuilder {
+ /**
+ * Create click metrics event builder with all required properties.
+ *
+ * @param options - Object containing options required to create the builder.
+ *
+ * Options:
+ * - targetId - Target ID used for building events.
+ * - targetType - Target type used for building events.
+ * - configuration - Metrics configuration used to build metrics events.
+ */
+ constructor(options) {
+ super(options.configuration);
+ this.targetId = options.targetId;
+ this.targetType = options.targetType;
+ }
+ /**
+ * Updates event builder with given target ID.
+ * @param targetId - The target ID to update in builder.
+ * @returns Event builder with updated target ID.
+ */
+ withTargetId(targetId) {
+ this.targetId = targetId;
+ return this;
+ }
+ /**
+ * Updates event builder with given target type.
+ * @param targetType - The target type to update in builder.
+ * @returns Event builder with updated target type.
+ */
+ withTargetType(targetType) {
+ this.targetType = targetType;
+ return this;
+ }
+ build() {
+ return createMetricsClickData(this.targetId, this.targetType, this.eventFields, this.configuration);
+ }
+}
+exports.ClickEventBuilder = ClickEventBuilder;
+/**
+ * Builder for back click events.
+ */
+class BackClickEventBuilder extends EventBuilder {
+ build() {
+ return createMetricsBackClickData(this.eventFields, this.configuration);
+ }
+}
+exports.BackClickEventBuilder = BackClickEventBuilder;
+/**
+ * Builder for page events.
+ */
+class PageEventBuilder extends EventBuilder {
+ /**
+ * Create page metrics event builder with all required properties.
+ *
+ * @param configuration - Metrics configuration used to build metrics events.
+ */
+ constructor(configuration) {
+ super(configuration);
+ this.timingMetrics = {};
+ }
+ /**
+ * Updates event builder with given fetch timing metrics.
+ * @param timingMetrics - The fetch timing metrics to update in builder.
+ * @returns Event builder with updated fetch timing metrics.
+ */
+ withTimingMetrics(timingMetrics) {
+ this.timingMetrics = timingMetrics;
+ return this;
+ }
+ build() {
+ return createMetricsPageData(this.eventFields, this.timingMetrics, this.configuration);
+ }
+}
+exports.PageEventBuilder = PageEventBuilder;
+/**
+ * Builder for search metrics events.
+ */
+class SearchEventBuilder extends EventBuilder {
+ /**
+ * Create search metrics event builder with all required properties.
+ *
+ * @param options - Object containing options required to create the builder.
+ *
+ * Options:
+ * - term - Search term used to build metrics events.
+ * - targetType - Target type used to build metrics events.
+ * - actionType - Action type used to build metrics events.
+ * - configuration - Metrics configuration used to build metrics events.
+ */
+ constructor(options) {
+ super(options.configuration);
+ this.term = options.term;
+ this.targetType = options.targetType;
+ this.actionType = options.actionType;
+ this.actionUrl = null;
+ }
+ /**
+ * Updates event builder with given search term.
+ * @param term - The search term to update in builder.
+ * @returns Event builder with updated search term.
+ */
+ withTerm(term) {
+ this.term = term;
+ return this;
+ }
+ /**
+ * Updates event builder with given target type.
+ * @param targetType - The target type to update in builder.
+ * @returns Event builder with updated target type.
+ */
+ withTargetType(targetType) {
+ this.targetType = targetType;
+ return this;
+ }
+ /**
+ * Updates event builder with given action type.
+ * @param actionType - The action type to update in builder.
+ * @returns Event builder with updated action type.
+ */
+ withActionType(actionType) {
+ this.actionType = actionType;
+ return this;
+ }
+ /**
+ * Updates event builder with given action URL.
+ * @param actionUrl - The action URL to update in builder.
+ * @returns Event builder with updated action URL.
+ */
+ withActionUrl(actionUrl) {
+ this.actionUrl = actionUrl;
+ return this;
+ }
+ build() {
+ return createMetricsSearchData(this.term, this.targetType, this.actionType, this.actionUrl, this.eventFields, this.configuration);
+ }
+}
+exports.SearchEventBuilder = SearchEventBuilder;
+/**
+ * Builder for impressions events.
+ */
+class ImpressionsEventBuilder extends EventBuilder {
+ constructor() {
+ super(...arguments);
+ /**
+ * Impressions event version.
+ */
+ this.impressionsEventVersion = 4;
+ }
+ /**
+ * Updates event builder with given impressions event version.
+ * @param version - The impressions event version to update in builder.
+ * @returns Event builder with updated impressions event version.
+ */
+ withImpressionsEventVersion(version) {
+ this.impressionsEventVersion = version;
+ return this;
+ }
+ build() {
+ return createMetricsImpressionsData(this.eventFields, this.configuration, this.impressionsEventVersion);
+ }
+}
+exports.ImpressionsEventBuilder = ImpressionsEventBuilder;
+/**
+ * Builder for media events.
+ */
+class MediaEventBuilder extends EventBuilder {
+ build() {
+ return createMetricsMediaData(this.eventFields, this.configuration);
+ }
+}
+exports.MediaEventBuilder = MediaEventBuilder;
+/**
+ * Builder for media click events.
+ */
+class MediaClickEventBuilder extends EventBuilder {
+ /**
+ * Create media click event builder with all required properties.
+ *
+ * @param options - Object containing options required to create the builder.
+ *
+ * Options:
+ * - targetId - Target ID used for building events.
+ * - targetType - Target type used to build metrics events.
+ * - configuration - Metrics configuration used to build metrics events.
+ */
+ constructor(options) {
+ super(options.configuration);
+ this.targetId = options.targetId;
+ this.targetType = options.targetType;
+ }
+ /**
+ * Updates event builder with given target ID.
+ * @param targetId - The target ID to update in builder.
+ * @returns Event builder with updated target ID.
+ */
+ withTargetId(targetId) {
+ this.targetId = targetId;
+ return this;
+ }
+ /**
+ * Updates event builder with given target type.
+ * @param targetType - The target type to update in builder.
+ * @returns Event builder with updated target type.
+ */
+ withTargetType(targetType) {
+ this.targetType = targetType;
+ return this;
+ }
+ build() {
+ return createMetricsMediaClickData(this.targetId, this.targetType, this.eventFields, this.configuration);
+ }
+}
+exports.MediaClickEventBuilder = MediaClickEventBuilder;
+// region Metrics Data
+/**
+ * Create metrics data for the click event.
+ *
+ * @param targetId - The ID of the click event target.
+ * @param targetType - The type of the click target.
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsClickData(targetId, targetType, eventFields, configuration) {
+ const eventType = "click" /* MetricsEventType.click */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ targetType: targetType,
+ targetId: targetId,
+ };
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsClickData = createMetricsClickData;
+/**
+ * Create metrics data for the Back button click event.
+ *
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsBackClickData(eventFields, configuration) {
+ const fields = {
+ ...eventFields,
+ actionType: "back",
+ };
+ return createMetricsClickData("back", "button" /* MetricsClickTargetType.button */, fields, configuration);
+}
+exports.createMetricsBackClickData = createMetricsBackClickData;
+/**
+ * Create metrics data for the page event.
+ * @param eventFields - Event fields to create metrics data from.
+ * @param timingMetrics - The timing metrics for page data fetching.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsPageData(eventFields, timingMetrics, configuration) {
+ const eventType = "page" /* MetricsEventType.page */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ ...timingMetrics,
+ };
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsPageData = createMetricsPageData;
+/**
+ * Create metrics data for search event.
+ *
+ * @param term - The search term.
+ * @param target - The type of the acton target.
+ * @param actionType - The type of the action.
+ * @param actionUrl - An optional action URL.
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsSearchData(term, targetType, actionType, actionUrl, eventFields, configuration) {
+ const eventType = "search" /* MetricsEventType.search */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ term: term,
+ targetType: targetType,
+ actionType: actionType,
+ };
+ if ((0, optional_1.isSome)(actionUrl)) {
+ // actionUrl is defined for `hints` but not for searches fired from elsewhere.
+ fields["actionUrl"] = actionUrl;
+ }
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsSearchData = createMetricsSearchData;
+/**
+ * Create metrics data for impressions event.
+ *
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ * @param impressionsEventVersion - The version of the impressions event.
+ */
+function createMetricsImpressionsData(eventFields, configuration, impressionsEventVersion = 4) {
+ const eventType = "impressions" /* MetricsEventType.impressions */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ impressionQueue: "data-metrics",
+ eventVersion: impressionsEventVersion,
+ };
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsImpressionsData = createMetricsImpressionsData;
+/**
+ * Create metrics data for media event.
+ *
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsMediaData(eventFields, configuration) {
+ const eventType = "media" /* MetricsEventType.media */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ };
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsMediaData = createMetricsMediaData;
+/**
+ * Create metrics data for media event.
+ *
+ * @param targetId - The ID of the click target.
+ * @param targetType - The type of the click target.
+ * @param eventFields - Event fields to create metrics data from.
+ * @param configuration - Metrics configuration used to create metrics data.
+ */
+function createMetricsMediaClickData(targetId, targetType, eventFields, configuration) {
+ const eventType = "click" /* MetricsEventType.click */;
+ const fields = {
+ ...eventFields,
+ eventType: eventType,
+ targetType: targetType,
+ targetId: targetId,
+ };
+ return createMetricsData(fields, configuration, eventType);
+}
+exports.createMetricsMediaClickData = createMetricsMediaClickData;
+// endregion
+// region Helpers
+function createMetricsData(fields, configuration, eventType) {
+ return {
+ fields: fields,
+ includingFields: configuration.defaultIncludeRequests[eventType],
+ excludingFields: configuration.defaultExcludeRequests[eventType],
+ topic: topicFromEventFields(fields, configuration.defaultTopic),
+ shouldFlush: (0, optional_1.isSome)(configuration.shouldFlush) ? configuration.shouldFlush(fields) : false,
+ };
+}
+/**
+ * Returns event topic for the given event fields.
+ * @param eventFields - Event fields.
+ * @param defaultTopic - An optional default topic to use if event fields doesn't have one.
+ */
+function topicFromEventFields(eventFields, defaultTopic) {
+ const topic = eventFields["topic"];
+ if ((0, optional_1.isSome)(topic)) {
+ return topic;
+ }
+ return defaultTopic;
+}
+// endregion
+//# sourceMappingURL=builder.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/cookies.js b/node_modules/@jet/environment/metrics/cookies.js
new file mode 100644
index 0000000..ba46ef1
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/cookies.js
@@ -0,0 +1,46 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.cookieValueForKey = exports.cookiesOf = void 0;
+const optional_1 = require("../types/optional");
+/**
+ * Iterate the cookies contained in a string.
+ *
+ * @param cookie - A string containing zero or more cookies.
+ */
+function* cookiesOf(cookie) {
+ if ((0, optional_1.isNothing)(cookie)) {
+ return;
+ }
+ const rawEntries = cookie.split(";");
+ for (const rawEntry of rawEntries) {
+ const keyEndIndex = rawEntry.indexOf("=");
+ if (keyEndIndex === -1) {
+ // If there's no splitter, treat the whole raw
+ // entry as the key and provide an empty value.
+ const key = decodeURIComponent(rawEntry).trim();
+ yield { key, value: "" };
+ }
+ else {
+ const key = decodeURIComponent(rawEntry.substring(0, keyEndIndex)).trim();
+ const value = decodeURIComponent(rawEntry.substring(keyEndIndex + 1)).trim();
+ yield { key, value };
+ }
+ }
+}
+exports.cookiesOf = cookiesOf;
+/**
+ * Returns value of the cookie with the given key or `null` if there's no such cookie.
+ *
+ * @param cookies - Cookies.
+ * @param key - The key to return cookie value for.
+ */
+function cookieValueForKey(cookies, key) {
+ for (const cookie of cookies) {
+ if (cookie.key === key) {
+ return cookie.value;
+ }
+ }
+ return null;
+}
+exports.cookieValueForKey = cookieValueForKey;
+//# sourceMappingURL=cookies.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/event-linter.js b/node_modules/@jet/environment/metrics/event-linter.js
new file mode 100644
index 0000000..172afe7
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/event-linter.js
@@ -0,0 +1,155 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.EventLinter = void 0;
+const object_reader_1 = require("../json/reader/object-reader");
+const optional_1 = require("../types/optional");
+const numerics = require("./helpers/numerics");
+/**
+ * A type which applies common business rules to metrics fields
+ * and generates events which are ready for posting to Figaro.
+ *
+ * The common business rules are:
+ * - Add base event fields provided by linter configuration provider object
+ * - Set clientBuiltType and resourceRevNum fields based on EventLinterEnvironment object values
+ * - Set xpSendMethod field to "jet-js"
+ * - Combine pageType and pageId using compound separator provided by linter configuration provider
+ * and set result to "page" field.
+ * - Apply event field de-resolution rules provided by linter configuration provider object
+ * - Set the "position" field for events of "media" type.
+ */
+class EventLinter {
+ /**
+ * Create an event linter.
+ *
+ * @param options - The options which specify various behaviors of the new linter.
+ * This object will be frozen.
+ */
+ constructor(options) {
+ this.options = Object.freeze(options);
+ }
+ // MARK: Public Properties
+ /**
+ * Topic to use if an event fields blob does not specify one.
+ */
+ get defaultTopic() {
+ return this.options.defaultTopic;
+ }
+ // MARK: Utilities
+ /**
+ * Reduce the accuracy of fields in a blob according to
+ * a given array of rules provided by linter configuration object.
+ *
+ * @param eventFields - The fields of an event to reduce the accuracy of.
+ * @param rules - An array of de-resolution rules to apply to event fields.
+ */
+ applyDeResolutionRules(eventFields, rules) {
+ const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
+ for (const rule of rules) {
+ const value = eventFieldsReader.asNumber(rule.fieldName);
+ if ((0, optional_1.isNothing)(value)) {
+ continue;
+ }
+ let magnitude = rule.magnitude;
+ if ((0, optional_1.isNothing)(magnitude)) {
+ magnitude = 1024 * 1024;
+ }
+ let significantDigits = rule.significantDigits;
+ if ((0, optional_1.isNothing)(significantDigits)) {
+ significantDigits = 2;
+ }
+ if (magnitude <= 0.0 || significantDigits < 0.0) {
+ // This is the failure mode from MetricsKit.
+ eventFields[rule.fieldName] = Number.NaN;
+ continue;
+ }
+ const scaledValue = value / magnitude;
+ eventFields[rule.fieldName] = numerics.reduceSignificantDigits(scaledValue, significantDigits);
+ }
+ }
+ // MARK: Rules
+ /**
+ * Apply the rules which are universal to all metrics events
+ * to a given metrics fields linter.
+ *
+ * @param eventFields - The fields which will be used to construct a built event.
+ * @param topic - The topic the built event will be submitted to.
+ */
+ decorateCommonEventFields(eventFields, topic) {
+ const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
+ const configurationProvider = this.options.configuration;
+ // - Base metrics fields.
+ const baseFields = configurationProvider.baseFields(topic);
+ if ((0, optional_1.isSome)(baseFields)) {
+ Object.assign(eventFields, baseFields);
+ }
+ // - Universal basic fields.
+ eventFields["clientBuildType"] = this.options.environment.buildType;
+ eventFields["resourceRevNum"] = this.options.environment.jsVersion;
+ eventFields["xpSendMethod"] = "jet-js";
+ // - Page.
+ const pageType = eventFieldsReader.asString("pageType");
+ const pageId = eventFieldsReader.asString("pageId");
+ if ((0, optional_1.isSome)(pageType) && (0, optional_1.isSome)(pageId) && (0, optional_1.isNothing)(eventFields["page"])) {
+ const bagValue = configurationProvider.compoundSeparator(topic);
+ const separator = (0, optional_1.isSome)(bagValue) ? (0, optional_1.unwrapOptional)(bagValue) : "_";
+ eventFields["page"] = `${pageType}${separator}${pageId}`;
+ }
+ // - Field value resolution reduction.
+ const rules = configurationProvider.deResolutionRules(topic);
+ this.applyDeResolutionRules(eventFields, rules);
+ }
+ /**
+ * Apply the rules specific to the `media` event.
+ *
+ * @param eventFields - The fields which will be used to construct a built event.
+ */
+ decorateMediaEventEvents(eventFields) {
+ const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
+ const position = eventFieldsReader.asNumber("position");
+ if ((0, optional_1.isSome)(position)) {
+ eventFields["position"] = Math.round(position);
+ }
+ }
+ // MARK: Decorating Event Fields
+ /**
+ * Lint metrics event fields by applying the common business rules to a given fields blob.
+ *
+ * @remarks
+ *
+ * Note: A deep copy of event fields is created by linter using `JSON.parse(JSON.stringify(eventFields))`.
+ * The original event fields are not modified.
+ *
+ * @param eventFields - The fields to decorate.
+ * @param context - The additional event linter context to be passed to all
+ * event linter rules. This is a free-form object so clients can pass custom
+ * context information.
+ * @returns Decorated fields ready for creating a metrics event.
+ */
+ lint(eventFields, context = {}) {
+ const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
+ const eventType = eventFieldsReader.asString("eventType");
+ if (this.options.isLoggingEnabled) {
+ console.log(`Building event for event type: ${eventType !== null && eventType !== void 0 ? eventType : "<null>"}`);
+ }
+ // Make sure we have a deep copy of an object.
+ const decoratedEventFields = JSON.parse(JSON.stringify(eventFields));
+ const value = eventFieldsReader.asString("topic");
+ const topic = (0, optional_1.isSome)(value) ? (0, optional_1.unwrapOptional)(value) : this.options.defaultTopic;
+ this.decorateCommonEventFields(decoratedEventFields, topic);
+ switch (eventType) {
+ case "media" /* MetricsEventType.media */:
+ this.decorateMediaEventEvents(decoratedEventFields);
+ break;
+ default:
+ break;
+ }
+ for (const rule of this.options.rules) {
+ rule.apply(decoratedEventFields, context);
+ }
+ return {
+ fields: decoratedEventFields,
+ };
+ }
+}
+exports.EventLinter = EventLinter;
+//# sourceMappingURL=event-linter.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/fetch-timing-metrics-builder.js b/node_modules/@jet/environment/metrics/fetch-timing-metrics-builder.js
new file mode 100644
index 0000000..7a658ff
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/fetch-timing-metrics-builder.js
@@ -0,0 +1,96 @@
+"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 \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/helpers/index.js b/node_modules/@jet/environment/metrics/helpers/index.js
new file mode 100644
index 0000000..ee6bdeb
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/helpers/index.js
@@ -0,0 +1,21 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./location"), exports);
+__exportStar(require("./models"), exports);
+__exportStar(require("./numerics"), exports);
+__exportStar(require("./util"), exports);
+//# sourceMappingURL=index.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/helpers/location.js b/node_modules/@jet/environment/metrics/helpers/location.js
new file mode 100644
index 0000000..7bccd40
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/helpers/location.js
@@ -0,0 +1,213 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.MetricsLocationTracker = void 0;
+const validation = require("../../json/validation");
+const optional_1 = require("../../types/optional");
+const metricsUtil = require("./util");
+/**
+ * A type describing metrics location tracker.
+ *
+ * The tracker manages stack of metrics location items.
+ */
+class MetricsLocationTracker {
+ // endregion
+ // region Initialization
+ /**
+ * Create new metrics location tracker with all required attributes.
+ * @param rootPosition - Current root position of the tracker.
+ * @param locations - Array of metrics location to track.
+ */
+ constructor(rootPosition = 0, locations = []) {
+ this.rootPosition = rootPosition;
+ this.locationStack = locations.map((location) => new MetricsLocationStackItem(location));
+ }
+ // endregion
+ // region Location Stack Management
+ /**
+ * Check whether location stack is empty or not.
+ */
+ get isEmpty() {
+ return this.locationStack.length === 0;
+ }
+ /**
+ * Push new location to location tracker's stack.
+ * @param location - Location to push to stack.
+ */
+ pushLocation(location) {
+ this.locationStack.push(new MetricsLocationStackItem(location));
+ }
+ /**
+ * Pop location from location tracker's stack.
+ */
+ popLocation() {
+ var _a;
+ if (this.locationStack.length === 0) {
+ validation.unexpectedType("ignoredValue", "non-empty location stack", "empty location stack");
+ return null;
+ }
+ return (_a = this.locationStack.pop()) === null || _a === void 0 ? void 0 : _a.location;
+ }
+ /**
+ * Returns tracker's current position.
+ */
+ get currentPosition() {
+ const stackItem = this.lastStackItem;
+ if ((0, optional_1.isSome)(stackItem)) {
+ return stackItem.position;
+ }
+ else {
+ return this.rootPosition;
+ }
+ }
+ /**
+ * Set current position of tracker.
+ * This is necessary when large today modules are broken apart into multipart shelves.
+ * We need to preserve the position of content within server-response, not our logical shelves.
+ * @param position - Position to set to.
+ */
+ setCurrentPosition(position) {
+ const stackItem = this.lastStackItem;
+ if ((0, optional_1.isSome)(stackItem)) {
+ stackItem.position = position;
+ }
+ else {
+ this.rootPosition = position;
+ }
+ }
+ /**
+ * Advance tracker's position.
+ */
+ nextPosition() {
+ const stackItem = this.lastStackItem;
+ if ((0, optional_1.isSome)(stackItem)) {
+ stackItem.position += 1;
+ }
+ else {
+ this.rootPosition += 1;
+ }
+ }
+ /**
+ * Convert location tracker's stack items to array of metric location objects.
+ */
+ get stackItemsToLocations() {
+ return this.locationStack.map((stackItem) => stackItem.location);
+ }
+ /**
+ * Returns last stack item in location stack or `null` if stack is empty.
+ */
+ get lastStackItem() {
+ const length = this.locationStack.length;
+ if (length === 0) {
+ return null;
+ }
+ return this.locationStack[length - 1];
+ }
+ // endregion
+ // region Adding Location
+ /**
+ * Create new basic location and add it to existing locations of the location tracker
+ * and return resulting array of locations.
+ * @param options - Base metrics options which include location tracker to get current locations from.
+ * @param title - New location title.
+ */
+ static locationsByAddingBasicLocation(options, title) {
+ const locations = options.locationTracker.stackItemsToLocations;
+ locations.push(MetricsLocationTracker.buildBasicLocation(options, title));
+ return locations;
+ }
+ /**
+ * Create new content location and add it to existing locations of the location tracker
+ * and return resulting array of locations.
+ * @param options - Content metrics options which include location tracker to get current locations from.
+ * @param title - New location title.
+ */
+ static locationsByAddingContentLocation(options, title) {
+ const locations = options.locationTracker.stackItemsToLocations;
+ locations.push(MetricsLocationTracker.buildContentLocation(options, title));
+ return locations;
+ }
+ // endregion
+ // region Metrics Options
+ /**
+ * Create new basic location from base metrics options
+ * and push it to the stack of location tracker included into options.
+ * @param options - Base metrics options which include location tracker to push new location to.
+ * @param title - Location title.
+ */
+ static pushBasicLocation(options, title) {
+ options.locationTracker.pushLocation(MetricsLocationTracker.buildBasicLocation(options, title));
+ }
+ /**
+ * Create new content location from content metrics options
+ * and push it to the stack of location tracker included into options.
+ * @param options - Content metrics options which include location tracker to push new location to.
+ * @param title - Location title.
+ */
+ static pushContentLocation(options, title) {
+ options.locationTracker.pushLocation(MetricsLocationTracker.buildContentLocation(options, title));
+ }
+ /**
+ * Pop last location from location tracker contained in metrics options.
+ * @param options - Metrics options containing the location tracker.
+ */
+ static popLocation(options) {
+ return options.locationTracker.popLocation();
+ }
+ // endregion
+ // region Location Builders
+ static buildBasicLocation(options, title) {
+ let name = title;
+ if ((0, optional_1.isSome)(options.anonymizationOptions)) {
+ name = options.anonymizationOptions.anonymizationString;
+ }
+ const location = {
+ locationPosition: options.locationTracker.currentPosition,
+ locationType: metricsUtil.targetTypeForMetricsOptions(options),
+ name: name,
+ };
+ if ((0, optional_1.isSome)(options.recoMetricsData)) {
+ Object.assign(location, options.recoMetricsData);
+ }
+ return location;
+ }
+ static buildContentLocation(options, title) {
+ const base = MetricsLocationTracker.buildBasicLocation(options, title);
+ // Use the location tracker if there is no id override.
+ if ((0, optional_1.isNothing)(options.id)) {
+ base.idType = "sequential" /* MetricsIDType.sequential */;
+ base.id = options.locationTracker.currentPosition.toString();
+ }
+ else {
+ // If there is a id specified, use that.
+ base.idType = metricsUtil.idTypeForMetricsOptions(options);
+ let id = options.id;
+ if ((0, optional_1.isSome)(options.anonymizationOptions)) {
+ id = options.anonymizationOptions.anonymizationString;
+ }
+ base.id = id;
+ }
+ if ((0, optional_1.isSome)(options.fcKind)) {
+ base.fcKind = options.fcKind;
+ }
+ if ((0, optional_1.isSome)(options.displayStyle)) {
+ base.displayStyle = options.displayStyle;
+ }
+ return base;
+ }
+}
+exports.MetricsLocationTracker = MetricsLocationTracker;
+/**
+ * A type describing a metrics location item in location tracking stack.
+ */
+class MetricsLocationStackItem {
+ /**
+ * Create new metrics location stack item with all required attributes.
+ * @param location - The metrics location associated with this item.
+ * @param position - The position of the item.
+ */
+ constructor(location, position = 0) {
+ this.location = location;
+ this.position = position;
+ }
+}
+//# sourceMappingURL=location.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/helpers/models.js b/node_modules/@jet/environment/metrics/helpers/models.js
new file mode 100644
index 0000000..b2dccd6
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/helpers/models.js
@@ -0,0 +1,3 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//# sourceMappingURL=models.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/helpers/numerics.js b/node_modules/@jet/environment/metrics/helpers/numerics.js
new file mode 100644
index 0000000..822f51f
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/helpers/numerics.js
@@ -0,0 +1,23 @@
+"use strict";
+/**
+ * Number related helper functions for metrics.
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.reduceSignificantDigits = void 0;
+/**
+ * Reduce significant figures of `value` by `significantDigits`.
+ * @param value - Value to reduce precision of.
+ * @param significantDigits - Number of significant digits to reduce precision by.
+ *
+ * Examples:
+ * value = 123.5, significantDigits = 0, result = 120 (no significant digit reduced)
+ * value = 123.5, significantDigits = 1, result = 120 (1 significant digit reduced)
+ * value = 123.5, significantDigits = 2, result = 100 (2 significant digit reduced)
+ */
+function reduceSignificantDigits(value, significantDigits) {
+ const roundFactor = Math.pow(10.0, significantDigits);
+ const roundingFunction = value > 0.0 ? Math.floor : Math.ceil;
+ return roundingFunction(value / roundFactor) * roundFactor;
+}
+exports.reduceSignificantDigits = reduceSignificantDigits;
+//# sourceMappingURL=numerics.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/helpers/util.js b/node_modules/@jet/environment/metrics/helpers/util.js
new file mode 100644
index 0000000..00c739a
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/helpers/util.js
@@ -0,0 +1,76 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.searchTermFromRefURL = exports.extractSiriRefAppFromRefURL = exports.idTypeForMetricsOptions = exports.targetTypeForMetricsOptions = void 0;
+const optional_1 = require("../../types/optional");
+const urls = require("../../util/urls");
+/**
+ * Returns click target type for given base metrics options.
+ * @param options - Base metrics options to derive click target type for.
+ */
+function targetTypeForMetricsOptions(options) {
+ let type = options.targetType;
+ if ((0, optional_1.isNothing)(type)) {
+ type = "lockup" /* MetricsClickTargetType.lockup */;
+ }
+ return type;
+}
+exports.targetTypeForMetricsOptions = targetTypeForMetricsOptions;
+/**
+ * Returns metrics ID type for given content metrics options.
+ * @param options - Content metrics options to derive metrics ID type for.
+ */
+function idTypeForMetricsOptions(options) {
+ let type = options.idType;
+ if ((0, optional_1.isNothing)(type)) {
+ type = "its_id" /* MetricsIDType.itsID */;
+ }
+ return type;
+}
+exports.idTypeForMetricsOptions = idTypeForMetricsOptions;
+/**
+ * Extract and return Siri reference app from URL string.
+ * @param refUrlString - URL string.
+ * @returns An optional Siri reference app string.
+ */
+function extractSiriRefAppFromRefURL(urlString) {
+ const refUrl = new urls.URL(urlString);
+ if ((0, optional_1.isNothing)(refUrl.query)) {
+ return null;
+ }
+ let extractedRefApp = null;
+ for (const key of Object.keys(refUrl.query)) {
+ if (key === "referrer") {
+ if (refUrl.query[key] === "siri") {
+ extractedRefApp = "com.apple.siri";
+ }
+ break;
+ }
+ }
+ return extractedRefApp;
+}
+exports.extractSiriRefAppFromRefURL = extractSiriRefAppFromRefURL;
+/**
+ * Extract and return search term from reference URL string.
+ * @param refUrlString - Reference URL string.
+ * @returns An optional search term string.
+ */
+function searchTermFromRefURL(refUrlString) {
+ const refUrl = new urls.URL(refUrlString);
+ const queryItems = refUrl.query;
+ if ((0, optional_1.isNothing)(queryItems)) {
+ return null;
+ }
+ const searchTerm = queryItems["term"];
+ const path = refUrl.pathname;
+ if ((0, optional_1.isNothing)(searchTerm) || (0, optional_1.isNothing)(path)) {
+ return null;
+ }
+ if (!path.endsWith("/search")) {
+ return null;
+ }
+ // the url object has already url-decoded this query parameter
+ const plainTerm = searchTerm;
+ return plainTerm;
+}
+exports.searchTermFromRefURL = searchTermFromRefURL;
+//# sourceMappingURL=util.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/index.js b/node_modules/@jet/environment/metrics/index.js
new file mode 100644
index 0000000..44c4a8f
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/index.js
@@ -0,0 +1,23 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+__exportStar(require("./builder"), exports);
+__exportStar(require("./cookies"), exports);
+__exportStar(require("./event-linter"), exports);
+__exportStar(require("./fetch-timing-metrics-builder"), exports);
+__exportStar(require("./helpers"), exports);
+__exportStar(require("./parse-and-build-model"), exports);
+//# sourceMappingURL=index.js.map \ No newline at end of file
diff --git a/node_modules/@jet/environment/metrics/parse-and-build-model.js b/node_modules/@jet/environment/metrics/parse-and-build-model.js
new file mode 100644
index 0000000..6f81a59
--- /dev/null
+++ b/node_modules/@jet/environment/metrics/parse-and-build-model.js
@@ -0,0 +1,116 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.parseAndBuildModel = exports.requestAndBuildModel = void 0;
+const dependencies_1 = require("../dependencies");
+const optional_1 = require("../types/optional");
+const fetch_timing_metrics_builder_1 = require("./fetch-timing-metrics-builder");
+/**
+ * Returns an object graph guaranteed to have a `FetchTimingMetricsBuilder` object.
+ *
+ * If a `FetchTimingMetricsBuilder` already exists, the same object graph is returned.
+ *
+ * If it doesn't exist, a new object graph is returned, which has a new `FetchTimingMetricsBuilder` added to it.
+ */
+function ensureFetchTimingMetricsBuilderExists(objectGraph, errorIfNotFound) {
+ const optionalBuilder = objectGraph.optional(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType);
+ if ((0, optional_1.isSome)(optionalBuilder)) {
+ return objectGraph;
+ }
+ else {
+ if (errorIfNotFound) {
+ throw new Error("Could not find FetchTimingMetricsBuilder in the object graph");
+ }
+ return objectGraph.adding(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, new fetch_timing_metrics_builder_1.FetchTimingMetricsBuilder());
+ }
+}
+/**
+ * Orchestrates the flow to make a network request and then build the view model,
+ * capturing timing points around the model building step, and then
+ * adding performance metrics data to the final result.
+ *
+ * **Important**
+ *
+ * When using this method, it is the responsibility of the `requester` to instrument the network times and parsing times
+ * using a `FetchTimingMetricsBuilder` which is in the object graph.
+ *
+ * A simplified implementation of a requester function might look like this:
+```
+ import * as types from "@jet/environment/types/globals/types"
+ import { fetchTimingMetricsBuilderType } from "@jet/environment/metrics";
+
+ export async function requestFromAPI(request: FetchRequest, objectGraph: ObjectGraph): Promise<MyParsedModel> {
+ const net = inject(types.net, objectGraph);
+ const fetchResponse = await net.fetch(request);
+ const fetchTimingMetricsBuilder = inject(fetchTimingMetricsBuilderType, objectGraph);
+ return fetchTimingMetricsBuilder.measureParsing(fetchResponse, (response) => {
+ const parsedBody = JSON.parse(response.body);
+ return new MyParsedModel(parsedBody);
+ });
+ }
+```
+ * This approach supports a common pattern in our adopters in which the code that coordinates the fetch of the network request
+ * is tightly coupled to the code which parses the response.
+ *
+ * For an alternative approach which includes orchestrating the parsing step, use `parseAndBuildModel()`.
+ *
+ * @param request - The request object to pass to the `requester` function.
+ * @param objectGraph - Object graph that can be used to pass data to the `requester` and `modelBuilder` steps.
+ * The object graph must contain a `FetchTimingMetricsBuilder` that the `requester` will use to collect network times and parsing times.
+ * @param requester - A function which can make a network request, and return a `ResponseType` which can be used by the `modelBuilder`.
+ * @param modelBuilder - A step that takes the output of the `requester` step, and builds the view model.
+ * This parameter supports both synchronous and asynchronous functions.
+ * @returns The view model.
+ */
+async function requestAndBuildModel(request, objectGraph, requester, modelBuilder) {
+ const modifiedObjectGraph = ensureFetchTimingMetricsBuilderExists(objectGraph, true);
+ const response = await requester(request, modifiedObjectGraph);
+ return await constructAndDecorateModel(response, modifiedObjectGraph, modelBuilder);
+}
+exports.requestAndBuildModel = requestAndBuildModel;
+/**
+ * Orchestrates the flow to parse a `FetchResponse` and then build the view model,
+ * adding performance metrics data to the final result.
+ *
+ * Timing points are captured around the parsing and model building steps,
+ * and this is added to the metrics which were returned from the `FetchResponse`.
+ *
+ * When using this method, it is the responsibility of the caller
+ * to perform the network fetch in order to have a `FetchResponse` object.
+ * The parsing logic which transforms the `FetchResponse` object into an intermediate model object
+ * will need to be decoupled so that it can be implemented in the `parser` function.
+ *
+ * @param response - The response from a `Network.fetch()` call.
+ * @param objectGraph - Object graph that can be used to pass data to the `parser` and `renderer` steps.
+ * @param parser - A step that parses a `FetchResponse` to an intermediate model object.
+ * @param modelBuilder - A step that takes the output of the `parser` step, and builds the view model.
+ * This parameter supports both synchronous and asynchronous functions.
+ * @returns The view model.
+ */
+async function parseAndBuildModel(response, objectGraph, parser, modelBuilder) {
+ const modifiedObjectGraph = ensureFetchTimingMetricsBuilderExists(objectGraph, false);
+ const fetchTimingMetricsBuilder = (0, dependencies_1.inject)(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, modifiedObjectGraph);
+ // Add metrics from FetchResponse, and run the parser, capturing timing points.
+ const parsedObject = fetchTimingMetricsBuilder.measureParsing(response, () => {
+ return parser(response, modifiedObjectGraph);
+ });
+ if ((0, optional_1.isNothing)(parsedObject)) {
+ throw new Error("parser function returned null or undefined");
+ }
+ return await constructAndDecorateModel(parsedObject, modifiedObjectGraph, modelBuilder);
+}
+exports.parseAndBuildModel = parseAndBuildModel;
+async function constructAndDecorateModel(parsedObject, objectGraph, modelBuilder) {
+ const fetchTimingMetricsBuilder = (0, dependencies_1.inject)(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, objectGraph);
+ // Run the model builder, capturing timing points.
+ const model = await fetchTimingMetricsBuilder.measureModelConstructionAsync(async () => {
+ const maybePromise = modelBuilder(parsedObject, objectGraph); // The actual model, or a Promise of the model.
+ return await Promise.resolve(maybePromise); // If it was promise, it will await until the promise is resolved.
+ });
+ if ((0, optional_1.isNothing)(model)) {
+ throw new Error("model builder function returned null or undefined");
+ }
+ // Decorate the final output with the metrics data.
+ fetchTimingMetricsBuilder.decorate(model);
+ return model;
+}
+//# sourceMappingURL=parse-and-build-model.js.map \ No newline at end of file