@klevu/core
Version:
Typescript SDK that simplifies development on Klevu backend. Klevu provides advanced AI-powered search and discovery solutions for online retailers.
309 lines (308 loc) • 14.4 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _KlevuResponseQueryObject_instances, _KlevuResponseQueryObject_initRedirects, _KlevuResponseQueryObject_initEventFunctions;
Object.defineProperty(exports, "__esModule", { value: true });
exports.KlevuResponseQueryObject = void 0;
const KlevuEvents_js_1 = require("../events/KlevuEvents.js");
const index_js_1 = require("../modifiers/index.js");
const extractActiveFilters_js_1 = require("../utils/extractActiveFilters.js");
const klevuFetch_js_1 = require("./klevuFetch.js");
const getAnnotationsForProduct_js_1 = require("./resultHelpers/getAnnotationsForProduct.js");
const getBanners_js_1 = require("./resultHelpers/getBanners.js");
const getRedirects_js_1 = require("./resultHelpers/getRedirects.js");
/**
* Result object for each query. A storage for results. Can be used to fetch more data, send events etc.
*/
class KlevuResponseQueryObject {
constructor(responseObject, query, func) {
_KlevuResponseQueryObject_instances.add(this);
/**
* Hooks that can be used to listen for events
*/
this.hooks = [];
this.responseObject = responseObject;
this.query = query;
this.func = func;
__classPrivateFieldGet(this, _KlevuResponseQueryObject_instances, "m", _KlevuResponseQueryObject_initEventFunctions).call(this);
__classPrivateFieldGet(this, _KlevuResponseQueryObject_instances, "m", _KlevuResponseQueryObject_initRedirects).call(this);
}
/**
* All filters related to this query
*/
get filters() {
return this.query.filters;
}
/**
* Id if the query
*/
get id() {
return this.query.id;
}
/**
* Meta data of the query
*/
get meta() {
return this.query.meta;
}
/**
* Records of the query
*/
get records() {
return this.query.records;
}
/**
* Special parameters that are saved to query
*/
get functionParams() {
return this.func.params;
}
/**
* Fetches page of results. If pageIndex is not defined it will fetch next page.
*
* @param params
* @returns
*/
getPage(params) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
const newFunc = Object.assign({}, this.func);
const prevQueryResponse = this.query;
if (!newFunc.queries) {
return undefined;
}
for (let i = 0; i < newFunc.queries.length; i++) {
const prevQuery = newFunc.queries[i];
if (!prevQuery.settings) {
prevQuery.settings = {};
}
if ((params === null || params === void 0 ? void 0 : params.pageIndex) !== undefined) {
prevQuery.settings.offset =
prevQueryResponse.meta.noOfResults * params.pageIndex;
}
else {
prevQuery.settings.offset =
prevQueryResponse.meta.noOfResults + prevQueryResponse.meta.offset;
}
prevQuery.settings.limit = (_c = (_a = params === null || params === void 0 ? void 0 : params.limit) !== null && _a !== void 0 ? _a : (_b = prevQuery.settings) === null || _b === void 0 ? void 0 : _b.limit) !== null && _c !== void 0 ? _c : 5;
newFunc.queries[i] = prevQuery;
}
// add previous filters with manager
if (params === null || params === void 0 ? void 0 : params.filterManager) {
if (!newFunc.modifiers) {
newFunc.modifiers = [];
}
newFunc.modifiers.push((0, index_js_1.applyFilterWithManager)(params.filterManager));
}
newFunc.previousResultRecords = [
...((_d = this.func.previousResultRecords) !== null && _d !== void 0 ? _d : []),
...prevQueryResponse.records,
];
return yield (0, klevuFetch_js_1.KlevuFetch)((0, klevuFetch_js_1.removeListFilters)(newFunc, prevQueryResponse));
});
}
/**
*
* @returns true if there are more pages to fetch
*/
hasNextPage() {
return (this.query.meta.totalResultsFound >
this.query.meta.offset + this.query.meta.noOfResults);
}
/**
*
* @returns total number of pages
*/
getTotalPages() {
return Math.ceil(this.query.meta.totalResultsFound / this.query.meta.offset);
}
annotationsById(productId, languageCode) {
return (0, getAnnotationsForProduct_js_1.getAnnotationsForProduct)(this.query, productId, languageCode);
}
/**
* @returns List of banners that were received for this query
* @param params in case of search query you need to specify location of search
*/
getBanners(params = {}) {
return __awaiter(this, void 0, void 0, function* () {
return (0, getBanners_js_1.getBanners)(this, params.searchType);
});
}
/**
* @returns List of params used in the query and the metadata that was generated during
* the query. This is useful for example to fetching KMC metadata that was received
* for recommendations query.
*/
getQueryParameters() {
return this.func.params;
}
}
exports.KlevuResponseQueryObject = KlevuResponseQueryObject;
_KlevuResponseQueryObject_instances = new WeakSet(), _KlevuResponseQueryObject_initRedirects = function _KlevuResponseQueryObject_initRedirects() {
if (this.func.klevuFunctionId === "search") {
this.getRedirects = () => {
var _a;
if (!((_a = this.func.params) === null || _a === void 0 ? void 0 : _a.term)) {
return Promise.resolve([]);
}
return (0, getRedirects_js_1.getRedirects)(this.func.params.term);
};
}
}, _KlevuResponseQueryObject_initEventFunctions = function _KlevuResponseQueryObject_initEventFunctions() {
var _a, _b, _c;
switch ((_a = this.func) === null || _a === void 0 ? void 0 : _a.klevuFunctionId) {
case "search": {
this.searchClickEvent = function ({ productId, variantId, autoSendViewEvent = true, override, }) {
var _a, _b, _c;
if (!this.func) {
return;
}
if (autoSendViewEvent && !((_a = this.func.params) === null || _a === void 0 ? void 0 : _a.searchSendEventSent)) {
KlevuEvents_js_1.KlevuEvents.search({
term: this.query.meta.searchedTerm,
totalResults: this.query.meta.noOfResults,
typeOfSearch: this.query.meta.typeOfSearch,
activeFilters: (0, extractActiveFilters_js_1.extractActiveFilters)(this.query),
override,
tags: this.query.meta.tags,
});
if (!this.func.params) {
this.func.params = {};
}
this.func.params.searchSendEventSent = true;
}
const record = [
...this.query.records,
...((_b = this.func.previousResultRecords) !== null && _b !== void 0 ? _b : []),
].find((r) => r.id === productId);
if (!record) {
throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
}
KlevuEvents_js_1.KlevuEvents.searchProductClick({
product: record,
searchTerm: this.query.meta.searchedTerm,
variantId,
tags: this.query.meta.tags,
});
for (const hook of (_c = this.hooks) !== null && _c !== void 0 ? _c : []) {
hook({ type: "search", productId, variantId });
}
};
break;
}
case "categoryMerchandising": {
this.categoryMerchandisingClickEvent = function ({ productId, categoryTitle, variantId, override, }) {
var _a, _b, _c, _d, _e, _f;
if (!this.func) {
return;
}
const record = [
...this.query.records,
...((_a = this.func.previousResultRecords) !== null && _a !== void 0 ? _a : []),
].find((r) => r.id === productId);
if (!record) {
throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
}
const index = this.query.records.findIndex((r) => r.id === productId);
const q = (_b = this.func.queries) === null || _b === void 0 ? void 0 : _b.find((q) => { var _a, _b; return Boolean((_b = (_a = q.settings) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.categoryPath); });
let abTestId, abTestVariantId;
if (!this.func.params) {
this.func.params = {};
}
if (this.func.params.abtest) {
abTestId = this.func.params.abtest.abTestId;
abTestVariantId = this.func.params.abtest.abTestVariantId;
}
KlevuEvents_js_1.KlevuEvents.categoryMerchandisingProductClick({
product: record,
categoryTitle,
klevuCategory: (_e = (_d = (_c = q === null || q === void 0 ? void 0 : q.settings) === null || _c === void 0 ? void 0 : _c.query) === null || _d === void 0 ? void 0 : _d.categoryPath) !== null && _e !== void 0 ? _e : "unknown",
variantId,
productPosition: (this.query.meta.offset || 0) + index + 1,
abTestId,
abTestVariantId,
activeFilters: (0, extractActiveFilters_js_1.extractActiveFilters)(this.query),
override,
});
for (const hook of (_f = this.hooks) !== null && _f !== void 0 ? _f : []) {
hook({ type: "categoryMerchandising", productId, variantId });
}
};
break;
}
case "kmcRecommendation": {
if (!((_b = this.func.params) === null || _b === void 0 ? void 0 : _b.kmcConfig)) {
break;
}
const config = (_c = this.func.params) === null || _c === void 0 ? void 0 : _c.kmcConfig;
if (config.metadata.action === "HIDE_RECOMMENDATION") {
break;
}
if (config.metadata.action === "STATIC_CONTENT") {
if (!config.staticContent) {
break;
}
this.recommendationBannerClickEvent = function ({ resolution }) {
var _a;
if (!config.staticContent || config.staticContent.length === 0) {
return;
}
const image = (_a = config.staticContent[0].image.find((image) => image.resolution === resolution)) !== null && _a !== void 0 ? _a : config.staticContent[0].image[0];
if (!image) {
return;
}
KlevuEvents_js_1.KlevuEvents.recommendationClick({
recommendationMetadata: config.metadata,
bannerInfo: {
resolution,
index: 1,
banner_alt_tag: image.altTag,
banner_image_url: image.url,
content_type: "image",
},
});
};
break;
}
this.recommendationClickEvent = function ({ productId, variantId, override, }) {
var _a, _b;
if (!this.func) {
return;
}
const record = [
...this.query.records,
...((_a = this.func.previousResultRecords) !== null && _a !== void 0 ? _a : []),
].find((r) => r.id === productId);
if (!record) {
throw new Error(`KlevuEvents: Given "${productId}" doesn't exists in this.querys`);
}
if (!config) {
throw new Error("KlevuEvents: Recommendation kmcConfig not available");
}
const index = this.query.records.findIndex((r) => r.id === productId);
KlevuEvents_js_1.KlevuEvents.recommendationClick({
recommendationMetadata: config.metadata,
product: record,
productIndexInList: index + 1,
variantId,
override,
});
for (const hook of (_b = this.hooks) !== null && _b !== void 0 ? _b : []) {
hook({ type: "recommendation", productId, variantId });
}
};
}
}
};