@getlupa/client 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6279,6 +6279,14 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6279
6279
  }
6280
6280
  return res.json();
6281
6281
  });
6282
+ const loadRedirectionRules = (queryKey, environment, customBaseUrl) => __awaiter(void 0, void 0, void 0, function* () {
6283
+ const res = yield fetch(`${getApiUrl$1(environment, customBaseUrl)}redirections/${queryKey}`, Object.assign(Object.assign({}, defaultConfig$1), { method: "GET" }));
6284
+ if (res.status < 400) {
6285
+ return res.json();
6286
+ }
6287
+ const errors = yield res.json();
6288
+ return { success: false, errors };
6289
+ });
6282
6290
  const LupaSearchSdk = {
6283
6291
  query: (queryKey, publicQuery, options = null) => {
6284
6292
  if (options === null || options === void 0 ? void 0 : options.customUrl) {
@@ -6300,6 +6308,9 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6300
6308
  },
6301
6309
  queryByIds: (queryKey, ids, options = null) => {
6302
6310
  return queryByIds(queryKey, ids, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6311
+ },
6312
+ loadRedirectionRules: (queryKey, options = null) => {
6313
+ return loadRedirectionRules(queryKey, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6303
6314
  }
6304
6315
  };
6305
6316
  const getNormalizedString = (str) => {
@@ -6378,6 +6389,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6378
6389
  });
6379
6390
  return output;
6380
6391
  };
6392
+ const inputMatches = (input, possibleValues) => {
6393
+ if (!input) {
6394
+ return false;
6395
+ }
6396
+ const normalizedInput = getNormalizedString(input);
6397
+ return possibleValues.some((v) => getNormalizedString(v).startsWith(normalizedInput));
6398
+ };
6381
6399
  const initAnalyticsTracking = (analyticsOptions) => {
6382
6400
  try {
6383
6401
  if (analyticsOptions == null ? void 0 : analyticsOptions.enabled) {
@@ -7328,12 +7346,86 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7328
7346
  }
7329
7347
  return getMostSpecificHierarchyTerms([param, ...params]);
7330
7348
  };
7349
+ const CACHE_KEY = "lupasearch-client-redirections";
7350
+ const useRedirectionStore = defineStore("redirections", () => {
7351
+ const redirections = ref({ rules: [] });
7352
+ const redirectionOptions = ref({ enabled: false, queryKey: "" });
7353
+ const saveToLocalStorage = () => {
7354
+ try {
7355
+ localStorage.setItem(
7356
+ CACHE_KEY,
7357
+ JSON.stringify({ redirections: redirections.value, savedAt: Date.now() })
7358
+ );
7359
+ } catch (e) {
7360
+ }
7361
+ };
7362
+ const tryLoadFromLocalStorage = (config) => {
7363
+ var _a;
7364
+ if (!config.cacheSeconds)
7365
+ return false;
7366
+ try {
7367
+ const data = JSON.parse((_a = localStorage.getItem(CACHE_KEY)) != null ? _a : "");
7368
+ if ((data == null ? void 0 : data.redirections) && Date.now() - data.savedAt < 1e3 * config.cacheSeconds) {
7369
+ redirections.value = data.redirections;
7370
+ return true;
7371
+ }
7372
+ } catch (e) {
7373
+ }
7374
+ return false;
7375
+ };
7376
+ const initiate = (config, options) => __async(void 0, null, function* () {
7377
+ var _a, _b, _c, _d;
7378
+ if ((_a = redirectionOptions.value) == null ? void 0 : _a.enabled) {
7379
+ return;
7380
+ }
7381
+ redirectionOptions.value = config;
7382
+ if (!(config == null ? void 0 : config.enabled)) {
7383
+ return;
7384
+ }
7385
+ const loaded = tryLoadFromLocalStorage(config);
7386
+ if (loaded || ((_c = (_b = redirections.value) == null ? void 0 : _b.rules) == null ? void 0 : _c.length) > 0) {
7387
+ return;
7388
+ }
7389
+ try {
7390
+ const result = yield LupaSearchSdk.loadRedirectionRules(config.queryKey, options);
7391
+ if (!((_d = result == null ? void 0 : result.rules) == null ? void 0 : _d.length)) {
7392
+ return;
7393
+ }
7394
+ redirections.value = result;
7395
+ saveToLocalStorage();
7396
+ } catch (e) {
7397
+ }
7398
+ });
7399
+ const redirectOnKeywordIfConfigured = (input, routingBehavior = "direct-link") => {
7400
+ var _a, _b, _c, _d;
7401
+ if (!((_b = (_a = redirections.value) == null ? void 0 : _a.rules) == null ? void 0 : _b.length)) {
7402
+ return false;
7403
+ }
7404
+ const redirectTo = redirections.value.rules.find((r) => inputMatches(input, r.sources));
7405
+ if (!redirectTo) {
7406
+ return false;
7407
+ }
7408
+ const url = ((_c = redirectionOptions.value) == null ? void 0 : _c.urlTransfromer) ? (_d = redirectionOptions.value) == null ? void 0 : _d.urlTransfromer(redirectTo == null ? void 0 : redirectTo.target) : redirectTo == null ? void 0 : redirectTo.target;
7409
+ if (routingBehavior === "event") {
7410
+ emitRoutingEvent(url);
7411
+ } else {
7412
+ window.location.assign(url);
7413
+ }
7414
+ return true;
7415
+ };
7416
+ return {
7417
+ redirections,
7418
+ redirectOnKeywordIfConfigured,
7419
+ initiate
7420
+ };
7421
+ });
7331
7422
  const useParamsStore = defineStore("params", () => {
7332
7423
  const params = ref({});
7333
7424
  const defaultLimit = ref(DEFAULT_PAGE_SIZE);
7334
7425
  const searchResultsLink = ref("");
7335
7426
  const searchString = ref("");
7336
7427
  const optionsStore = useOptionsStore();
7428
+ const redirectionStore = useRedirectionStore();
7337
7429
  const query = computed(() => params.value[QUERY_PARAMS_PARSED.QUERY]);
7338
7430
  const page = computed(() => {
7339
7431
  const page2 = Number(params.value[QUERY_PARAMS_PARSED.PAGE]) || 1;
@@ -7411,6 +7503,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7411
7503
  facet
7412
7504
  }) => {
7413
7505
  var _a;
7506
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
7507
+ searchText,
7508
+ optionsStore.boxRoutingBehavior
7509
+ );
7510
+ if (redirectionApplied) {
7511
+ return;
7512
+ }
7414
7513
  if (!searchResultsLink.value || linksMatch(searchResultsLink.value, window.location.pathname)) {
7415
7514
  const singleFacetParam = facet ? getFacetParam(facet.key, [facet.title]) : void 0;
7416
7515
  const facetParam = singleFacetParam ? [
@@ -9326,6 +9425,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
9326
9425
  const searchBoxStore = useSearchBoxStore();
9327
9426
  const optionsStore = useOptionsStore();
9328
9427
  const trackingStore = useTrackingStore();
9428
+ const redirectionStore = useRedirectionStore();
9329
9429
  const inputValue = ref("");
9330
9430
  const suggestedValue = ref(defaultSuggestedValue);
9331
9431
  const opened = ref(props.isSearchContainer);
@@ -9364,6 +9464,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
9364
9464
  paramsStore.setSearchResultsLink(props.options.links.searchResults);
9365
9465
  searchBoxStore.saveOptions({ newOptions: props.options });
9366
9466
  optionsStore.setSearchBoxOptions({ options: props.options });
9467
+ redirectionStore.initiate(props.options.redirections, props.options.options);
9367
9468
  bindSearchTriggers(searchTriggers.value, handleCurrentValueSearch);
9368
9469
  if (props.isSearchContainer && searchBoxInput.value) {
9369
9470
  (_a2 = searchBoxInput.value) == null ? void 0 : _a2.focus();
@@ -14054,6 +14155,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14054
14155
  const trackingStore = useTrackingStore();
14055
14156
  const dynamicDataStore = useDynamicDataStore();
14056
14157
  const screenStore = useScreenStore();
14158
+ const redirectionStore = useRedirectionStore();
14057
14159
  const initialFilters = computed(() => {
14058
14160
  var _a;
14059
14161
  return (_a = props.initialFilters) != null ? _a : {};
@@ -14079,17 +14181,18 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14079
14181
  const searchParams = getSearchParams((_a = props.options.ssr) == null ? void 0 : _a.url);
14080
14182
  paramStore.add(parseParams(searchParams));
14081
14183
  };
14082
- onMounted(() => {
14184
+ onMounted(() => __async(this, null, function* () {
14083
14185
  var _a, _b;
14084
14186
  window.addEventListener("popstate", handlePopState);
14085
14187
  window.addEventListener("resize", handleResize);
14188
+ yield redirectionStore.initiate(props.options.redirections, props.options.options);
14086
14189
  if (props.initialData) {
14087
14190
  searchResultStore.add(__spreadValues2({}, props.initialData));
14088
14191
  }
14089
14192
  handleMounted();
14090
14193
  (_b = (_a = props.options.callbacks) == null ? void 0 : _a.onMounted) == null ? void 0 : _b.call(_a);
14091
14194
  mounted.value = true;
14092
- });
14195
+ }));
14093
14196
  onBeforeUnmount(() => {
14094
14197
  window.removeEventListener("resize", handleResize);
14095
14198
  window.removeEventListener("popstate", handlePopState);
@@ -14133,6 +14236,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14133
14236
  const context = getLupaTrackingContext();
14134
14237
  const limit = publicQuery.limit || defaultSearchResultPageSize.value;
14135
14238
  const query2 = __spreadProps2(__spreadValues2(__spreadValues2({}, publicQuery), context), { limit });
14239
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
14240
+ publicQuery.searchText,
14241
+ optionStore.searchResultsRoutingBehavior
14242
+ );
14243
+ if (redirectionApplied) {
14244
+ return;
14245
+ }
14136
14246
  if (!query2.searchText && props.options.disallowEmptyQuery) {
14137
14247
  return;
14138
14248
  }
@@ -6279,6 +6279,14 @@ const track$1 = (queryKey, event, environment, customBaseUrl) => __awaiter(void
6279
6279
  }
6280
6280
  return res.json();
6281
6281
  });
6282
+ const loadRedirectionRules = (queryKey, environment, customBaseUrl) => __awaiter(void 0, void 0, void 0, function* () {
6283
+ const res = yield fetch(`${getApiUrl$1(environment, customBaseUrl)}redirections/${queryKey}`, Object.assign(Object.assign({}, defaultConfig$1), { method: "GET" }));
6284
+ if (res.status < 400) {
6285
+ return res.json();
6286
+ }
6287
+ const errors = yield res.json();
6288
+ return { success: false, errors };
6289
+ });
6282
6290
  const LupaSearchSdk = {
6283
6291
  query: (queryKey, publicQuery, options = null) => {
6284
6292
  if (options === null || options === void 0 ? void 0 : options.customUrl) {
@@ -6300,6 +6308,9 @@ const LupaSearchSdk = {
6300
6308
  },
6301
6309
  queryByIds: (queryKey, ids, options = null) => {
6302
6310
  return queryByIds(queryKey, ids, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6311
+ },
6312
+ loadRedirectionRules: (queryKey, options = null) => {
6313
+ return loadRedirectionRules(queryKey, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6303
6314
  }
6304
6315
  };
6305
6316
  const getNormalizedString = (str) => {
@@ -6378,6 +6389,13 @@ const escapeHtml = (value) => {
6378
6389
  });
6379
6390
  return output;
6380
6391
  };
6392
+ const inputMatches = (input, possibleValues) => {
6393
+ if (!input) {
6394
+ return false;
6395
+ }
6396
+ const normalizedInput = getNormalizedString(input);
6397
+ return possibleValues.some((v) => getNormalizedString(v).startsWith(normalizedInput));
6398
+ };
6381
6399
  const initAnalyticsTracking = (analyticsOptions) => {
6382
6400
  try {
6383
6401
  if (analyticsOptions == null ? void 0 : analyticsOptions.enabled) {
@@ -7328,12 +7346,86 @@ const toggleHierarchyParam = (params = [], param = "", removeAllLevels = false)
7328
7346
  }
7329
7347
  return getMostSpecificHierarchyTerms([param, ...params]);
7330
7348
  };
7349
+ const CACHE_KEY = "lupasearch-client-redirections";
7350
+ const useRedirectionStore = defineStore("redirections", () => {
7351
+ const redirections = ref({ rules: [] });
7352
+ const redirectionOptions = ref({ enabled: false, queryKey: "" });
7353
+ const saveToLocalStorage = () => {
7354
+ try {
7355
+ localStorage.setItem(
7356
+ CACHE_KEY,
7357
+ JSON.stringify({ redirections: redirections.value, savedAt: Date.now() })
7358
+ );
7359
+ } catch (e) {
7360
+ }
7361
+ };
7362
+ const tryLoadFromLocalStorage = (config) => {
7363
+ var _a;
7364
+ if (!config.cacheSeconds)
7365
+ return false;
7366
+ try {
7367
+ const data = JSON.parse((_a = localStorage.getItem(CACHE_KEY)) != null ? _a : "");
7368
+ if ((data == null ? void 0 : data.redirections) && Date.now() - data.savedAt < 1e3 * config.cacheSeconds) {
7369
+ redirections.value = data.redirections;
7370
+ return true;
7371
+ }
7372
+ } catch (e) {
7373
+ }
7374
+ return false;
7375
+ };
7376
+ const initiate = (config, options) => __async(void 0, null, function* () {
7377
+ var _a, _b, _c, _d;
7378
+ if ((_a = redirectionOptions.value) == null ? void 0 : _a.enabled) {
7379
+ return;
7380
+ }
7381
+ redirectionOptions.value = config;
7382
+ if (!(config == null ? void 0 : config.enabled)) {
7383
+ return;
7384
+ }
7385
+ const loaded = tryLoadFromLocalStorage(config);
7386
+ if (loaded || ((_c = (_b = redirections.value) == null ? void 0 : _b.rules) == null ? void 0 : _c.length) > 0) {
7387
+ return;
7388
+ }
7389
+ try {
7390
+ const result = yield LupaSearchSdk.loadRedirectionRules(config.queryKey, options);
7391
+ if (!((_d = result == null ? void 0 : result.rules) == null ? void 0 : _d.length)) {
7392
+ return;
7393
+ }
7394
+ redirections.value = result;
7395
+ saveToLocalStorage();
7396
+ } catch (e) {
7397
+ }
7398
+ });
7399
+ const redirectOnKeywordIfConfigured = (input, routingBehavior = "direct-link") => {
7400
+ var _a, _b, _c, _d;
7401
+ if (!((_b = (_a = redirections.value) == null ? void 0 : _a.rules) == null ? void 0 : _b.length)) {
7402
+ return false;
7403
+ }
7404
+ const redirectTo = redirections.value.rules.find((r) => inputMatches(input, r.sources));
7405
+ if (!redirectTo) {
7406
+ return false;
7407
+ }
7408
+ const url = ((_c = redirectionOptions.value) == null ? void 0 : _c.urlTransfromer) ? (_d = redirectionOptions.value) == null ? void 0 : _d.urlTransfromer(redirectTo == null ? void 0 : redirectTo.target) : redirectTo == null ? void 0 : redirectTo.target;
7409
+ if (routingBehavior === "event") {
7410
+ emitRoutingEvent(url);
7411
+ } else {
7412
+ window.location.assign(url);
7413
+ }
7414
+ return true;
7415
+ };
7416
+ return {
7417
+ redirections,
7418
+ redirectOnKeywordIfConfigured,
7419
+ initiate
7420
+ };
7421
+ });
7331
7422
  const useParamsStore = defineStore("params", () => {
7332
7423
  const params = ref({});
7333
7424
  const defaultLimit = ref(DEFAULT_PAGE_SIZE);
7334
7425
  const searchResultsLink = ref("");
7335
7426
  const searchString = ref("");
7336
7427
  const optionsStore = useOptionsStore();
7428
+ const redirectionStore = useRedirectionStore();
7337
7429
  const query = computed(() => params.value[QUERY_PARAMS_PARSED.QUERY]);
7338
7430
  const page = computed(() => {
7339
7431
  const page2 = Number(params.value[QUERY_PARAMS_PARSED.PAGE]) || 1;
@@ -7411,6 +7503,13 @@ const useParamsStore = defineStore("params", () => {
7411
7503
  facet
7412
7504
  }) => {
7413
7505
  var _a;
7506
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
7507
+ searchText,
7508
+ optionsStore.boxRoutingBehavior
7509
+ );
7510
+ if (redirectionApplied) {
7511
+ return;
7512
+ }
7414
7513
  if (!searchResultsLink.value || linksMatch(searchResultsLink.value, window.location.pathname)) {
7415
7514
  const singleFacetParam = facet ? getFacetParam(facet.key, [facet.title]) : void 0;
7416
7515
  const facetParam = singleFacetParam ? [
@@ -9326,6 +9425,7 @@ const _sfc_main$_ = /* @__PURE__ */ defineComponent({
9326
9425
  const searchBoxStore = useSearchBoxStore();
9327
9426
  const optionsStore = useOptionsStore();
9328
9427
  const trackingStore = useTrackingStore();
9428
+ const redirectionStore = useRedirectionStore();
9329
9429
  const inputValue = ref("");
9330
9430
  const suggestedValue = ref(defaultSuggestedValue);
9331
9431
  const opened = ref(props.isSearchContainer);
@@ -9364,6 +9464,7 @@ const _sfc_main$_ = /* @__PURE__ */ defineComponent({
9364
9464
  paramsStore.setSearchResultsLink(props.options.links.searchResults);
9365
9465
  searchBoxStore.saveOptions({ newOptions: props.options });
9366
9466
  optionsStore.setSearchBoxOptions({ options: props.options });
9467
+ redirectionStore.initiate(props.options.redirections, props.options.options);
9367
9468
  bindSearchTriggers(searchTriggers.value, handleCurrentValueSearch);
9368
9469
  if (props.isSearchContainer && searchBoxInput.value) {
9369
9470
  (_a2 = searchBoxInput.value) == null ? void 0 : _a2.focus();
@@ -14054,6 +14155,7 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14054
14155
  const trackingStore = useTrackingStore();
14055
14156
  const dynamicDataStore = useDynamicDataStore();
14056
14157
  const screenStore = useScreenStore();
14158
+ const redirectionStore = useRedirectionStore();
14057
14159
  const initialFilters = computed(() => {
14058
14160
  var _a;
14059
14161
  return (_a = props.initialFilters) != null ? _a : {};
@@ -14079,17 +14181,18 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14079
14181
  const searchParams = getSearchParams((_a = props.options.ssr) == null ? void 0 : _a.url);
14080
14182
  paramStore.add(parseParams(searchParams));
14081
14183
  };
14082
- onMounted(() => {
14184
+ onMounted(() => __async(this, null, function* () {
14083
14185
  var _a, _b;
14084
14186
  window.addEventListener("popstate", handlePopState);
14085
14187
  window.addEventListener("resize", handleResize);
14188
+ yield redirectionStore.initiate(props.options.redirections, props.options.options);
14086
14189
  if (props.initialData) {
14087
14190
  searchResultStore.add(__spreadValues2({}, props.initialData));
14088
14191
  }
14089
14192
  handleMounted();
14090
14193
  (_b = (_a = props.options.callbacks) == null ? void 0 : _a.onMounted) == null ? void 0 : _b.call(_a);
14091
14194
  mounted.value = true;
14092
- });
14195
+ }));
14093
14196
  onBeforeUnmount(() => {
14094
14197
  window.removeEventListener("resize", handleResize);
14095
14198
  window.removeEventListener("popstate", handlePopState);
@@ -14133,6 +14236,13 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14133
14236
  const context = getLupaTrackingContext();
14134
14237
  const limit = publicQuery.limit || defaultSearchResultPageSize.value;
14135
14238
  const query2 = __spreadProps2(__spreadValues2(__spreadValues2({}, publicQuery), context), { limit });
14239
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
14240
+ publicQuery.searchText,
14241
+ optionStore.searchResultsRoutingBehavior
14242
+ );
14243
+ if (redirectionApplied) {
14244
+ return;
14245
+ }
14136
14246
  if (!query2.searchText && props.options.disallowEmptyQuery) {
14137
14247
  return;
14138
14248
  }
@@ -6277,6 +6277,14 @@ const track$1 = (queryKey, event, environment, customBaseUrl) => __awaiter(void
6277
6277
  }
6278
6278
  return res.json();
6279
6279
  });
6280
+ const loadRedirectionRules = (queryKey, environment, customBaseUrl) => __awaiter(void 0, void 0, void 0, function* () {
6281
+ const res = yield fetch(`${getApiUrl$1(environment, customBaseUrl)}redirections/${queryKey}`, Object.assign(Object.assign({}, defaultConfig$1), { method: "GET" }));
6282
+ if (res.status < 400) {
6283
+ return res.json();
6284
+ }
6285
+ const errors = yield res.json();
6286
+ return { success: false, errors };
6287
+ });
6280
6288
  const LupaSearchSdk = {
6281
6289
  query: (queryKey, publicQuery, options = null) => {
6282
6290
  if (options === null || options === void 0 ? void 0 : options.customUrl) {
@@ -6298,6 +6306,9 @@ const LupaSearchSdk = {
6298
6306
  },
6299
6307
  queryByIds: (queryKey, ids, options = null) => {
6300
6308
  return queryByIds(queryKey, ids, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6309
+ },
6310
+ loadRedirectionRules: (queryKey, options = null) => {
6311
+ return loadRedirectionRules(queryKey, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6301
6312
  }
6302
6313
  };
6303
6314
  const getNormalizedString = (str) => {
@@ -6376,6 +6387,13 @@ const escapeHtml = (value) => {
6376
6387
  });
6377
6388
  return output;
6378
6389
  };
6390
+ const inputMatches = (input, possibleValues) => {
6391
+ if (!input) {
6392
+ return false;
6393
+ }
6394
+ const normalizedInput = getNormalizedString(input);
6395
+ return possibleValues.some((v) => getNormalizedString(v).startsWith(normalizedInput));
6396
+ };
6379
6397
  const initAnalyticsTracking = (analyticsOptions) => {
6380
6398
  try {
6381
6399
  if (analyticsOptions == null ? void 0 : analyticsOptions.enabled) {
@@ -7326,12 +7344,86 @@ const toggleHierarchyParam = (params = [], param = "", removeAllLevels = false)
7326
7344
  }
7327
7345
  return getMostSpecificHierarchyTerms([param, ...params]);
7328
7346
  };
7347
+ const CACHE_KEY = "lupasearch-client-redirections";
7348
+ const useRedirectionStore = defineStore("redirections", () => {
7349
+ const redirections = ref({ rules: [] });
7350
+ const redirectionOptions = ref({ enabled: false, queryKey: "" });
7351
+ const saveToLocalStorage = () => {
7352
+ try {
7353
+ localStorage.setItem(
7354
+ CACHE_KEY,
7355
+ JSON.stringify({ redirections: redirections.value, savedAt: Date.now() })
7356
+ );
7357
+ } catch (e) {
7358
+ }
7359
+ };
7360
+ const tryLoadFromLocalStorage = (config) => {
7361
+ var _a;
7362
+ if (!config.cacheSeconds)
7363
+ return false;
7364
+ try {
7365
+ const data = JSON.parse((_a = localStorage.getItem(CACHE_KEY)) != null ? _a : "");
7366
+ if ((data == null ? void 0 : data.redirections) && Date.now() - data.savedAt < 1e3 * config.cacheSeconds) {
7367
+ redirections.value = data.redirections;
7368
+ return true;
7369
+ }
7370
+ } catch (e) {
7371
+ }
7372
+ return false;
7373
+ };
7374
+ const initiate = (config, options) => __async(void 0, null, function* () {
7375
+ var _a, _b, _c, _d;
7376
+ if ((_a = redirectionOptions.value) == null ? void 0 : _a.enabled) {
7377
+ return;
7378
+ }
7379
+ redirectionOptions.value = config;
7380
+ if (!(config == null ? void 0 : config.enabled)) {
7381
+ return;
7382
+ }
7383
+ const loaded = tryLoadFromLocalStorage(config);
7384
+ if (loaded || ((_c = (_b = redirections.value) == null ? void 0 : _b.rules) == null ? void 0 : _c.length) > 0) {
7385
+ return;
7386
+ }
7387
+ try {
7388
+ const result = yield LupaSearchSdk.loadRedirectionRules(config.queryKey, options);
7389
+ if (!((_d = result == null ? void 0 : result.rules) == null ? void 0 : _d.length)) {
7390
+ return;
7391
+ }
7392
+ redirections.value = result;
7393
+ saveToLocalStorage();
7394
+ } catch (e) {
7395
+ }
7396
+ });
7397
+ const redirectOnKeywordIfConfigured = (input, routingBehavior = "direct-link") => {
7398
+ var _a, _b, _c, _d;
7399
+ if (!((_b = (_a = redirections.value) == null ? void 0 : _a.rules) == null ? void 0 : _b.length)) {
7400
+ return false;
7401
+ }
7402
+ const redirectTo = redirections.value.rules.find((r) => inputMatches(input, r.sources));
7403
+ if (!redirectTo) {
7404
+ return false;
7405
+ }
7406
+ const url = ((_c = redirectionOptions.value) == null ? void 0 : _c.urlTransfromer) ? (_d = redirectionOptions.value) == null ? void 0 : _d.urlTransfromer(redirectTo == null ? void 0 : redirectTo.target) : redirectTo == null ? void 0 : redirectTo.target;
7407
+ if (routingBehavior === "event") {
7408
+ emitRoutingEvent(url);
7409
+ } else {
7410
+ window.location.assign(url);
7411
+ }
7412
+ return true;
7413
+ };
7414
+ return {
7415
+ redirections,
7416
+ redirectOnKeywordIfConfigured,
7417
+ initiate
7418
+ };
7419
+ });
7329
7420
  const useParamsStore = defineStore("params", () => {
7330
7421
  const params = ref({});
7331
7422
  const defaultLimit = ref(DEFAULT_PAGE_SIZE);
7332
7423
  const searchResultsLink = ref("");
7333
7424
  const searchString = ref("");
7334
7425
  const optionsStore = useOptionsStore();
7426
+ const redirectionStore = useRedirectionStore();
7335
7427
  const query = computed(() => params.value[QUERY_PARAMS_PARSED.QUERY]);
7336
7428
  const page = computed(() => {
7337
7429
  const page2 = Number(params.value[QUERY_PARAMS_PARSED.PAGE]) || 1;
@@ -7409,6 +7501,13 @@ const useParamsStore = defineStore("params", () => {
7409
7501
  facet
7410
7502
  }) => {
7411
7503
  var _a;
7504
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
7505
+ searchText,
7506
+ optionsStore.boxRoutingBehavior
7507
+ );
7508
+ if (redirectionApplied) {
7509
+ return;
7510
+ }
7412
7511
  if (!searchResultsLink.value || linksMatch(searchResultsLink.value, window.location.pathname)) {
7413
7512
  const singleFacetParam = facet ? getFacetParam(facet.key, [facet.title]) : void 0;
7414
7513
  const facetParam = singleFacetParam ? [
@@ -9324,6 +9423,7 @@ const _sfc_main$_ = /* @__PURE__ */ defineComponent({
9324
9423
  const searchBoxStore = useSearchBoxStore();
9325
9424
  const optionsStore = useOptionsStore();
9326
9425
  const trackingStore = useTrackingStore();
9426
+ const redirectionStore = useRedirectionStore();
9327
9427
  const inputValue = ref("");
9328
9428
  const suggestedValue = ref(defaultSuggestedValue);
9329
9429
  const opened = ref(props.isSearchContainer);
@@ -9362,6 +9462,7 @@ const _sfc_main$_ = /* @__PURE__ */ defineComponent({
9362
9462
  paramsStore.setSearchResultsLink(props.options.links.searchResults);
9363
9463
  searchBoxStore.saveOptions({ newOptions: props.options });
9364
9464
  optionsStore.setSearchBoxOptions({ options: props.options });
9465
+ redirectionStore.initiate(props.options.redirections, props.options.options);
9365
9466
  bindSearchTriggers(searchTriggers.value, handleCurrentValueSearch);
9366
9467
  if (props.isSearchContainer && searchBoxInput.value) {
9367
9468
  (_a2 = searchBoxInput.value) == null ? void 0 : _a2.focus();
@@ -14052,6 +14153,7 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14052
14153
  const trackingStore = useTrackingStore();
14053
14154
  const dynamicDataStore = useDynamicDataStore();
14054
14155
  const screenStore = useScreenStore();
14156
+ const redirectionStore = useRedirectionStore();
14055
14157
  const initialFilters = computed(() => {
14056
14158
  var _a;
14057
14159
  return (_a = props.initialFilters) != null ? _a : {};
@@ -14077,17 +14179,18 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14077
14179
  const searchParams = getSearchParams((_a = props.options.ssr) == null ? void 0 : _a.url);
14078
14180
  paramStore.add(parseParams(searchParams));
14079
14181
  };
14080
- onMounted(() => {
14182
+ onMounted(() => __async(this, null, function* () {
14081
14183
  var _a, _b;
14082
14184
  window.addEventListener("popstate", handlePopState);
14083
14185
  window.addEventListener("resize", handleResize);
14186
+ yield redirectionStore.initiate(props.options.redirections, props.options.options);
14084
14187
  if (props.initialData) {
14085
14188
  searchResultStore.add(__spreadValues2({}, props.initialData));
14086
14189
  }
14087
14190
  handleMounted();
14088
14191
  (_b = (_a = props.options.callbacks) == null ? void 0 : _a.onMounted) == null ? void 0 : _b.call(_a);
14089
14192
  mounted.value = true;
14090
- });
14193
+ }));
14091
14194
  onBeforeUnmount(() => {
14092
14195
  window.removeEventListener("resize", handleResize);
14093
14196
  window.removeEventListener("popstate", handlePopState);
@@ -14131,6 +14234,13 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
14131
14234
  const context = getLupaTrackingContext();
14132
14235
  const limit = publicQuery.limit || defaultSearchResultPageSize.value;
14133
14236
  const query2 = __spreadProps2(__spreadValues2(__spreadValues2({}, publicQuery), context), { limit });
14237
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
14238
+ publicQuery.searchText,
14239
+ optionStore.searchResultsRoutingBehavior
14240
+ );
14241
+ if (redirectionApplied) {
14242
+ return;
14243
+ }
14134
14244
  if (!query2.searchText && props.options.disallowEmptyQuery) {
14135
14245
  return;
14136
14246
  }
@@ -6281,6 +6281,14 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6281
6281
  }
6282
6282
  return res.json();
6283
6283
  });
6284
+ const loadRedirectionRules = (queryKey, environment, customBaseUrl) => __awaiter(void 0, void 0, void 0, function* () {
6285
+ const res = yield fetch(`${getApiUrl$1(environment, customBaseUrl)}redirections/${queryKey}`, Object.assign(Object.assign({}, defaultConfig$1), { method: "GET" }));
6286
+ if (res.status < 400) {
6287
+ return res.json();
6288
+ }
6289
+ const errors = yield res.json();
6290
+ return { success: false, errors };
6291
+ });
6284
6292
  const LupaSearchSdk = {
6285
6293
  query: (queryKey, publicQuery, options = null) => {
6286
6294
  if (options === null || options === void 0 ? void 0 : options.customUrl) {
@@ -6302,6 +6310,9 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6302
6310
  },
6303
6311
  queryByIds: (queryKey, ids, options = null) => {
6304
6312
  return queryByIds(queryKey, ids, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6313
+ },
6314
+ loadRedirectionRules: (queryKey, options = null) => {
6315
+ return loadRedirectionRules(queryKey, (options === null || options === void 0 ? void 0 : options.environment) || "production", options === null || options === void 0 ? void 0 : options.customBaseUrl);
6305
6316
  }
6306
6317
  };
6307
6318
  const getNormalizedString = (str) => {
@@ -6380,6 +6391,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
6380
6391
  });
6381
6392
  return output;
6382
6393
  };
6394
+ const inputMatches = (input, possibleValues) => {
6395
+ if (!input) {
6396
+ return false;
6397
+ }
6398
+ const normalizedInput = getNormalizedString(input);
6399
+ return possibleValues.some((v) => getNormalizedString(v).startsWith(normalizedInput));
6400
+ };
6383
6401
  const initAnalyticsTracking = (analyticsOptions) => {
6384
6402
  try {
6385
6403
  if (analyticsOptions == null ? void 0 : analyticsOptions.enabled) {
@@ -7330,12 +7348,86 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7330
7348
  }
7331
7349
  return getMostSpecificHierarchyTerms([param, ...params]);
7332
7350
  };
7351
+ const CACHE_KEY = "lupasearch-client-redirections";
7352
+ const useRedirectionStore = defineStore("redirections", () => {
7353
+ const redirections = ref({ rules: [] });
7354
+ const redirectionOptions = ref({ enabled: false, queryKey: "" });
7355
+ const saveToLocalStorage = () => {
7356
+ try {
7357
+ localStorage.setItem(
7358
+ CACHE_KEY,
7359
+ JSON.stringify({ redirections: redirections.value, savedAt: Date.now() })
7360
+ );
7361
+ } catch (e) {
7362
+ }
7363
+ };
7364
+ const tryLoadFromLocalStorage = (config) => {
7365
+ var _a;
7366
+ if (!config.cacheSeconds)
7367
+ return false;
7368
+ try {
7369
+ const data = JSON.parse((_a = localStorage.getItem(CACHE_KEY)) != null ? _a : "");
7370
+ if ((data == null ? void 0 : data.redirections) && Date.now() - data.savedAt < 1e3 * config.cacheSeconds) {
7371
+ redirections.value = data.redirections;
7372
+ return true;
7373
+ }
7374
+ } catch (e) {
7375
+ }
7376
+ return false;
7377
+ };
7378
+ const initiate = (config, options) => __async(void 0, null, function* () {
7379
+ var _a, _b, _c, _d;
7380
+ if ((_a = redirectionOptions.value) == null ? void 0 : _a.enabled) {
7381
+ return;
7382
+ }
7383
+ redirectionOptions.value = config;
7384
+ if (!(config == null ? void 0 : config.enabled)) {
7385
+ return;
7386
+ }
7387
+ const loaded = tryLoadFromLocalStorage(config);
7388
+ if (loaded || ((_c = (_b = redirections.value) == null ? void 0 : _b.rules) == null ? void 0 : _c.length) > 0) {
7389
+ return;
7390
+ }
7391
+ try {
7392
+ const result = yield LupaSearchSdk.loadRedirectionRules(config.queryKey, options);
7393
+ if (!((_d = result == null ? void 0 : result.rules) == null ? void 0 : _d.length)) {
7394
+ return;
7395
+ }
7396
+ redirections.value = result;
7397
+ saveToLocalStorage();
7398
+ } catch (e) {
7399
+ }
7400
+ });
7401
+ const redirectOnKeywordIfConfigured = (input, routingBehavior = "direct-link") => {
7402
+ var _a, _b, _c, _d;
7403
+ if (!((_b = (_a = redirections.value) == null ? void 0 : _a.rules) == null ? void 0 : _b.length)) {
7404
+ return false;
7405
+ }
7406
+ const redirectTo = redirections.value.rules.find((r) => inputMatches(input, r.sources));
7407
+ if (!redirectTo) {
7408
+ return false;
7409
+ }
7410
+ const url = ((_c = redirectionOptions.value) == null ? void 0 : _c.urlTransfromer) ? (_d = redirectionOptions.value) == null ? void 0 : _d.urlTransfromer(redirectTo == null ? void 0 : redirectTo.target) : redirectTo == null ? void 0 : redirectTo.target;
7411
+ if (routingBehavior === "event") {
7412
+ emitRoutingEvent(url);
7413
+ } else {
7414
+ window.location.assign(url);
7415
+ }
7416
+ return true;
7417
+ };
7418
+ return {
7419
+ redirections,
7420
+ redirectOnKeywordIfConfigured,
7421
+ initiate
7422
+ };
7423
+ });
7333
7424
  const useParamsStore = defineStore("params", () => {
7334
7425
  const params = ref({});
7335
7426
  const defaultLimit = ref(DEFAULT_PAGE_SIZE);
7336
7427
  const searchResultsLink = ref("");
7337
7428
  const searchString = ref("");
7338
7429
  const optionsStore = useOptionsStore();
7430
+ const redirectionStore = useRedirectionStore();
7339
7431
  const query = computed(() => params.value[QUERY_PARAMS_PARSED.QUERY]);
7340
7432
  const page = computed(() => {
7341
7433
  const page2 = Number(params.value[QUERY_PARAMS_PARSED.PAGE]) || 1;
@@ -7413,6 +7505,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7413
7505
  facet
7414
7506
  }) => {
7415
7507
  var _a;
7508
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
7509
+ searchText,
7510
+ optionsStore.boxRoutingBehavior
7511
+ );
7512
+ if (redirectionApplied) {
7513
+ return;
7514
+ }
7416
7515
  if (!searchResultsLink.value || linksMatch(searchResultsLink.value, window.location.pathname)) {
7417
7516
  const singleFacetParam = facet ? getFacetParam(facet.key, [facet.title]) : void 0;
7418
7517
  const facetParam = singleFacetParam ? [
@@ -9328,6 +9427,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
9328
9427
  const searchBoxStore = useSearchBoxStore();
9329
9428
  const optionsStore = useOptionsStore();
9330
9429
  const trackingStore = useTrackingStore();
9430
+ const redirectionStore = useRedirectionStore();
9331
9431
  const inputValue = ref("");
9332
9432
  const suggestedValue = ref(defaultSuggestedValue);
9333
9433
  const opened = ref(props.isSearchContainer);
@@ -9366,6 +9466,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
9366
9466
  paramsStore.setSearchResultsLink(props.options.links.searchResults);
9367
9467
  searchBoxStore.saveOptions({ newOptions: props.options });
9368
9468
  optionsStore.setSearchBoxOptions({ options: props.options });
9469
+ redirectionStore.initiate(props.options.redirections, props.options.options);
9369
9470
  bindSearchTriggers(searchTriggers.value, handleCurrentValueSearch);
9370
9471
  if (props.isSearchContainer && searchBoxInput.value) {
9371
9472
  (_a2 = searchBoxInput.value) == null ? void 0 : _a2.focus();
@@ -14056,6 +14157,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14056
14157
  const trackingStore = useTrackingStore();
14057
14158
  const dynamicDataStore = useDynamicDataStore();
14058
14159
  const screenStore = useScreenStore();
14160
+ const redirectionStore = useRedirectionStore();
14059
14161
  const initialFilters = computed(() => {
14060
14162
  var _a;
14061
14163
  return (_a = props.initialFilters) != null ? _a : {};
@@ -14081,17 +14183,18 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14081
14183
  const searchParams = getSearchParams((_a = props.options.ssr) == null ? void 0 : _a.url);
14082
14184
  paramStore.add(parseParams(searchParams));
14083
14185
  };
14084
- onMounted(() => {
14186
+ onMounted(() => __async(this, null, function* () {
14085
14187
  var _a, _b;
14086
14188
  window.addEventListener("popstate", handlePopState);
14087
14189
  window.addEventListener("resize", handleResize);
14190
+ yield redirectionStore.initiate(props.options.redirections, props.options.options);
14088
14191
  if (props.initialData) {
14089
14192
  searchResultStore.add(__spreadValues2({}, props.initialData));
14090
14193
  }
14091
14194
  handleMounted();
14092
14195
  (_b = (_a = props.options.callbacks) == null ? void 0 : _a.onMounted) == null ? void 0 : _b.call(_a);
14093
14196
  mounted.value = true;
14094
- });
14197
+ }));
14095
14198
  onBeforeUnmount(() => {
14096
14199
  window.removeEventListener("resize", handleResize);
14097
14200
  window.removeEventListener("popstate", handlePopState);
@@ -14135,6 +14238,13 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
14135
14238
  const context = getLupaTrackingContext();
14136
14239
  const limit = publicQuery.limit || defaultSearchResultPageSize.value;
14137
14240
  const query2 = __spreadProps2(__spreadValues2(__spreadValues2({}, publicQuery), context), { limit });
14241
+ const redirectionApplied = redirectionStore.redirectOnKeywordIfConfigured(
14242
+ publicQuery.searchText,
14243
+ optionStore.searchResultsRoutingBehavior
14244
+ );
14245
+ if (redirectionApplied) {
14246
+ return;
14247
+ }
14138
14248
  if (!query2.searchText && props.options.disallowEmptyQuery) {
14139
14249
  return;
14140
14250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getlupa/client",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "main": "dist/lupaSearch.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/src/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "devDependencies": {
22
22
  "@getlupa/client-sdk": "^1.3.4",
23
- "@getlupa/vue": "0.6.2",
23
+ "@getlupa/vue": "0.7.0",
24
24
  "@rushstack/eslint-patch": "^1.3.2",
25
25
  "@tsconfig/node18": "^2.0.1",
26
26
  "@types/jsdom": "^21.1.1",