@klevu/core
Version:
Typescript SDK that simplifies development on Klevu backend. Klevu provides advanced AI-powered search and discovery solutions for online retailers.
109 lines (108 loc) • 5.03 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());
});
};
import { KlevuConfig } from "../../config.js";
import { post } from "../../connection/fetch.js";
import { KlevuTypeOfRequest } from "../../models/KlevuTypeOfRequest.js";
import { isBrowser } from "../../utils/isBrowser.js";
import { KlevuStorage } from "../../utils/storage.js";
const STORAGE_TS_KEY = "abtest-data-ts";
const STORAGE_KEY = "abtest-data";
const STORAGE_PERMANENT_KEY = "abtest-permanent-data";
const HALF_HOUR = 1800000;
/**
* Enables AB test functionality. This will make extra request to Klevu servers and it is recommended only if you wish to use A/B testing feature.
*
* Currently not supported in server side rendering.
*
* @category Modifier
* @returns
*/
export function abTest() {
return {
klevuModifierId: "abtest",
modifyAfter: (queries, func) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
// A/B test is not supported in the serverside
if (!isBrowser()) {
return Array.from(queries);
}
const data = yield fetchAbTestInfo();
const permanent = JSON.parse((_a = KlevuStorage.getItem(STORAGE_PERMANENT_KEY)) !== null && _a !== void 0 ? _a : "[]");
if (!data) {
throw new Error("Failed to fetch AB test data");
}
// clean permanent data
const newpermanent = [];
for (const perm of permanent) {
if (data.assigned.some((a) => a.abTestId === perm.abTestId && a.sourceId === perm.sourceId)) {
newpermanent.push(perm);
}
}
const copy = Array.from(queries);
for (const q of copy) {
if (q.typeOfRequest !== KlevuTypeOfRequest.CategoryNavigation) {
throw new Error("abtest can only be applied to category navigation");
}
const path = (_c = (_b = q.settings) === null || _b === void 0 ? void 0 : _b.query) === null || _c === void 0 ? void 0 : _c.categoryPath;
if (!path) {
throw new Error("missing category path from abtest");
}
const perm = newpermanent.find((a) => a.sourceId.toLocaleLowerCase() === path.toLocaleLowerCase());
if (!func.params) {
func.params = {};
}
if (perm) {
q.abTestId = perm.abTestId;
q.abTestVariantId = perm.abTestVariantId;
func.params.abtest = perm;
continue;
}
const test = data.assigned.find((a) => a.sourceId.toLocaleLowerCase() === path.toLocaleLowerCase());
if (!test) {
continue;
}
if (!newpermanent.some((a) => a.abTestId === test.abTestId && a.sourceId === test.sourceId)) {
newpermanent.push(test);
post(`https://api.ksearchnet.com/abtest/public/usage/${KlevuConfig.getDefault().apiKey}`, test, true);
}
q.abTestId = test.abTestId;
q.abTestVariantId = test.abTestVariantId;
func.params.abtest = test;
}
KlevuStorage.setItem(STORAGE_PERMANENT_KEY, JSON.stringify(newpermanent));
return copy;
}),
};
}
/**
* This function never wait for result if there is one in cache. Returns new results on next time.
*
* @returns
*/
function fetchAbTestInfo() {
return __awaiter(this, void 0, void 0, function* () {
const ts = KlevuStorage.getItem(STORAGE_TS_KEY);
const res = KlevuStorage.getItem(STORAGE_KEY);
const fetch = () => __awaiter(this, void 0, void 0, function* () {
const data = yield post(`https://api.ksearchnet.com/abtest/public/allocation/${KlevuConfig.getDefault().apiKey}/`, {});
KlevuStorage.setItem(STORAGE_TS_KEY, new Date().getTime().toString());
KlevuStorage.setItem(STORAGE_KEY, JSON.stringify(data));
return data;
});
if (res && ts) {
if (new Date().getTime() - parseInt(ts, 10) > HALF_HOUR) {
// do not wait
fetch();
}
return JSON.parse(res);
}
return fetch();
});
}