@depict-ai/ui 1.1.4 → 1.2.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.
@@ -43,7 +43,7 @@ $parcel$export(module.exports, "defaultGridSpacing", () => $a3280f0aad997933$exp
43
43
  $parcel$export(module.exports, "defaultColsAtSize", () => $a3280f0aad997933$export$c3834fa86c616831);
44
44
  $parcel$export(module.exports, "defaultCategoryTitlePlugin", () => $a3280f0aad997933$export$7bf543b9d9be2c22);
45
45
  $parcel$export(module.exports, "version", () => $b757f75811f3261f$export$83d89fbfd8236492);
46
- /*! Depict.ai search and product listing SDK */ const $b757f75811f3261f$export$83d89fbfd8236492 = "1.1.4";
46
+ /*! Depict.ai search and product listing SDK */ const $b757f75811f3261f$export$83d89fbfd8236492 = "1.2.0";
47
47
 
48
48
 
49
49
 
@@ -228,26 +228,77 @@ class $e1d6c0f3d89d531c$export$e015ed2f2950f2e3 {
228
228
  #get_metadata;
229
229
  #get_user_id;
230
230
  #get_session_id;
231
- constructor({ get_metadata: get_metadata , get_user_id: get_user_id , get_session_id: get_session_id } = {}){
232
- this.#get_metadata = get_metadata;
233
- this.#get_user_id = get_user_id;
234
- this.#get_session_id = get_session_id;
231
+ #guard_url_creator_length(expected, received) {
232
+ if (expected.length !== received.length) {
233
+ const e = new Error("Page URL creator returned wrong number of page URLs, got " + received.length + ", expected " + expected.length);
234
+ queueMicrotask(()=>{
235
+ throw e;
236
+ });
237
+ throw e;
238
+ }
235
239
  }
236
- async suggest(input_req) {
237
- const request = this.#add_ids_to_request(input_req);
238
- const url = (0, $diwD4$depictaiutilishared.make_url_with_query_params)($e1d6c0f3d89d531c$var$search_base_url + "suggestions", request);
239
- const results = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(url));
240
- attempt_to_return_api_response: {
241
- if (!results) break attempt_to_return_api_response;
242
- const decoded_json = await results.json();
243
- if (!Array.isArray(decoded_json?.suggestions)) break attempt_to_return_api_response;
244
- return decoded_json;
240
+ async #run_url_creator_for_suggest(merchant, market, response) {
241
+ if (!this.page_url_creator) return response;
242
+ // find category suggestions, run thing with them, and then replace them
243
+ const category_suggestions = response.suggestions.filter((suggestion)=>suggestion.type === "category");
244
+ const page_urls = await this.page_url_creator({
245
+ type: "categories",
246
+ market: market,
247
+ merchant: merchant,
248
+ data: [
249
+ ...category_suggestions
250
+ ]
251
+ });
252
+ this.#guard_url_creator_length(category_suggestions, page_urls);
253
+ while(page_urls.length)Object.assign(category_suggestions.pop(), page_urls.pop());
254
+ return response;
255
+ }
256
+ async #run_url_creator_for_rest(merchant1, market1, input_data) {
257
+ if (!this.page_url_creator) return input_data;
258
+ const displays = input_data.displays;
259
+ const breadcrumb = input_data.breadcrumb;
260
+ const quick_links = input_data.quick_links;
261
+ if (displays) {
262
+ const page_urls = await this.page_url_creator({
263
+ type: "products",
264
+ merchant: merchant1,
265
+ market: market1,
266
+ displays: [
267
+ ...input_data.displays
268
+ ]
269
+ });
270
+ this.#guard_url_creator_length(displays, page_urls);
271
+ for(let i = 0; i < displays.length; i++){
272
+ const new_display_or_page_url = page_urls[i];
273
+ const old_display = displays[i];
274
+ if ("page_url" in new_display_or_page_url && Object.keys(new_display_or_page_url).length === 1) {
275
+ // they only returned page_url, let's put it into the display
276
+ const old_display_was_modern = "variant_index" in old_display;
277
+ if (old_display_was_modern) {
278
+ const variant_displays = old_display.variant_displays;
279
+ for(let i = 0; i < variant_displays.length; i++)variant_displays[i].page_url = new_display_or_page_url.page_url;
280
+ } else old_display.page_url = new_display_or_page_url.page_url;
281
+ } else // We got a whole new display, let's replace it
282
+ displays[i] = new_display_or_page_url;
283
+ }
245
284
  }
246
- return {
247
- "suggestions_request_id": "error",
248
- "suggestions": [],
249
- failed: true
250
- };
285
+ for (const category_display_array of [
286
+ breadcrumb,
287
+ quick_links
288
+ ]){
289
+ if (!category_display_array) continue;
290
+ const page_urls = await this.page_url_creator({
291
+ type: "categories",
292
+ merchant: merchant1,
293
+ market: market1,
294
+ data: [
295
+ ...category_display_array
296
+ ]
297
+ });
298
+ this.#guard_url_creator_length(category_display_array, page_urls);
299
+ for(let i = 0; i < category_display_array.length; i++)Object.assign(category_display_array[i], page_urls[i]);
300
+ }
301
+ return input_data;
251
302
  }
252
303
  async #cached_post_request(endpoint1, input_req, fallback_response) {
253
304
  const cache_obj = this.#get_cache_obj_for_endpoint(endpoint1);
@@ -264,66 +315,101 @@ class $e1d6c0f3d89d531c$export$e015ed2f2950f2e3 {
264
315
  let resolve_in_progress;
265
316
  cache_obj.in_progress_[body] = new Promise((r)=>resolve_in_progress = r);
266
317
  try {
267
- let search_results = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(endpoint1), {
318
+ let api_response = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(endpoint1), {
268
319
  method: "POST",
269
320
  body: body
270
321
  });
271
322
  if ("query_id" in request && request.type === "collection") // FIXME: Remove. Backwards compatibility layer
272
323
  // This will retry the request without the collection type if the first request fails
273
324
  {
274
- if (!search_results || search_results?.status === 404) {
325
+ if (!api_response || api_response?.status === 404) {
275
326
  (0, $diwD4$depictaiutilishared.dlog)("Fallback request for collections due to failure");
276
327
  const fallback_body = JSON.parse(body);
277
328
  delete fallback_body.type;
278
- search_results = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(endpoint1), {
329
+ api_response = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(endpoint1), {
279
330
  method: "POST",
280
331
  body: JSON.stringify(fallback_body)
281
332
  });
282
333
  }
283
334
  }
284
- if (!search_results || search_results.status !== 200) {
285
- const retval = fallback_response(input_req);
286
- resolve_in_progress(retval);
287
- return retval;
335
+ return_successfully: {
336
+ if (!api_response || api_response.status !== 200) break return_successfully;
337
+ let result;
338
+ try {
339
+ const unmodified_result = await api_response.json();
340
+ result = await this.#run_url_creator_for_rest(input_req.tenant, input_req.market, unmodified_result);
341
+ } catch (e) {
342
+ (0, $diwD4$depictaiutilishared.dwarn)("URL creator or json decoding failed", e);
343
+ break return_successfully;
344
+ }
345
+ cache_obj.cache_[body] = new WeakRef(result);
346
+ resolve_in_progress(result);
347
+ setTimeout((0, $diwD4$depictaiutilishared.catchify)(()=>{
348
+ if (this.#supports_finalization_registry) cache_obj.finalization_registry_.register(result, body); // delete key from cache when value (WeakRefs) are collected
349
+ else // delete things from cache after 5 minutes, so it doesn't get too heavy
350
+ setTimeout((0, $diwD4$depictaiutilishared.catchify)(()=>delete cache_obj.cache_[body]), 300000);
351
+ }), 60000 // cache values for at least 60 seconds
352
+ );
353
+ return result;
288
354
  }
289
- const result = await search_results.json();
290
- cache_obj.cache_[body] = new WeakRef(result);
291
- resolve_in_progress(result);
292
- setTimeout((0, $diwD4$depictaiutilishared.catchify)(()=>{
293
- if (this.#supports_finalization_registry) cache_obj.finalization_registry_.register(result, body); // delete key from cache when value (WeakRefs) are collected
294
- else // delete things from cache after 5 minutes, so it doesn't get too heavy
295
- setTimeout((0, $diwD4$depictaiutilishared.catchify)(()=>delete cache_obj.cache_[body]), 300000);
296
- }), 30000 // cache values for at least 30 seconds
297
- );
298
- return result;
355
+ // If we get here, the request failed
356
+ const retval = fallback_response(input_req);
357
+ resolve_in_progress(retval);
358
+ return retval;
299
359
  } finally{
300
360
  delete cache_obj.in_progress_[body];
301
361
  }
302
362
  }
363
+ constructor(options){
364
+ const { get_metadata: get_metadata , get_user_id: get_user_id , get_session_id: get_session_id , page_url_creator: page_url_creator } = options ?? {};
365
+ this.#get_metadata = get_metadata;
366
+ this.#get_user_id = get_user_id;
367
+ this.#get_session_id = get_session_id;
368
+ this.page_url_creator = page_url_creator;
369
+ }
370
+ async suggest(input_req) {
371
+ const request = this.#add_ids_to_request(input_req);
372
+ const url = (0, $diwD4$depictaiutilishared.make_url_with_query_params)($e1d6c0f3d89d531c$var$search_base_url + "suggestions", request);
373
+ const results = await (0, $diwD4$depictaiutilishared.fetch_retry)((0, $diwD4$depictaiutilishared.add_version_query_params)(url));
374
+ attempt_to_return_api_response: {
375
+ if (!results) break attempt_to_return_api_response;
376
+ const decoded_json = await results.json();
377
+ if (!Array.isArray(decoded_json?.suggestions)) break attempt_to_return_api_response;
378
+ try {
379
+ return await this.#run_url_creator_for_suggest(input_req.tenant, input_req.market, decoded_json);
380
+ } catch (e) {
381
+ (0, $diwD4$depictaiutilishared.dwarn)("URL creator failed", e);
382
+ }
383
+ }
384
+ return {
385
+ "suggestions_request_id": "error",
386
+ "suggestions": [],
387
+ failed: true
388
+ };
389
+ }
303
390
  async query(input_req) {
304
- return await this.#cached_post_request($e1d6c0f3d89d531c$var$search_base_url + "results", input_req, (request)=>({
391
+ return await this.#cached_post_request($e1d6c0f3d89d531c$var$search_base_url + "results", input_req, ()=>({
305
392
  "n_hits": 0,
306
- "page": request.page ?? 1,
307
393
  "displays": [],
308
- "facets": [],
309
- "suggestions": [],
394
+ "sorts": [],
395
+ "filters": [],
310
396
  "search_request_id": "error",
311
397
  failed: true
312
398
  }));
313
399
  }
314
400
  async list(input_req) {
315
- return await this.#cached_post_request($e1d6c0f3d89d531c$var$v2_base_url + "product-listing", input_req, (request)=>({
401
+ return await this.#cached_post_request($e1d6c0f3d89d531c$var$v2_base_url + "product-listing", input_req, ()=>({
316
402
  "n_hits": 0,
317
- "page": request.page ?? 1,
318
403
  "displays": [],
319
- "facets": [],
320
- "suggestions": [],
404
+ "sorts": [],
405
+ "filters": [],
406
+ "breadcrumb": [],
407
+ "quick_links": [],
321
408
  "product_listing_request_id": "error",
322
409
  failed: true
323
410
  }));
