@getlupa/client 1.18.5 → 1.19.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.
@@ -12588,7 +12588,7 @@ var __async = (__this, __arguments, generator) => {
12588
12588
  return "";
12589
12589
  }
12590
12590
  const transformedStr = typeof str === "string" ? str : str.toString();
12591
- return transformedStr.normalize === void 0 ? (_a = transformedStr.toLocaleLowerCase()) == null ? void 0 : _a.trim() : (_b = transformedStr.toLocaleLowerCase().normalize("NFKD").replace(/[^\w\s.-_/]/g, "")) == null ? void 0 : _b.trim();
12591
+ return transformedStr.normalize === void 0 ? (_a = transformedStr.toLocaleLowerCase()) == null ? void 0 : _a.trim() : (_b = transformedStr.toLocaleLowerCase().normalize("NFKD").replace(/[^\p{L}\p{N}\s]/gu, "")) == null ? void 0 : _b.trim();
12592
12592
  };
12593
12593
  const getTransformedString = (str) => {
12594
12594
  var _a, _b;
@@ -14328,8 +14328,8 @@ var __async = (__this, __arguments, generator) => {
14328
14328
  staging: "https://api.staging.lupasearch.com/v1/"
14329
14329
  };
14330
14330
  const VoiceServiceEnv = {
14331
- production: "ws://voice.lupasearch.com:3001",
14332
- staging: "ws://voice.lupasearch.dev:3001"
14331
+ production: "wss://voice.lupasearch.com",
14332
+ staging: "wss://voice.lupasearch.dev"
14333
14333
  };
14334
14334
  const DEFAULT_REQUEST_CONFIG = {
14335
14335
  method: "POST",
@@ -14370,7 +14370,7 @@ var __async = (__this, __arguments, generator) => {
14370
14370
  }
14371
14371
  };
14372
14372
  const startProgressBar = () => {
14373
- if (!progressBar.value || !props.isRecording) {
14373
+ if (!progressBar.value) {
14374
14374
  return;
14375
14375
  }
14376
14376
  const duration = props.timesliceLimit * props.timeSliceLength;
@@ -14428,6 +14428,7 @@ var __async = (__this, __arguments, generator) => {
14428
14428
  const mediaStream = ref(null);
14429
14429
  const mediaRecorder = ref(null);
14430
14430
  const isRecording = ref(false);
14431
+ const isSocketReady = ref(false);
14431
14432
  const errorRef = ref(null);
14432
14433
  const transcription = ref("");
14433
14434
  const timeSliceLength = computed(() => {
@@ -14440,35 +14441,51 @@ var __async = (__this, __arguments, generator) => {
14440
14441
  });
14441
14442
  const initSocket = (url, onMessage) => {
14442
14443
  socket.value = new WebSocket(url);
14443
- socket.value.onopen = () => __async2(this, null, function* () {
14444
+ socket.value.onmessage = (event) => __async2(this, null, function* () {
14444
14445
  var _a;
14445
- if (((_a = mediaRecorder.value) == null ? void 0 : _a.state) !== "recording") {
14446
- yield startRecording();
14446
+ try {
14447
+ const msg = JSON.parse(event.data);
14448
+ if (msg.event === "ready") {
14449
+ if (((_a = mediaRecorder.value) == null ? void 0 : _a.state) !== "recording") {
14450
+ try {
14451
+ isSocketReady.value = true;
14452
+ yield startRecording();
14453
+ } catch (error) {
14454
+ console.error("Recording failed to start:", error);
14455
+ closeSocket();
14456
+ }
14457
+ }
14458
+ } else if (msg.event === "transcription") {
14459
+ transcription.value = msg.transcription;
14460
+ onMessage == null ? void 0 : onMessage(msg.transcription);
14461
+ stopSocketConnection();
14462
+ } else if (msg.event === "error") {
14463
+ errorRef.value = msg.message || "An error occurred during transcription";
14464
+ isSocketReady.value = false;
14465
+ stopRecording();
14466
+ closeSocket();
14467
+ }
14468
+ } catch (error) {
14469
+ console.error("Error processing WebSocket message:", error);
14447
14470
  }
14448
14471
  });
14449
- socket.value.onmessage = (event) => {
14450
- const msg = JSON.parse(event.data);
14451
- if (msg.event === "transcription") {
14452
- transcription.value = msg.transcription;
14453
- onMessage == null ? void 0 : onMessage(msg.transcription);
14454
- stopSocketConnection();
14455
- } else if (msg.event === "error") {
14456
- errorRef.value = "Server error during transcription";
14457
- stopRecording();
14472
+ socket.value.onclose = (event) => {
14473
+ if (event.code === 4001) {
14474
+ errorRef.value = event.reason || "Connection closed by server";
14458
14475
  }
14459
- };
14460
- socket.value.onclose = () => {
14461
14476
  stopRecording();
14462
14477
  };
14463
14478
  socket.value.onerror = () => {
14464
- stopRecording();
14465
14479
  errorRef.value = "Service connection error";
14480
+ stopRecording();
14466
14481
  };
14467
14482
  };
14468
14483
  const onMediaRecorderDataAvailable = (event) => __async2(this, null, function* () {
14469
14484
  var _a, _b;
14470
- if (((_a = mediaRecorder.value) == null ? void 0 : _a.state) !== "recording")
14485
+ if (!isSocketReady.value || ((_a = socket.value) == null ? void 0 : _a.readyState) !== WebSocket.OPEN) {
14486
+ console.warn("Skipping audio chunk: socket not ready.");
14471
14487
  return;
14488
+ }
14472
14489
  const audioBuffer = yield event.data.arrayBuffer();
14473
14490
  const header = buildSocketMessageFrameHeader("audio-chunk", audioBuffer.byteLength);
14474
14491
  const buffer = new Uint8Array(header.length + audioBuffer.byteLength);
@@ -14477,20 +14494,29 @@ var __async = (__this, __arguments, generator) => {
14477
14494
  (_b = socket.value) == null ? void 0 : _b.send(buffer);
14478
14495
  });
14479
14496
  const startRecording = () => __async2(this, null, function* () {
14480
- mediaStream.value = yield navigator.mediaDevices.getUserMedia({
14481
- video: false,
14482
- audio: {
14483
- channelCount: 1,
14484
- echoCancellation: true,
14485
- sampleRate: 16e3
14497
+ var _a, _b;
14498
+ try {
14499
+ mediaStream.value = yield navigator.mediaDevices.getUserMedia({
14500
+ video: false,
14501
+ audio: {
14502
+ channelCount: 1,
14503
+ echoCancellation: true,
14504
+ sampleRate: options.sampleRate || 16e3
14505
+ }
14506
+ });
14507
+ mediaRecorder.value = new MediaRecorder(mediaStream.value, {
14508
+ mimeType: "audio/webm; codecs=opus"
14509
+ });
14510
+ mediaRecorder.value.ondataavailable = onMediaRecorderDataAvailable;
14511
+ mediaRecorder.value.start(timeSliceLength.value);
14512
+ isRecording.value = true;
14513
+ } catch (error) {
14514
+ if (error.name === "NotAllowedError") {
14515
+ errorRef.value = ((_a = options.labels) == null ? void 0 : _a.microphoneNotAllowed) || "Microphone access denied. Please allow microphone access in your browser settings.";
14516
+ } else if (error.name === "NotFoundError") {
14517
+ errorRef.value = ((_b = options.labels) == null ? void 0 : _b.microphoneNotFound) || "No microphone found. Please connect a microphone and try again.";
14486
14518
  }
14487
- });
14488
- mediaRecorder.value = new MediaRecorder(mediaStream.value, {
14489
- mimeType: "audio/webm; codecs=opus"
14490
- });
14491
- mediaRecorder.value.ondataavailable = onMediaRecorderDataAvailable;
14492
- mediaRecorder.value.start(timeSliceLength.value);
14493
- isRecording.value = true;
14519
+ }
14494
14520
  });
14495
14521
  const stopRecording = () => {
14496
14522
  var _a, _b;
@@ -14513,6 +14539,7 @@ var __async = (__this, __arguments, generator) => {
14513
14539
  var _a;
14514
14540
  (_a = socket.value) == null ? void 0 : _a.close();
14515
14541
  socket.value = null;
14542
+ isSocketReady.value = false;
14516
14543
  };
14517
14544
  const reset = () => {
14518
14545
  stopRecording();
@@ -14520,9 +14547,11 @@ var __async = (__this, __arguments, generator) => {
14520
14547
  transcription.value = "";
14521
14548
  errorRef.value = null;
14522
14549
  isRecording.value = false;
14550
+ isSocketReady.value = false;
14523
14551
  };
14524
14552
  return {
14525
14553
  isRecording,
14554
+ isSocketReady,
14526
14555
  transcription,
14527
14556
  errorRef,
14528
14557
  initSocket,
@@ -14556,6 +14585,7 @@ var __async = (__this, __arguments, generator) => {
14556
14585
  const optionsStore = useOptionsStore();
14557
14586
  const {
14558
14587
  isRecording,
14588
+ isSocketReady,
14559
14589
  transcription,
14560
14590
  errorRef,
14561
14591
  initSocket,
@@ -14581,20 +14611,28 @@ var __async = (__this, __arguments, generator) => {
14581
14611
  return (_a = props.options.labels) != null ? _a : {};
14582
14612
  });
14583
14613
  const description = computed(() => {
14584
- var _a, _b, _c;
14614
+ var _a, _b;
14585
14615
  if (errorRef.value) {
14586
- return (_a = labels.value.serviceError) != null ? _a : errorRef.value;
14616
+ return errorRef.value;
14587
14617
  }
14588
- if (!isRecording.value) {
14589
- return (_b = labels.value.microphoneOff) != null ? _b : "Microphone is off. Try again.";
14618
+ if (!isSocketReady.value || !isRecording.value) {
14619
+ return (_a = labels.value.connecting) != null ? _a : "Connecting...";
14590
14620
  }
14591
- return (_c = labels.value.listening) != null ? _c : "Listening...";
14621
+ return (_b = labels.value.listening) != null ? _b : "Listening...";
14592
14622
  });
14593
14623
  watch(transcription, (newValue) => {
14594
14624
  emit2("transcript-update", newValue);
14595
14625
  });
14596
- const handleRecordingButtonClick = () => {
14626
+ watch(isRecording, (newVal) => {
14597
14627
  var _a, _b;
14628
+ if (newVal === true) {
14629
+ (_a = voiceSearchProgressBar.value) == null ? void 0 : _a.startProgressBar();
14630
+ } else {
14631
+ (_b = voiceSearchProgressBar.value) == null ? void 0 : _b.stopProgressBar();
14632
+ }
14633
+ });
14634
+ const handleRecordingButtonClick = () => {
14635
+ var _a;
14598
14636
  if (isRecording.value) {
14599
14637
  setTimeout(() => {
14600
14638
  stopSocketConnection();
@@ -14608,7 +14646,6 @@ var __async = (__this, __arguments, generator) => {
14608
14646
  );
14609
14647
  const socketUrl = `${voiceServiceUrl}?clientId=${clientId.value}&queryKey=${props.options.queryKey}&languageCode=${(_a = props.options.language) != null ? _a : "en-US"}&connectionType=write-first`;
14610
14648
  initSocket(socketUrl);
14611
- (_b = voiceSearchProgressBar.value) == null ? void 0 : _b.startProgressBar();
14612
14649
  setTimeout(() => {
14613
14650
  stopSocketConnection();
14614
14651
  handleOnStopEvent();
@@ -24291,6 +24328,15 @@ and ensure you are accounting for this risk.
24291
24328
  return false;
24292
24329
  }
24293
24330
  };
24331
+ function shouldDisplay(displayOpt, doc2) {
24332
+ if (!displayOpt)
24333
+ return true;
24334
+ if (typeof displayOpt === "function") {
24335
+ return displayOpt(doc2);
24336
+ }
24337
+ const rules = Array.isArray(displayOpt) ? displayOpt : [displayOpt];
24338
+ return rules.every((rule2) => processDisplayCondition(rule2, doc2));
24339
+ }
24294
24340
  const checkHasFullImageUrl = (imageUrl) => typeof imageUrl === "string" && (imageUrl.indexOf("http://") === 0 || imageUrl.indexOf("https://") === 0);
24295
24341
  const computeImageUrl = (imageUrl, rootImageUrl) => {
24296
24342
  const mainUrl = Array.isArray(imageUrl) ? imageUrl[0] : imageUrl;
@@ -25107,7 +25153,7 @@ and ensure you are accounting for this risk.
25107
25153
  if (!element.display) {
25108
25154
  return true;
25109
25155
  }
25110
- return typeof element.display === "function" ? element.display(item) : processDisplayCondition(element.display, item);
25156
+ return shouldDisplay(element.display, item);
25111
25157
  });
25112
25158
  const enhancedItem = computed(() => {
25113
25159
  var _a, _b, _c, _d;
@@ -25430,7 +25476,7 @@ and ensure you are accounting for this risk.
25430
25476
  if (!element.display) {
25431
25477
  return true;
25432
25478
  }
25433
- return typeof element.display === "function" ? element.display(item) : processDisplayCondition(element.display, item);
25479
+ return shouldDisplay(element.display, item);
25434
25480
  };
25435
25481
  const badges = computed(() => {
25436
25482
  if (!props.options.elements) {
@@ -25508,10 +25554,6 @@ and ensure you are accounting for this risk.
25508
25554
  const badgeOptions = computed(() => {
25509
25555
  return __spreadProps2(__spreadValues2({}, props.panelOptions.badges), { product: props.item });
25510
25556
  });
25511
- const imageElements = computed(() => {
25512
- var _a, _b;
25513
- return (_b = (_a = props.panelOptions.elements) == null ? void 0 : _a.filter((e2) => e2.type === DocumentElementType.IMAGE)) != null ? _b : [];
25514
- });
25515
25557
  const mainImageElement = computed(() => {
25516
25558
  return imageElements.value[0];
25517
25559
  });
@@ -25531,12 +25573,6 @@ and ensure you are accounting for this risk.
25531
25573
  minWidth: widthOverride.value ? `${widthOverride.value + 10}px` : void 0
25532
25574
  } : {};
25533
25575
  });
25534
- const detailElements = computed(() => {
25535
- var _a, _b;
25536
- return (_b = (_a = props.panelOptions.elements) == null ? void 0 : _a.filter(
25537
- (e2) => e2.type !== DocumentElementType.IMAGE && e2.type !== DocumentElementType.ADDTOCART
25538
- )) != null ? _b : [];
25539
- });
25540
25576
  const addToCartElement = computed(() => {
25541
25577
  var _a;
25542
25578
  return (_a = props.panelOptions.elements) == null ? void 0 : _a.find((e2) => e2.type === DocumentElementType.ADDTOCART);
@@ -25555,12 +25591,42 @@ and ensure you are accounting for this risk.
25555
25591
  onMounted(() => {
25556
25592
  checkIfIsInStock();
25557
25593
  });
25558
- const processIsInStock = () => {
25559
- return typeof props.panelOptions.isInStock === "function" ? props.panelOptions.isInStock(props.item) : processDisplayCondition(props.panelOptions.isInStock, props.item);
25560
- };
25594
+ const processIsInStock = computed(() => {
25595
+ const raw = props.panelOptions.isInStock;
25596
+ if (!raw)
25597
+ return true;
25598
+ const rules = Array.isArray(raw) ? raw : [raw];
25599
+ return rules.every((rule2) => shouldDisplay(rule2, props.item));
25600
+ });
25561
25601
  const checkIfIsInStock = () => __async2(this, null, function* () {
25562
- isInStock.value = props.panelOptions.isInStock ? processIsInStock() : true;
25602
+ isInStock.value = props.panelOptions.isInStock ? processIsInStock.value : true;
25563
25603
  });
25604
+ const imageElements = computed(
25605
+ () => {
25606
+ var _a, _b;
25607
+ return (_b = (_a = props.panelOptions.elements) == null ? void 0 : _a.filter((e2) => e2.type === DocumentElementType.IMAGE && !e2.group)) != null ? _b : [];
25608
+ }
25609
+ );
25610
+ const detailElements = computed(
25611
+ () => {
25612
+ var _a, _b;
25613
+ return (_b = (_a = props.panelOptions.elements) == null ? void 0 : _a.filter(
25614
+ (e2) => e2.type !== DocumentElementType.IMAGE && e2.type !== DocumentElementType.ADDTOCART && !e2.group
25615
+ )) != null ? _b : [];
25616
+ }
25617
+ );
25618
+ const elementGroups = computed(
25619
+ () => {
25620
+ var _a;
25621
+ return Array.from(
25622
+ new Set((_a = props.panelOptions.elements) == null ? void 0 : _a.map((e2) => e2.group).filter((g) => Boolean(g)))
25623
+ );
25624
+ }
25625
+ );
25626
+ function getGroupElements(group) {
25627
+ var _a, _b;
25628
+ return (_b = (_a = props.panelOptions.elements) == null ? void 0 : _a.filter((e2) => e2.group === group)) != null ? _b : [];
25629
+ }
25564
25630
  return (_ctx, _cache) => {
25565
25631
  return openBlock(), createElementBlock("a", mergeProps({
25566
25632
  class: ["lupa-search-box-product", { "lupa-search-box-product-highlighted": _ctx.highlighted }],
@@ -25576,9 +25642,9 @@ and ensure you are accounting for this risk.
25576
25642
  (openBlock(true), createElementBlock(Fragment, null, renderList(imageElements.value, (element) => {
25577
25643
  return openBlock(), createBlock(_sfc_main$1g, {
25578
25644
  class: "lupa-search-box-product-element",
25645
+ key: element.key,
25579
25646
  item: _ctx.item,
25580
25647
  element,
25581
- key: element.key,
25582
25648
  labels: _ctx.labels,
25583
25649
  link: link.value
25584
25650
  }, null, 8, ["item", "element", "labels", "link"]);
@@ -25588,14 +25654,14 @@ and ensure you are accounting for this risk.
25588
25654
  (openBlock(true), createElementBlock(Fragment, null, renderList(detailElements.value, (element) => {
25589
25655
  var _a;
25590
25656
  return openBlock(), createBlock(_sfc_main$1g, {
25591
- key: element.key,
25592
25657
  class: "lupa-search-box-product-element",
25658
+ key: element.key,
25593
25659
  item: _ctx.item,
25594
25660
  element,
25595
25661
  labels: _ctx.labels,
25596
25662
  link: link.value
25597
25663
  }, createSlots({ _: 2 }, [
25598
- badgeOptions.value && ((_a = badgeOptions.value) == null ? void 0 : _a.anchorElementKey) === element.key ? {
25664
+ ((_a = badgeOptions.value) == null ? void 0 : _a.anchorElementKey) === element.key ? {
25599
25665
  name: "badges",
25600
25666
  fn: withCtx(() => [
25601
25667
  createVNode(_sfc_main$19, {
@@ -25608,6 +25674,24 @@ and ensure you are accounting for this risk.
25608
25674
  ]), 1032, ["item", "element", "labels", "link"]);
25609
25675
  }), 128))
25610
25676
  ]),
25677
+ (openBlock(true), createElementBlock(Fragment, null, renderList(elementGroups.value, (group) => {
25678
+ return openBlock(), createElementBlock("div", {
25679
+ key: group,
25680
+ class: normalizeClass(`lupa-search-box-group-${group}`)
25681
+ }, [
25682
+ (openBlock(true), createElementBlock(Fragment, null, renderList(getGroupElements(group), (element) => {
25683
+ return openBlock(), createBlock(_sfc_main$1g, {
25684
+ class: "lupa-search-box-product-element",
25685
+ key: element.key,
25686
+ item: _ctx.item,
25687
+ element,
25688
+ labels: _ctx.labels,
25689
+ link: link.value,
25690
+ isInStock: isInStock.value
25691
+ }, null, 8, ["item", "element", "labels", "link", "isInStock"]);
25692
+ }), 128))
25693
+ ], 2);
25694
+ }), 128)),
25611
25695
  addToCartElement.value ? (openBlock(), createElementBlock("div", _hoisted_3$z, [
25612
25696
  createVNode(_sfc_main$1g, {
25613
25697
  class: "lupa-search-box-product-element",
@@ -30604,14 +30688,9 @@ and ensure you are accounting for this risk.
30604
30688
  const enhancementData = (_d = (_c = dynamicDataIdMap.value) == null ? void 0 : _c[(_b = props.item) == null ? void 0 : _b.id]) != null ? _d : {};
30605
30689
  return __spreadValues2(__spreadValues2({}, props.item), enhancementData);
30606
30690
  });
30607
- const displayElement = computed(() => {
30608
- const element = props.element;
30609
- const item = enhancedItem.value;
30610
- if (!element.display) {
30611
- return true;
30612
- }
30613
- return typeof element.display === "function" ? element.display(item) : processDisplayCondition(element.display, item);
30614
- });
30691
+ const displayElement = computed(
30692
+ () => shouldDisplay(props.element.display, enhancedItem.value)
30693
+ );
30615
30694
  const dynamicAttributes = computed(() => {
30616
30695
  return getDynamicAttributes(props.element.dynamicAttributes, enhancedItem.value);
30617
30696
  });
@@ -30739,15 +30818,21 @@ and ensure you are accounting for this risk.
30739
30818
  var _a, _b;
30740
30819
  return (_b = (_a = props.options.elements) == null ? void 0 : _a.filter((e2) => e2.group === group)) != null ? _b : [];
30741
30820
  };
30742
- const processIsInStock = () => {
30743
- return typeof props.options.isInStock === "function" ? props.options.isInStock(props.product) : processDisplayCondition(props.options.isInStock, props.product);
30821
+ const shouldShowInStock = () => {
30822
+ const raw = props.options.isInStock;
30823
+ if (!raw)
30824
+ return true;
30825
+ const rules = Array.isArray(raw) ? raw : [raw];
30826
+ return rules.every(
30827
+ (rule2) => typeof rule2 === "function" ? rule2(props.product) : processDisplayCondition(rule2, props.product)
30828
+ );
30829
+ };
30830
+ const checkIfIsInStock = () => {
30831
+ isInStock.value = shouldShowInStock();
30744
30832
  };
30745
30833
  onMounted(() => {
30746
30834
  checkIfIsInStock();
30747
30835
  });
30748
- const checkIfIsInStock = () => __async2(this, null, function* () {
30749
- isInStock.value = props.options.isInStock ? yield processIsInStock() : true;
30750
- });
30751
30836
  const handleClick = () => {
30752
30837
  var _a, _b, _c, _d;
30753
30838
  const event = {