324
411
  }
325
412
  async get_recommended(input_req) {
326
- // @ts-ignore ModernDisplay doesn't have arbitrary string access, and we'd like it to stay that way
327
413
  return await this.#cached_post_request($e1d6c0f3d89d531c$var$search_base_url + "related", input_req, ()=>({
328
414
  displays: []
329
415
  }));
@@ -947,6 +1033,7 @@ function $ac167f6af6a48fc3$export$a1fd619a4743ca08({ plp_results_: plp_results_
947
1033
  const record = records[i];
948
1034
  const { target: target , intersectionRatio: intersectionRatio } = record;
949
1035
  const index_of_target = target_to_index_map.get(target);
1036
+ if (index_of_target == undefined) return; // It seems like it can happen that we get IntersectionObserverEntries after the onCleanup function for a recommendation card has run, in Firefox. Probably a bug in Firefox? If I understood the bug correctly, this is a workaround.
950
1037
  const is_in_set = currently_intersecting.has(index_of_target);
951
1038
  if (intersectionRatio > 0) {
952
1039
  if (!is_in_set) currently_intersecting.add(index_of_target);
@@ -4346,23 +4433,30 @@ function $276380e4607fb9fb$export$6e49da55e449af7c({ scroll_restoration_data_: [
4346
4433
  ]); // get rid of old data the browser saves the old state and will restore it later on
4347
4434
  };
4348
4435
  (0, $diwD4$solidjs.createComputed)((0, $diwD4$depictaiutilishared.catchify)(()=>{
4349
- const r = get_last_result_in_viewport_();
4350
- if (r == undefined || r <= 0 || r == Infinity) return;
4436
+ const last_result = get_last_result_in_viewport_();
4437
+ if (last_result == undefined || last_result <= 0 || last_result == Infinity) return;
4438
+ if (isNaN(last_result)) {
4439
+ // if last_result is NaN there's an issue somewhere, but if we store something here that's not a number the for loop further down will break, and we won't be able to load results at all, so let's just continue
4440
+ (0, $diwD4$depictaiutilishared.report)(new Error("last_result is NaN, this should not happen"), "error", {
4441
+ last_result: last_result
4442
+ });
4443
+ return;
4444
+ }
4351
4445
  // We can push to history.state max 100 times per 30 seconds (Safari) so we have to debounce/cap this at 300ms for aggressive scrolling.
4352
4446
  // Pushing to history.state right before we leave the page (onunload etc.) is unreliable, as it has to occur *before* the next page is pushed to history.
4353
- // Instead we delay our push with a timeout set to the next acceptable interval to the previous one, when necessary
4447
+ // Instead, we delay our push with a timeout set to the next acceptable interval to the previous one, when necessary
4354
4448
  const now = +new Date();
4355
4449
  const time_since_last_ran = now - last_time_history_changed;
4356
4450
  if (time_since_last_ran > $276380e4607fb9fb$var$max_history_change_frequency) {
4357
4451
  // If the interval to the previous push is already long enough, it's fine to push the next value directly.
4358
- set_min_results_loaded(r);
4452
+ set_min_results_loaded(last_result);
4359
4453
  last_time_history_changed = now;
4360
4454
  // Even though the interval has passed, there could still be a delayed push timeout in flight (browser can delay timeouts at will).
4361
4455
  // We've already written the guaranteed-to-be-freshest value so we can just cancel it.
4362
4456
  clearTimeout(timeout);
4363
4457
  return;
4364
4458
  }
4365
- set_to_later = r;
4459
+ set_to_later = last_result;
4366
4460
  // If a delayed push timeout is already running, just changing the value that will be pushed is sufficient
4367
4461
  if (timeout) return;
4368
4462
  timeout = setTimeout((0, $diwD4$depictaiutilishared.catchify)(()=>{
@@ -5264,7 +5358,7 @@ class $48567ac5b39bac56$export$f34314aa9505732e {
5264
5358
  set on_navigation(new_function) {
5265
5359
  this.#router.on_navigation_ = new_function;
5266
5360
  }
5267
- constructor({ api: api , on_navigation: on_navigation , ...props_on_class }){
5361
+ constructor({ api: api , on_navigation: on_navigation , page_url_creator: page_url_creator , ...props_on_class }){
5268
5362
  const owner = (0, $diwD4$solidjs.getOwner)() || (0, $diwD4$solidjs.createRoot)(()=>(0, $diwD4$solidjs.getOwner)()); // we might have an owner, if so, pass it on. Otherwise, create one so solid doesn't print warnings to the console
5269
5363
  (0, $diwD4$solidjs.runWithOwner)(owner, ()=>{
5270
5364
  if ($48567ac5b39bac56$export$f34314aa9505732e.#has_been_constructed && !(0, $diwD4$solidjsweb.isServer)) // on the server we can't write stuff to history.state anyway so can have multiple
@@ -5292,7 +5386,9 @@ class $48567ac5b39bac56$export$f34314aa9505732e {
5292
5386
  quicklinks_signal_: (0, $diwD4$solidjs.createSignal)(),
5293
5387
  i18n_: i18n_,
5294
5388
  reset_history_state_: reset_history_state_,
5295
- depict_api_: api ?? new (0, $e1d6c0f3d89d531c$export$e015ed2f2950f2e3)(),
5389
+ depict_api_: api ?? new (0, $e1d6c0f3d89d531c$export$e015ed2f2950f2e3)({
5390
+ page_url_creator: page_url_creator
5391
+ }),
5296
5392
  router_: this.#router,
5297
5393
  selected_filters_: selected_filters_,
5298
5394
  current_sorting_: current_sorting_,
@@ -7429,7 +7525,7 @@ class $2c61e4cd8229c49a$export$ac6237957a15b3f0 {
7429
7525
  #modal_open_signal = (0, $diwD4$solidjs.createSignal)(false);
7430
7526
  static #has_been_constructed = false;
7431
7527
  #router = new (0, $e96dd13889871fc0$export$7e1297a3a19f10d8)("hard_navigation");
7432
- constructor({ search_query_url_param_name: search_query_url_param_name_ = "query" , url_transformer: url_transformer , on_navigation: on_navigation , enable_category_suggestions: enable_category_suggestions = true , disable_scrolling_during_modal: // Stuff needed for non-standard customer deployments that we shouldn't actually expose
7528
+ constructor({ search_query_url_param_name: search_query_url_param_name_ = "query" , url_transformer: url_transformer , on_navigation: on_navigation , enable_category_suggestions: enable_category_suggestions = true , page_url_creator: page_url_creator , disable_scrolling_during_modal: // Stuff needed for non-standard customer deployments that we shouldn't actually expose
7433
7529
  disable_scrolling_during_modal = true , api: api , bottom_distance_under_modal: bottom_distance_under_modal , render_instant_card: render_instant_card , ...props_on_class }){
7434
7530
  const owner = (0, $diwD4$solidjs.getOwner)() || (0, $diwD4$solidjs.createRoot)(()=>(0, $diwD4$solidjs.getOwner)()); // we might have an owner, if so, pass it on. Otherwise, create one so solid doesn't print warnings to the console
7435
7531
  (0, $diwD4$solidjs.runWithOwner)(owner, ()=>{
@@ -7458,7 +7554,9 @@ class $2c61e4cd8229c49a$export$ac6237957a15b3f0 {
7458
7554
  if (get_search_query_updating_blocked()) return previous_value;
7459
7555
  else return raw_search_query_accessor();
7460
7556
  });
7461
- const depict_api_ = api ?? new (0, $e1d6c0f3d89d531c$export$e015ed2f2950f2e3)();
7557
+ const depict_api_ = api ?? new (0, $e1d6c0f3d89d531c$export$e015ed2f2950f2e3)({
7558
+ page_url_creator: page_url_creator
7559
+ });
7462
7560
  const previous_searches = (0, $2b7a005a65221045$export$84bba84a7b837187)(get_search_query_);
7463
7561
  const [, set_search_showing_recommendation_rows] = state_.search_showing_recommendation_rows;
7464
7562
  const after_submit_ = ()=>set_search_showing_recommendation_rows((0, $fb29c6201c369e39$export$1c8c715550dc689d)); // do this every time after we have submitted a new query - otherwise there might already be a saved number of rows in the state
@@ -1,8 +1,8 @@
1
- import {add_to_version_info as $cV3wj$add_to_version_info, observer as $cV3wj$observer, catchify as $cV3wj$catchify, fetch_recs as $cV3wj$fetch_recs, snakeCasifyObject as $cV3wj$snakeCasifyObject, instant_exec_on_suspect_history_change as $cV3wj$instant_exec_on_suspect_history_change, base_url as $cV3wj$base_url, dlog as $cV3wj$dlog, get_depict_id as $cV3wj$get_depict_id, get_user_id as $cV3wj$get_user_id, get_session_id as $cV3wj$get_session_id, make_url_with_query_params as $cV3wj$make_url_with_query_params, fetch_retry as $cV3wj$fetch_retry, add_version_query_params as $cV3wj$add_version_query_params, sort_obj as $cV3wj$sort_obj, report as $cV3wj$report, javascript_media_query as $cV3wj$javascript_media_query, standard_price_format as $cV3wj$standard_price_format, make_random_classname as $cV3wj$make_random_classname, n_col_styling_with_dist as $cV3wj$n_col_styling_with_dist, useExpandingContainer as $cV3wj$useExpandingContainer, Amazing_Slider as $cV3wj$Amazing_Slider, slider_snap_css as $cV3wj$slider_snap_css, slider_fading_factory as $cV3wj$slider_fading_factory, hsl_to_rgb as $cV3wj$hsl_to_rgb, relative_luminance_from_rgb as $cV3wj$relative_luminance_from_rgb, base64_encode_unicode as $cV3wj$base64_encode_unicode, base64_decode_unicode as $cV3wj$base64_decode_unicode, queueMacroTask as $cV3wj$queueMacroTask, dwarn as $cV3wj$dwarn, Layout as $cV3wj$Layout, async_iterable_ipns as $cV3wj$async_iterable_ipns, make_asyncIterable_exiter as $cV3wj$make_asyncIterable_exiter, href_change_ipns as $cV3wj$href_change_ipns, ContainedImage as $cV3wj$ContainedImage, deparallelize_no_drop as $cV3wj$deparallelize_no_drop, insert_surfaces as $cV3wj$insert_surfaces} from "@depict-ai/utilishared";
1
+ import {add_to_version_info as $cV3wj$add_to_version_info, observer as $cV3wj$observer, catchify as $cV3wj$catchify, fetch_recs as $cV3wj$fetch_recs, snakeCasifyObject as $cV3wj$snakeCasifyObject, instant_exec_on_suspect_history_change as $cV3wj$instant_exec_on_suspect_history_change, base_url as $cV3wj$base_url, dlog as $cV3wj$dlog, get_depict_id as $cV3wj$get_depict_id, get_user_id as $cV3wj$get_user_id, get_session_id as $cV3wj$get_session_id, sort_obj as $cV3wj$sort_obj, fetch_retry as $cV3wj$fetch_retry, add_version_query_params as $cV3wj$add_version_query_params, dwarn as $cV3wj$dwarn, make_url_with_query_params as $cV3wj$make_url_with_query_params, report as $cV3wj$report, javascript_media_query as $cV3wj$javascript_media_query, standard_price_format as $cV3wj$standard_price_format, make_random_classname as $cV3wj$make_random_classname, n_col_styling_with_dist as $cV3wj$n_col_styling_with_dist, useExpandingContainer as $cV3wj$useExpandingContainer, Amazing_Slider as $cV3wj$Amazing_Slider, slider_snap_css as $cV3wj$slider_snap_css, slider_fading_factory as $cV3wj$slider_fading_factory, hsl_to_rgb as $cV3wj$hsl_to_rgb, relative_luminance_from_rgb as $cV3wj$relative_luminance_from_rgb, base64_encode_unicode as $cV3wj$base64_encode_unicode, base64_decode_unicode as $cV3wj$base64_decode_unicode, queueMacroTask as $cV3wj$queueMacroTask, Layout as $cV3wj$Layout, async_iterable_ipns as $cV3wj$async_iterable_ipns, make_asyncIterable_exiter as $cV3wj$make_asyncIterable_exiter, href_change_ipns as $cV3wj$href_change_ipns, ContainedImage as $cV3wj$ContainedImage, deparallelize_no_drop as $cV3wj$deparallelize_no_drop, insert_surfaces as $cV3wj$insert_surfaces} from "@depict-ai/utilishared";
2
2
  import {createRoot as $cV3wj$createRoot, createSignal as $cV3wj$createSignal, getOwner as $cV3wj$getOwner, runWithOwner as $cV3wj$runWithOwner, onCleanup as $cV3wj$onCleanup, createComputed as $cV3wj$createComputed, createRenderEffect as $cV3wj$createRenderEffect, createEffect as $cV3wj$createEffect, untrack as $cV3wj$untrack, batch as $cV3wj$batch, createResource as $cV3wj$createResource, createMemo as $cV3wj$createMemo, Show as $cV3wj$Show, createReaction as $cV3wj$createReaction, Suspense as $cV3wj$Suspense, on as $cV3wj$on, ErrorBoundary as $cV3wj$ErrorBoundary, For as $cV3wj$For, Index as $cV3wj$Index} from "solid-js";
3
3
  import {ssrElement as $cV3wj$ssrElement, ssr as $cV3wj$ssr, ssrHydrationKey as $cV3wj$ssrHydrationKey, ssrAttribute as $cV3wj$ssrAttribute, escape as $cV3wj$escape, isServer as $cV3wj$isServer, createComponent as $cV3wj$createComponent, ssrClassList as $cV3wj$ssrClassList, insert as $cV3wj$insert, ssrStyle as $cV3wj$ssrStyle, Dynamic as $cV3wj$Dynamic, mergeProps as $cV3wj$mergeProps} from "solid-js/web";
4
4
 
5
- /*! Depict.ai search and product listing SDK */ const $ec291e0010116877$export$83d89fbfd8236492 = "1.1.4";
5
+ /*! Depict.ai search and product listing SDK */ const $ec291e0010116877$export$83d89fbfd8236492 = "1.2.0";
6
6
 
7
7
 
8
8
 
@@ -187,26 +187,77 @@ class $7fa23e2a0079eca4$export$e015ed2f2950f2e3 {
187
187
  #get_metadata;
188
188
  #get_user_id;
189
189
  #get_session_id;
190
- constructor({ get_metadata: get_metadata , get_user_id: get_user_id , get_session_id: get_session_id } = {}){
191
- this.#get_metadata = get_metadata;
192
- this.#get_user_id = get_user_id;
193
- this.#get_session_id = get_session_id;
190
+ #guard_url_creator_length(expected, received) {
191
+ if (expected.length !== received.length) {
192
+ const e = new Error("Page URL creator returned wrong number of page URLs, got " + received.length + ", expected " + expected.length);
193
+ queueMicrotask(()=>{
194
+ throw e;
195
+ });
196
+ throw e;
197
+ }
194
198
  }
195
- async suggest(input_req) {
196
- const request = this.#add_ids_to_request(input_req);
197
- const url = (0, $cV3wj$make_url_with_query_params)($7fa23e2a0079eca4$var$search_base_url + "suggestions", request);
198
- const results = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(url));
199
- attempt_to_return_api_response: {
200
- if (!results) break attempt_to_return_api_response;
201
- const decoded_json = await results.json();
202
- if (!Array.isArray(decoded_json?.suggestions)) break attempt_to_return_api_response;
203
- return decoded_json;
199
+ async #run_url_creator_for_suggest(merchant, market, response) {
200
+ if (!this.page_url_creator) return response;
201
+ // find category suggestions, run thing with them, and then replace them
202
+ const category_suggestions = response.suggestions.filter((suggestion)=>suggestion.type === "category");
203
+ const page_urls = await this.page_url_creator({
204
+ type: "categories",
205
+ market: market,
206
+ merchant: merchant,
207
+ data: [
208
+ ...category_suggestions
209
+ ]
210
+ });
211
+ this.#guard_url_creator_length(category_suggestions, page_urls);
212
+ while(page_urls.length)Object.assign(category_suggestions.pop(), page_urls.pop());
213
+ return response;
214
+ }
215
+ async #run_url_creator_for_rest(merchant1, market1, input_data) {
216
+ if (!this.page_url_creator) return input_data;
217
+ const displays = input_data.displays;
218
+ const breadcrumb = input_data.breadcrumb;
219
+ const quick_links = input_data.quick_links;
220
+ if (displays) {
221
+ const page_urls = await this.page_url_creator({
222
+ type: "products",
223
+ merchant: merchant1,
224
+ market: market1,
225
+ displays: [
226
+ ...input_data.displays
227
+ ]
228
+ });
229
+ this.#guard_url_creator_length(displays, page_urls);
230
+ for(let i = 0; i < displays.length; i++){
231
+ const new_display_or_page_url = page_urls[i];
232
+ const old_display = displays[i];
233
+ if ("page_url" in new_display_or_page_url && Object.keys(new_display_or_page_url).length === 1) {
234
+ // they only returned page_url, let's put it into the display
235
+ const old_display_was_modern = "variant_index" in old_display;
236
+ if (old_display_was_modern) {
237
+ const variant_displays = old_display.variant_displays;
238
+ for(let i = 0; i < variant_displays.length; i++)variant_displays[i].page_url = new_display_or_page_url.page_url;
239
+ } else old_display.page_url = new_display_or_page_url.page_url;
240
+ } else // We got a whole new display, let's replace it
241
+ displays[i] = new_display_or_page_url;
242
+ }
204
243
  }
205
- return {
206
- "suggestions_request_id": "error",
207
- "suggestions": [],
208
- failed: true
209
- };
244
+ for (const category_display_array of [
245
+ breadcrumb,
246
+ quick_links
247
+ ]){
248
+ if (!category_display_array) continue;
249
+ const page_urls = await this.page_url_creator({
250
+ type: "categories",
251
+ merchant: merchant1,
252
+ market: market1,
253
+ data: [
254
+ ...category_display_array
255
+ ]
256
+ });
257
+ this.#guard_url_creator_length(category_display_array, page_urls);
258
+ for(let i = 0; i < category_display_array.length; i++)Object.assign(category_display_array[i], page_urls[i]);
259
+ }
260
+ return input_data;
210
261
  }
211
262
  async #cached_post_request(endpoint1, input_req, fallback_response) {
212
263
  const cache_obj = this.#get_cache_obj_for_endpoint(endpoint1);
@@ -223,66 +274,101 @@ class $7fa23e2a0079eca4$export$e015ed2f2950f2e3 {
223
274
  let resolve_in_progress;
224
275
  cache_obj.in_progress_[body] = new Promise((r)=>resolve_in_progress = r);
225
276
  try {
226
- let search_results = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(endpoint1), {
277
+ let api_response = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(endpoint1), {
227
278
  method: "POST",
228
279
  body: body
229
280
  });
230
281
  if ("query_id" in request && request.type === "collection") // FIXME: Remove. Backwards compatibility layer
231
282
  // This will retry the request without the collection type if the first request fails
232
283
  {
233
- if (!search_results || search_results?.status === 404) {
284
+ if (!api_response || api_response?.status === 404) {
234
285
  (0, $cV3wj$dlog)("Fallback request for collections due to failure");
235
286
  const fallback_body = JSON.parse(body);
236
287
  delete fallback_body.type;
237
- search_results = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(endpoint1), {
288
+ api_response = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(endpoint1), {
238
289
  method: "POST",
239
290
  body: JSON.stringify(fallback_body)
240
291
  });
241
292
  }
242
293
  }
243
- if (!search_results || search_results.status !== 200) {
244
- const retval = fallback_response(input_req);
245
- resolve_in_progress(retval);
246
- return retval;
294
+ return_successfully: {
295
+ if (!api_response || api_response.status !== 200) break return_successfully;
296
+ let result;
297
+ try {
298
+ const unmodified_result = await api_response.json();
299
+ result = await this.#run_url_creator_for_rest(input_req.tenant, input_req.market, unmodified_result);
300
+ } catch (e) {
301
+ (0, $cV3wj$dwarn)("URL creator or json decoding failed", e);
302
+ break return_successfully;
303
+ }
304
+ cache_obj.cache_[body] = new WeakRef(result);
305
+ resolve_in_progress(result);
306
+ setTimeout((0, $cV3wj$catchify)(()=>{
307
+ if (this.#supports_finalization_registry) cache_obj.finalization_registry_.register(result, body); // delete key from cache when value (WeakRefs) are collected
308
+ else // delete things from cache after 5 minutes, so it doesn't get too heavy
309
+ setTimeout((0, $cV3wj$catchify)(()=>delete cache_obj.cache_[body]), 300000);
310
+ }), 60000 // cache values for at least 60 seconds
311
+ );
312
+ return result;
247
313
  }
248
- const result = await search_results.json();
249
- cache_obj.cache_[body] = new WeakRef(result);
250
- resolve_in_progress(result);
251
- setTimeout((0, $cV3wj$catchify)(()=>{
252
- if (this.#supports_finalization_registry) cache_obj.finalization_registry_.register(result, body); // delete key from cache when value (WeakRefs) are collected
253
- else // delete things from cache after 5 minutes, so it doesn't get too heavy
254
- setTimeout((0, $cV3wj$catchify)(()=>delete cache_obj.cache_[body]), 300000);
255
- }), 30000 // cache values for at least 30 seconds
256
- );
257
- return result;
314
+ // If we get here, the request failed
315
+ const retval = fallback_response(input_req);
316
+ resolve_in_progress(retval);
317
+ return retval;
258
318
  } finally{
259
319
  delete cache_obj.in_progress_[body];
260
320
  }
261
321
  }
322
+ constructor(options){
323
+ const { get_metadata: get_metadata , get_user_id: get_user_id , get_session_id: get_session_id , page_url_creator: page_url_creator } = options ?? {};
324
+ this.#get_metadata = get_metadata;
325
+ this.#get_user_id = get_user_id;
326
+ this.#get_session_id = get_session_id;
327
+ this.page_url_creator = page_url_creator;
328
+ }
329
+ async suggest(input_req) {
330
+ const request = this.#add_ids_to_request(input_req);
331
+ const url = (0, $cV3wj$make_url_with_query_params)($7fa23e2a0079eca4$var$search_base_url + "suggestions", request);
332
+ const results = await (0, $cV3wj$fetch_retry)((0, $cV3wj$add_version_query_params)(url));
333
+ attempt_to_return_api_response: {
334
+ if (!results) break attempt_to_return_api_response;
335
+ const decoded_json = await results.json();
336
+ if (!Array.isArray(decoded_json?.suggestions)) break attempt_to_return_api_response;
337
+ try {
338
+ return await this.#run_url_creator_for_suggest(input_req.tenant, input_req.market, decoded_json);
339
+ } catch (e) {
340
+ (0, $cV3wj$dwarn)("URL creator failed", e);
341
+ }
342
+ }
343
+ return {
344
+ "suggestions_request_id": "error",
345
+ "suggestions": [],
346
+ failed: true
347
+ };
348
+ }
262
349
  async query(input_req) {
263
- return await this.#cached_post_request($7fa23e2a0079eca4$var$search_base_url + "results", input_req, (request)=>({
350
+ return await this.#cached_post_request($7fa23e2a0079eca4$var$search_base_url + "results", input_req, ()=>({
264
351
  "n_hits": 0,
265
- "page": request.page ?? 1,
266
352
  "displays": [],
267
- "facets": [],
268
- "suggestions": [],
353
+ "sorts": [],
354
+ "filters": [],
269
355
  "search_request_id": "error",
270
356
  failed: true
271
357
  }));
272
358
  }
273
359
  async list(input_req) {
274
- return await this.#cached_post_request($7fa23e2a0079eca4$var$v2_base_url + "product-listing", input_req, (request)=>({
360
+ return await this.#cached_post_request($7fa23e2a0079eca4$var$v2_base_url + "product-listing", input_req, ()=>({
275
361
  "n_hits": 0,
276
- "page": request.page ?? 1,
277
362
  "displays": [],
278
- "facets": [],
279
- "suggestions": [],
363
+ "sorts": [],
364
+ "filters": [],
365
+ "breadcrumb": [],
366
+ "quick_links": [],
280
367
  "product_listing_request_id": "error",
281
368
  failed: true
282
369
  }));
283
370
  }
284
371
  async get_recommended(input_req) {
285
- // @ts-ignore ModernDisplay doesn't have arbitrary string access, and we'd like it to stay that way
286
372
  return await this.#cached_post_request($7fa23e2a0079eca4$var$search_base_url + "related", input_req, ()=>({
287
373
  displays: []
288
374
  }));
@@ -906,6 +992,7 @@ function $0449e7d49398c077$export$a1fd619a4743ca08({ plp_results_: plp_results_
906
992
  const record = records[i];
907
993
  const { target: target , intersectionRatio: intersectionRatio } = record;
908
994
  const index_of_target = target_to_index_map.get(target);
995
+ if (index_of_target == undefined) return; // It seems like it can happen that we get IntersectionObserverEntries after the onCleanup function for a recommendation card has run, in Firefox. Probably a bug in Firefox? If I understood the bug correctly, this is a workaround.
909
996
  const is_in_set = currently_intersecting.has(index_of_target);
910
997
  if (intersectionRatio > 0) {
911
998
  if (!is_in_set) currently_intersecting.add(index_of_target);
@@ -4305,23 +4392,30 @@ function $641bba2917fe862b$export$6e49da55e449af7c({ scroll_restoration_data_: [
4305
4392
  ]); // get rid of old data the browser saves the old state and will restore it later on
4306
4393
  };
4307
4394
  (0, $cV3wj$createComputed)((0, $cV3wj$catchify)(()=>{
4308
- const r = get_last_result_in_viewport_();
4309
- if (r == undefined || r <= 0 || r == Infinity) return;
4395
+ const last_result = get_last_result_in_viewport_();
4396
+ if (last_result == undefined || last_result <= 0 || last_result == Infinity) return;
4397
+ if (isNaN(last_result)) {
4398
+ // if last_result is NaN there's an issue somewhere, but if we store something here that's not a number the for loop further down will break, and we won't be able to load results at all, so let's just continue
4399
+ (0, $cV3wj$report)(new Error("last_result is NaN, this should not happen"), "error", {
4400
+ last_result: last_result
4401
+ });
4402
+ return;
4403
+ }
4310
4404
  // We can push to history.state max 100 times per 30 seconds (Safari) so we have to debounce/cap this at 300ms for aggressive scrolling.
4311
4405
  // Pushing to history.state right before we leave the page (onunload etc.) is unreliable, as it has to occur *before* the next page is pushed to history.
4312
- // Instead we delay our push with a timeout set to the next acceptable interval to the previous one, when necessary
4406
+ // Instead, we delay our push with a timeout set to the next acceptable interval to the previous one, when necessary
4313
4407
  const now = +new Date();
4314
4408
  const time_since_last_ran = now - last_time_history_changed;
4315
4409
  if (time_since_last_ran > $641bba2917fe862b$var$max_history_change_frequency) {
4316
4410
  // If the interval to the previous push is already long enough, it's fine to push the next value directly.
4317
- set_min_results_loaded(r);
4411
+ set_min_results_loaded(last_result);
4318
4412
  last_time_history_changed = now;
4319
4413
  // Even though the interval has passed, there could still be a delayed push timeout in flight (browser can delay timeouts at will).
4320
4414
  // We've already written the guaranteed-to-be-freshest value so we can just cancel it.
4321
4415
  clearTimeout(timeout);
4322
4416
  return;
4323
4417
  }
4324
- set_to_later = r;
4418
+ set_to_later = last_result;
4325
4419
  // If a delayed push timeout is already running, just changing the value that will be pushed is sufficient
4326
4420
  if (timeout) return;
4327
4421
  timeout = setTimeout((0, $cV3wj$catchify)(()=>{
@@ -5223,7 +5317,7 @@ class $961b5c64bef4662f$export$f34314aa9505732e {
5223
5317
  set on_navigation(new_function) {
5224
5318
  this.#router.on_navigation_ = new_function;
5225
5319
  }
5226
- constructor({ api: api , on_navigation: on_navigation , ...props_on_class }){
5320
+ constructor({ api: api , on_navigation: on_navigation , page_url_creator: page_url_creator , ...props_on_class }){
5227
5321
  const owner = (0, $cV3wj$getOwner)() || (0, $cV3wj$createRoot)(()=>(0, $cV3wj$getOwner)()); // we might have an owner, if so, pass it on. Otherwise, create one so solid doesn't print warnings to the console
5228
5322
  (0, $cV3wj$runWithOwner)(owner, ()=>{
5229
5323
  if ($961b5c64bef4662f$export$f34314aa9505732e.#has_been_constructed && !(0, $cV3wj$isServer)) // on the server we can't write stuff to history.state anyway so can have multiple
@@ -5251,7 +5345,9 @@ class $961b5c64bef4662f$export$f34314aa9505732e {
5251
5345
  quicklinks_signal_: (0, $cV3wj$createSignal)(),
5252
5346
  i18n_: i18n_,
5253
5347
  reset_history_state_: reset_history_state_,
5254
- depict_api_: api ?? new (0, $7fa23e2a0079eca4$export$e015ed2f2950f2e3)(),
5348
+ depict_api_: api ?? new (0, $7fa23e2a0079eca4$export$e015ed2f2950f2e3)({
5349
+ page_url_creator: page_url_creator
5350
+ }),
5255
5351
  router_: this.#router,
5256
5352
  selected_filters_: selected_filters_,
5257
5353
  current_sorting_: current_sorting_,
@@ -7388,7 +7484,7 @@ class $806c97b931758897$export$ac6237957a15b3f0 {
7388
7484
  #modal_open_signal = (0, $cV3wj$createSignal)(false);
7389
7485
  static #has_been_constructed = false;
7390
7486
  #router = new (0, $4fd2ba03703a7d92$export$7e1297a3a19f10d8)("hard_navigation");
7391
- constructor({ search_query_url_param_name: search_query_url_param_name_ = "query" , url_transformer: url_transformer , on_navigation: on_navigation , enable_category_suggestions: enable_category_suggestions = true , disable_scrolling_during_modal: // Stuff needed for non-standard customer deployments that we shouldn't actually expose
7487
+ constructor({ search_query_url_param_name: search_query_url_param_name_ = "query" , url_transformer: url_transformer , on_navigation: on_navigation , enable_category_suggestions: enable_category_suggestions = true , page_url_creator: page_url_creator , disable_scrolling_during_modal: // Stuff needed for non-standard customer deployments that we shouldn't actually expose
7392
7488
  disable_scrolling_during_modal = true , api: api , bottom_distance_under_modal: bottom_distance_under_modal , render_instant_card: render_instant_card , ...props_on_class }){
7393
7489
  const owner = (0, $cV3wj$getOwner)() || (0, $cV3wj$createRoot)(()=>(0, $cV3wj$getOwner)()); // we might have an owner, if so, pass it on. Otherwise, create one so solid doesn't print warnings to the console
7394
7490
  (0, $cV3wj$runWithOwner)(owner, ()=>{
@@ -7417,7 +7513,9 @@ class $806c97b931758897$export$ac6237957a15b3f0 {
7417
7513
  if (get_search_query_updating_blocked()) return previous_value;
7418
7514
  else return raw_search_query_accessor();
7419
7515
  });
7420
- const depict_api_ = api ?? new (0, $7fa23e2a0079eca4$export$e015ed2f2950f2e3)();
7516
+ const depict_api_ = api ?? new (0, $7fa23e2a0079eca4$export$e015ed2f2950f2e3)({
7517
+ page_url_creator: page_url_creator
7518
+ });
7421
7519
  const previous_searches = (0, $21f51c14cb3f586f$export$84bba84a7b837187)(get_search_query_);
7422
7520
  const [, set_search_showing_recommendation_rows] = state_.search_showing_recommendation_rows;
7423
7521
  const after_submit_ = ()=>set_search_showing_recommendation_rows((0, $172e1b898d457050$export$1c8c715550dc689d)); // do this every time after we have submitted a new query - otherwise there might already be a saved number of rows in the state