@blotoutio/providers-shop-gpt-sdk 1.7.0 → 1.8.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.
Files changed (4) hide show
  1. package/index.cjs.js +131 -25
  2. package/index.js +131 -25
  3. package/index.mjs +131 -25
  4. package/package.json +1 -1
package/index.cjs.js CHANGED
@@ -364,6 +364,50 @@ const usStates = new Map([
364
364
  ]);
365
365
  new Set([...isoCountries.keys(), ...usStates.keys()]);
366
366
 
367
+ const createEnabled = () => ({
368
+ name: 'enabled',
369
+ groupNames: new Set(),
370
+ groupName: '',
371
+ isEnabled: true,
372
+ });
373
+ const createDisabled = () => ({
374
+ name: 'disabled',
375
+ groupNames: new Set(),
376
+ groupName: '',
377
+ isEnabled: false,
378
+ });
379
+ const createABTest = ({ userId }) => {
380
+ const [sample] = userId.split('-');
381
+ const segment = parseInt(sample, 16) % 2;
382
+ return {
383
+ name: 'ab-test',
384
+ groupNames: new Set(['enabled', 'control']),
385
+ groupName: segment == 1 ? 'enabled' : 'control',
386
+ isEnabled: segment == 1,
387
+ };
388
+ };
389
+ const createPreview = ({ preview }) => {
390
+ return {
391
+ name: 'preview',
392
+ groupNames: new Set(['preview']),
393
+ groupName: preview ? 'preview' : '',
394
+ isEnabled: preview !== null && preview !== void 0 ? preview : false,
395
+ };
396
+ };
397
+ const getExperimentName = (mode) => (mode !== null && mode !== void 0 ? mode : 'disabled');
398
+ const createExperiment = (props) => {
399
+ switch (props.name) {
400
+ case 'enabled':
401
+ return createEnabled();
402
+ case 'disabled':
403
+ return createDisabled();
404
+ case 'ab-test':
405
+ return createABTest(props);
406
+ case 'preview':
407
+ return createPreview(props);
408
+ }
409
+ };
410
+
367
411
  const packageName = 'shopGPT';
368
412
  const DEFAULT_MAX_THREAD_AGE = 14;
369
413
  const previewKeyName = 'previewShopGPT';
@@ -530,6 +574,18 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
530
574
  throw new Error(`Failed to save feedback - ${response.status}: ${await response.text()}`);
531
575
  }
532
576
  };
577
+ const fetchCustomPrompts = async (threadId) => {
578
+ const response = await fetchImpl(getURL(`/custom-prompts?threadId=${threadId}`), {
579
+ method: 'GET',
580
+ headers: getHeaders(),
581
+ credentials: 'include',
582
+ });
583
+ if (!response.ok) {
584
+ throw new Error(`Could not fetch custom prompts - ${response.status}: ${await response.text()}`);
585
+ }
586
+ const data = (await response.json());
587
+ return data.customPrompts;
588
+ };
533
589
  return {
534
590
  processQuery,
535
591
  fetchChatHistory,
@@ -538,6 +594,7 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
538
594
  deleteSingleThread,
539
595
  deleteAllThreads,
540
596
  saveFeedback,
597
+ fetchCustomPrompts,
541
598
  };
542
599
  };
543
600
 
@@ -571,11 +628,15 @@ const init = (params) => {
571
628
  // exit if not in top window
572
629
  return;
573
630
  }
574
- const { enabled, devMode, merchantUrl, profiles, productHandles, targetPath, uiMode, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
575
- let shouldShowUI = enabled;
576
- if (!enabled && hasPreviewKey()) {
631
+ const { enabled, mode, devMode, merchantUrl, profiles, productHandles, targetPath, view, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
632
+ const experiment = createExperiment({
633
+ name: getExperimentName(mode),
634
+ userId: params.userId,
635
+ preview: hasPreviewKey(),
636
+ });
637
+ const shouldShowUI = enabled || experiment.isEnabled;
638
+ if (experiment.name === 'preview' && shouldShowUI) {
577
639
  logger.log('Enabling UI in preview mode');
578
- shouldShowUI = true;
579
640
  }
580
641
  if (shouldShowUI) {
581
642
  const uiImplementation = window[registryKey].ui;
@@ -592,7 +653,7 @@ const init = (params) => {
592
653
  storeAPI,
593
654
  shopGPTAPI,
594
655
  devMode,
595
- uiMode,
656
+ view,
596
657
  merchantUrl,
597
658
  profiles,
598
659
  productHandles,
@@ -1012,6 +1073,10 @@ const chatThreadsStyles = i$4 `
1012
1073
  &:hover {
1013
1074
  background: #091627;
1014
1075
  }
1076
+
1077
+ &:disabled {
1078
+ cursor: not-allowed;
1079
+ }
1015
1080
  }
1016
1081
 
1017
1082
  .history {
@@ -1257,6 +1322,7 @@ class ChatThreads extends r$2 {
1257
1322
  <span class="line"></span>
1258
1323
  <button
1259
1324
  class="btn-new-search"
1325
+ ?disabled=${this.isLoading || this.isTyping}
1260
1326
  @click=${() => this.setSelectedThreadId('')}
1261
1327
  >
1262
1328
  New Search
@@ -1265,7 +1331,7 @@ class ChatThreads extends r$2 {
1265
1331
  ${this.merchantUrl
1266
1332
  ? x `<div class="footer">
1267
1333
  Catalog:
1268
- <a href="${this.getDomain()}" target="_blank">
1334
+ <a href="${this.getDomain()}" target="_blank" rel="noopener">
1269
1335
  ${this.getDomain().replace('https://', '')}
1270
1336
  </a>
1271
1337
  </div>`
@@ -2236,6 +2302,7 @@ const chatSectionStyles = i$4 `
2236
2302
  padding: 10px;
2237
2303
  border-radius: 10px;
2238
2304
  border: 1px solid #a3b2c6;
2305
+ text-decoration: none;
2239
2306
 
2240
2307
  color: #4e647f;
2241
2308
  line-height: 21px;
@@ -2987,7 +3054,7 @@ const markdown = (text) => {
2987
3054
  stash[--si] = p4
2988
3055
  ? p2
2989
3056
  ? `<img src="${p4}" alt="${p3}"/>`
2990
- : `<a href="${p4}">${highlight(p3)}</a>`
3057
+ : `<a href="${p4}" rel="noopener">${highlight(p3)}</a>`
2991
3058
  : p6;
2992
3059
  return `${si}\uf8ff`;
2993
3060
  });
@@ -3638,7 +3705,7 @@ class ChatSection extends r$2 {
3638
3705
  </div>
3639
3706
  </div>`
3640
3707
  : E}
3641
- ${this.messages.map((message) => {
3708
+ ${o$1(this.messages, (message) => {
3642
3709
  if (message.sender === 'bot') {
3643
3710
  return this.botMessage(message);
3644
3711
  }
@@ -3660,28 +3727,39 @@ class ChatSection extends r$2 {
3660
3727
  </div>
3661
3728
  `;
3662
3729
  }
3663
- quickPrompts() {
3730
+ renderPrompts() {
3664
3731
  if (this.isLoadingHistory || this.isTyping || this.isLoadingThreads) {
3665
3732
  return E;
3666
3733
  }
3734
+ const isWelcomeMessage = this.messages.length === 1 && this.messages[0].sender === 'bot';
3667
3735
  const prompts = this.messages.length
3668
3736
  ? this.messages[0].welcomePrompts
3669
3737
  : this.prompts
3670
3738
  ? this.prompts.split(',').map((prompt) => prompt.trim())
3671
3739
  : ['Best Sellers'];
3672
- if (!prompts) {
3740
+ const customPrompts = !this.messages.length || isWelcomeMessage ? this.customPrompts : undefined;
3741
+ if (!prompts && !customPrompts) {
3673
3742
  return E;
3674
3743
  }
3675
3744
  return x `
3676
3745
  <div class="prompts btn">
3677
- ${prompts.map((prompt) => x `
3678
- <div
3679
- class="prompt"
3680
- @click=${(e) => this.processMessage(e, prompt)}
3681
- >
3682
- ${prompt}
3683
- </div>
3684
- `)}
3746
+ ${o$1(prompts, (prompt) => {
3747
+ return x `
3748
+ <div
3749
+ class="prompt"
3750
+ @click=${(e) => this.processMessage(e, prompt)}
3751
+ >
3752
+ ${prompt}
3753
+ </div>
3754
+ `;
3755
+ })}
3756
+ ${o$1(customPrompts, ({ prompt, link }) => {
3757
+ return x `
3758
+ <a class="prompt" href=${link} target="_blank" rel="noopener">
3759
+ ${prompt}
3760
+ </a>
3761
+ `;
3762
+ })}
3685
3763
  </div>
3686
3764
  `;
3687
3765
  }
@@ -3928,7 +4006,7 @@ class ChatSection extends r$2 {
3928
4006
  'modal-view': this.viewType === 'modal',
3929
4007
  })}
3930
4008
  >
3931
- ${this.chatWindow()} ${this.quickPrompts()}
4009
+ ${this.chatWindow()} ${this.renderPrompts()}
3932
4010
  <form class="chat-form" @submit=${this.onSubmit}>
3933
4011
  <input
3934
4012
  type="text"
@@ -4011,6 +4089,10 @@ __decorate([
4011
4089
  n({ type: String }),
4012
4090
  __metadata("design:type", Object)
4013
4091
  ], ChatSection.prototype, "prompts", void 0);
4092
+ __decorate([
4093
+ n({ type: Array }),
4094
+ __metadata("design:type", Object)
4095
+ ], ChatSection.prototype, "customPrompts", void 0);
4014
4096
  __decorate([
4015
4097
  n({ type: Boolean }),
4016
4098
  __metadata("design:type", Boolean)
@@ -4106,6 +4188,7 @@ class ShopGPT extends r$2 {
4106
4188
  this.products = [];
4107
4189
  this.messages = [];
4108
4190
  this.chatThreads = new Map();
4191
+ this.customPrompts = [];
4109
4192
  this.loadData = async () => {
4110
4193
  if (!this.shopGPTAPI) {
4111
4194
  return;
@@ -4128,7 +4211,7 @@ class ShopGPT extends r$2 {
4128
4211
  }
4129
4212
  connectedCallback() {
4130
4213
  super.connectedCallback();
4131
- if (!this.uiMode || this.uiMode === 'overlay') {
4214
+ if (!this.view || this.view === 'overlay') {
4132
4215
  if (!this.path) {
4133
4216
  return;
4134
4217
  }
@@ -4149,7 +4232,7 @@ class ShopGPT extends r$2 {
4149
4232
  init() {
4150
4233
  window.addEventListener('edgetag-initialized', this.loadData);
4151
4234
  window.addEventListener('popstate', this.onPopState);
4152
- if (!this.uiMode || this.uiMode === 'overlay') {
4235
+ if (!this.view || this.view === 'overlay') {
4153
4236
  delay(DIALOG_DELAY).then(() => {
4154
4237
  var _a;
4155
4238
  if (document.hidden) {
@@ -4288,10 +4371,25 @@ class ShopGPT extends r$2 {
4288
4371
  this.isLoadingHistory = false;
4289
4372
  }
4290
4373
  }
4374
+ async loadCustomPrompts(threadId) {
4375
+ try {
4376
+ if (!threadId) {
4377
+ this.customPrompts = [];
4378
+ return;
4379
+ }
4380
+ this.customPrompts = await this.shopGPTAPI.fetchCustomPrompts(threadId);
4381
+ }
4382
+ catch (e) {
4383
+ logger.error(e);
4384
+ }
4385
+ }
4291
4386
  async setSelectedThreadId(threadId) {
4292
4387
  this.isFailed = false;
4293
4388
  this.selectedThreadId = threadId;
4294
- await this.loadHistory(threadId);
4389
+ await Promise.all([
4390
+ this.loadHistory(threadId),
4391
+ this.loadCustomPrompts(threadId),
4392
+ ]);
4295
4393
  }
4296
4394
  async createChatThread(payload, loadInitialQuery) {
4297
4395
  try {
@@ -4302,7 +4400,9 @@ class ShopGPT extends r$2 {
4302
4400
  ]);
4303
4401
  this.selectedThreadId = thread.threadId;
4304
4402
  if (loadInitialQuery) {
4305
- await this.loadInitialQuery();
4403
+ await Promise.all([
4404
+ (this.loadInitialQuery(), this.loadCustomPrompts(thread.threadId)),
4405
+ ]);
4306
4406
  }
4307
4407
  }
4308
4408
  catch (e) {
@@ -4395,7 +4495,7 @@ class ShopGPT extends r$2 {
4395
4495
  return this.storeAPI.getSiteCurrency();
4396
4496
  }
4397
4497
  render() {
4398
- if (this.uiMode === 'modal') {
4498
+ if (this.view === 'modal') {
4399
4499
  return this.modalMode();
4400
4500
  }
4401
4501
  return this.overlayMode();
@@ -4444,6 +4544,7 @@ class ShopGPT extends r$2 {
4444
4544
  .profiles=${this.profiles}
4445
4545
  .viewType=${'overlay'}
4446
4546
  .isLoadingThreads=${this.isLoadingThreads}
4547
+ .customPrompts=${this.customPrompts}
4447
4548
  ></chat-section>
4448
4549
  </div>
4449
4550
  </dialog>
@@ -4494,6 +4595,7 @@ class ShopGPT extends r$2 {
4494
4595
  .chatThreads=${this.chatThreads}
4495
4596
  .isLoadingThreads=${this.isLoadingThreads}
4496
4597
  .merchantImage=${this.merchantImage}
4598
+ .customPrompts=${this.customPrompts}
4497
4599
  ></chat-section>
4498
4600
  </div>
4499
4601
  `;
@@ -4544,6 +4646,10 @@ __decorate([
4544
4646
  n({ type: Object }),
4545
4647
  __metadata("design:type", Map)
4546
4648
  ], ShopGPT.prototype, "chatThreads", void 0);
4649
+ __decorate([
4650
+ n({ type: Array }),
4651
+ __metadata("design:type", Array)
4652
+ ], ShopGPT.prototype, "customPrompts", void 0);
4547
4653
  if (!customElements.get('shop-gpt')) {
4548
4654
  customElements.define('shop-gpt', ShopGPT);
4549
4655
  }
@@ -4565,7 +4671,7 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
4565
4671
  shopGPT.merchantUrl = params.merchantUrl;
4566
4672
  shopGPT.profiles = params.profiles;
4567
4673
  shopGPT.productHandles = params.productHandles;
4568
- shopGPT.uiMode = params.uiMode;
4674
+ shopGPT.view = params.view;
4569
4675
  shopGPT.path = params.path;
4570
4676
  shopGPT.brandName = params.brandName;
4571
4677
  shopGPT.quickPrompts = params.quickPrompts;
package/index.js CHANGED
@@ -365,6 +365,50 @@ var ProvidersShopGptSdk = (function () {
365
365
  ]);
366
366
  new Set([...isoCountries.keys(), ...usStates.keys()]);
367
367
 
368
+ const createEnabled = () => ({
369
+ name: 'enabled',
370
+ groupNames: new Set(),
371
+ groupName: '',
372
+ isEnabled: true,
373
+ });
374
+ const createDisabled = () => ({
375
+ name: 'disabled',
376
+ groupNames: new Set(),
377
+ groupName: '',
378
+ isEnabled: false,
379
+ });
380
+ const createABTest = ({ userId }) => {
381
+ const [sample] = userId.split('-');
382
+ const segment = parseInt(sample, 16) % 2;
383
+ return {
384
+ name: 'ab-test',
385
+ groupNames: new Set(['enabled', 'control']),
386
+ groupName: segment == 1 ? 'enabled' : 'control',
387
+ isEnabled: segment == 1,
388
+ };
389
+ };
390
+ const createPreview = ({ preview }) => {
391
+ return {
392
+ name: 'preview',
393
+ groupNames: new Set(['preview']),
394
+ groupName: preview ? 'preview' : '',
395
+ isEnabled: preview !== null && preview !== void 0 ? preview : false,
396
+ };
397
+ };
398
+ const getExperimentName = (mode) => (mode !== null && mode !== void 0 ? mode : 'disabled');
399
+ const createExperiment = (props) => {
400
+ switch (props.name) {
401
+ case 'enabled':
402
+ return createEnabled();
403
+ case 'disabled':
404
+ return createDisabled();
405
+ case 'ab-test':
406
+ return createABTest(props);
407
+ case 'preview':
408
+ return createPreview(props);
409
+ }
410
+ };
411
+
368
412
  const packageName = 'shopGPT';
369
413
  const DEFAULT_MAX_THREAD_AGE = 14;
370
414
  const previewKeyName = 'previewShopGPT';
@@ -531,6 +575,18 @@ var ProvidersShopGptSdk = (function () {
531
575
  throw new Error(`Failed to save feedback - ${response.status}: ${await response.text()}`);
532
576
  }
533
577
  };
578
+ const fetchCustomPrompts = async (threadId) => {
579
+ const response = await fetchImpl(getURL(`/custom-prompts?threadId=${threadId}`), {
580
+ method: 'GET',
581
+ headers: getHeaders(),
582
+ credentials: 'include',
583
+ });
584
+ if (!response.ok) {
585
+ throw new Error(`Could not fetch custom prompts - ${response.status}: ${await response.text()}`);
586
+ }
587
+ const data = (await response.json());
588
+ return data.customPrompts;
589
+ };
534
590
  return {
535
591
  processQuery,
536
592
  fetchChatHistory,
@@ -539,6 +595,7 @@ var ProvidersShopGptSdk = (function () {
539
595
  deleteSingleThread,
540
596
  deleteAllThreads,
541
597
  saveFeedback,
598
+ fetchCustomPrompts,
542
599
  };
543
600
  };
544
601
 
@@ -572,11 +629,15 @@ var ProvidersShopGptSdk = (function () {
572
629
  // exit if not in top window
573
630
  return;
574
631
  }
575
- const { enabled, devMode, merchantUrl, profiles, productHandles, targetPath, uiMode, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
576
- let shouldShowUI = enabled;
577
- if (!enabled && hasPreviewKey()) {
632
+ const { enabled, mode, devMode, merchantUrl, profiles, productHandles, targetPath, view, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
633
+ const experiment = createExperiment({
634
+ name: getExperimentName(mode),
635
+ userId: params.userId,
636
+ preview: hasPreviewKey(),
637
+ });
638
+ const shouldShowUI = enabled || experiment.isEnabled;
639
+ if (experiment.name === 'preview' && shouldShowUI) {
578
640
  logger.log('Enabling UI in preview mode');
579
- shouldShowUI = true;
580
641
  }
581
642
  if (shouldShowUI) {
582
643
  const uiImplementation = window[registryKey].ui;
@@ -593,7 +654,7 @@ var ProvidersShopGptSdk = (function () {
593
654
  storeAPI,
594
655
  shopGPTAPI,
595
656
  devMode,
596
- uiMode,
657
+ view,
597
658
  merchantUrl,
598
659
  profiles,
599
660
  productHandles,
@@ -1013,6 +1074,10 @@ var ProvidersShopGptSdk = (function () {
1013
1074
  &:hover {
1014
1075
  background: #091627;
1015
1076
  }
1077
+
1078
+ &:disabled {
1079
+ cursor: not-allowed;
1080
+ }
1016
1081
  }
1017
1082
 
1018
1083
  .history {
@@ -1258,6 +1323,7 @@ var ProvidersShopGptSdk = (function () {
1258
1323
  <span class="line"></span>
1259
1324
  <button
1260
1325
  class="btn-new-search"
1326
+ ?disabled=${this.isLoading || this.isTyping}
1261
1327
  @click=${() => this.setSelectedThreadId('')}
1262
1328
  >
1263
1329
  New Search
@@ -1266,7 +1332,7 @@ var ProvidersShopGptSdk = (function () {
1266
1332
  ${this.merchantUrl
1267
1333
  ? x `<div class="footer">
1268
1334
  Catalog:
1269
- <a href="${this.getDomain()}" target="_blank">
1335
+ <a href="${this.getDomain()}" target="_blank" rel="noopener">
1270
1336
  ${this.getDomain().replace('https://', '')}
1271
1337
  </a>
1272
1338
  </div>`
@@ -2237,6 +2303,7 @@ var ProvidersShopGptSdk = (function () {
2237
2303
  padding: 10px;
2238
2304
  border-radius: 10px;
2239
2305
  border: 1px solid #a3b2c6;
2306
+ text-decoration: none;
2240
2307
 
2241
2308
  color: #4e647f;
2242
2309
  line-height: 21px;
@@ -2988,7 +3055,7 @@ var ProvidersShopGptSdk = (function () {
2988
3055
  stash[--si] = p4
2989
3056
  ? p2
2990
3057
  ? `<img src="${p4}" alt="${p3}"/>`
2991
- : `<a href="${p4}">${highlight(p3)}</a>`
3058
+ : `<a href="${p4}" rel="noopener">${highlight(p3)}</a>`
2992
3059
  : p6;
2993
3060
  return `${si}\uf8ff`;
2994
3061
  });
@@ -3639,7 +3706,7 @@ ${this.comment ? this.comment : E}</textarea
3639
3706
  </div>
3640
3707
  </div>`
3641
3708
  : E}
3642
- ${this.messages.map((message) => {
3709
+ ${o$1(this.messages, (message) => {
3643
3710
  if (message.sender === 'bot') {
3644
3711
  return this.botMessage(message);
3645
3712
  }
@@ -3661,28 +3728,39 @@ ${this.comment ? this.comment : E}</textarea
3661
3728
  </div>
3662
3729
  `;
3663
3730
  }
3664
- quickPrompts() {
3731
+ renderPrompts() {
3665
3732
  if (this.isLoadingHistory || this.isTyping || this.isLoadingThreads) {
3666
3733
  return E;
3667
3734
  }
3735
+ const isWelcomeMessage = this.messages.length === 1 && this.messages[0].sender === 'bot';
3668
3736
  const prompts = this.messages.length
3669
3737
  ? this.messages[0].welcomePrompts
3670
3738
  : this.prompts
3671
3739
  ? this.prompts.split(',').map((prompt) => prompt.trim())
3672
3740
  : ['Best Sellers'];
3673
- if (!prompts) {
3741
+ const customPrompts = !this.messages.length || isWelcomeMessage ? this.customPrompts : undefined;
3742
+ if (!prompts && !customPrompts) {
3674
3743
  return E;
3675
3744
  }
3676
3745
  return x `
3677
3746
  <div class="prompts btn">
3678
- ${prompts.map((prompt) => x `
3679
- <div
3680
- class="prompt"
3681
- @click=${(e) => this.processMessage(e, prompt)}
3682
- >
3683
- ${prompt}
3684
- </div>
3685
- `)}
3747
+ ${o$1(prompts, (prompt) => {
3748
+ return x `
3749
+ <div
3750
+ class="prompt"
3751
+ @click=${(e) => this.processMessage(e, prompt)}
3752
+ >
3753
+ ${prompt}
3754
+ </div>
3755
+ `;
3756
+ })}
3757
+ ${o$1(customPrompts, ({ prompt, link }) => {
3758
+ return x `
3759
+ <a class="prompt" href=${link} target="_blank" rel="noopener">
3760
+ ${prompt}
3761
+ </a>
3762
+ `;
3763
+ })}
3686
3764
  </div>
3687
3765
  `;
3688
3766
  }
@@ -3929,7 +4007,7 @@ ${this.comment ? this.comment : E}</textarea
3929
4007
  'modal-view': this.viewType === 'modal',
3930
4008
  })}
3931
4009
  >
3932
- ${this.chatWindow()} ${this.quickPrompts()}
4010
+ ${this.chatWindow()} ${this.renderPrompts()}
3933
4011
  <form class="chat-form" @submit=${this.onSubmit}>
3934
4012
  <input
3935
4013
  type="text"
@@ -4012,6 +4090,10 @@ ${this.comment ? this.comment : E}</textarea
4012
4090
  n({ type: String }),
4013
4091
  __metadata("design:type", Object)
4014
4092
  ], ChatSection.prototype, "prompts", void 0);
4093
+ __decorate([
4094
+ n({ type: Array }),
4095
+ __metadata("design:type", Object)
4096
+ ], ChatSection.prototype, "customPrompts", void 0);
4015
4097
  __decorate([
4016
4098
  n({ type: Boolean }),
4017
4099
  __metadata("design:type", Boolean)
@@ -4107,6 +4189,7 @@ ${this.comment ? this.comment : E}</textarea
4107
4189
  this.products = [];
4108
4190
  this.messages = [];
4109
4191
  this.chatThreads = new Map();
4192
+ this.customPrompts = [];
4110
4193
  this.loadData = async () => {
4111
4194
  if (!this.shopGPTAPI) {
4112
4195
  return;
@@ -4129,7 +4212,7 @@ ${this.comment ? this.comment : E}</textarea
4129
4212
  }
4130
4213
  connectedCallback() {
4131
4214
  super.connectedCallback();
4132
- if (!this.uiMode || this.uiMode === 'overlay') {
4215
+ if (!this.view || this.view === 'overlay') {
4133
4216
  if (!this.path) {
4134
4217
  return;
4135
4218
  }
@@ -4150,7 +4233,7 @@ ${this.comment ? this.comment : E}</textarea
4150
4233
  init() {
4151
4234
  window.addEventListener('edgetag-initialized', this.loadData);
4152
4235
  window.addEventListener('popstate', this.onPopState);
4153
- if (!this.uiMode || this.uiMode === 'overlay') {
4236
+ if (!this.view || this.view === 'overlay') {
4154
4237
  delay(DIALOG_DELAY).then(() => {
4155
4238
  var _a;
4156
4239
  if (document.hidden) {
@@ -4289,10 +4372,25 @@ ${this.comment ? this.comment : E}</textarea
4289
4372
  this.isLoadingHistory = false;
4290
4373
  }
4291
4374
  }
4375
+ async loadCustomPrompts(threadId) {
4376
+ try {
4377
+ if (!threadId) {
4378
+ this.customPrompts = [];
4379
+ return;
4380
+ }
4381
+ this.customPrompts = await this.shopGPTAPI.fetchCustomPrompts(threadId);
4382
+ }
4383
+ catch (e) {
4384
+ logger.error(e);
4385
+ }
4386
+ }
4292
4387
  async setSelectedThreadId(threadId) {
4293
4388
  this.isFailed = false;
4294
4389
  this.selectedThreadId = threadId;
4295
- await this.loadHistory(threadId);
4390
+ await Promise.all([
4391
+ this.loadHistory(threadId),
4392
+ this.loadCustomPrompts(threadId),
4393
+ ]);
4296
4394
  }
4297
4395
  async createChatThread(payload, loadInitialQuery) {
4298
4396
  try {
@@ -4303,7 +4401,9 @@ ${this.comment ? this.comment : E}</textarea
4303
4401
  ]);
4304
4402
  this.selectedThreadId = thread.threadId;
4305
4403
  if (loadInitialQuery) {
4306
- await this.loadInitialQuery();
4404
+ await Promise.all([
4405
+ (this.loadInitialQuery(), this.loadCustomPrompts(thread.threadId)),
4406
+ ]);
4307
4407
  }
4308
4408
  }
4309
4409
  catch (e) {
@@ -4396,7 +4496,7 @@ ${this.comment ? this.comment : E}</textarea
4396
4496
  return this.storeAPI.getSiteCurrency();
4397
4497
  }
4398
4498
  render() {
4399
- if (this.uiMode === 'modal') {
4499
+ if (this.view === 'modal') {
4400
4500
  return this.modalMode();
4401
4501
  }
4402
4502
  return this.overlayMode();
@@ -4445,6 +4545,7 @@ ${this.comment ? this.comment : E}</textarea
4445
4545
  .profiles=${this.profiles}
4446
4546
  .viewType=${'overlay'}
4447
4547
  .isLoadingThreads=${this.isLoadingThreads}
4548
+ .customPrompts=${this.customPrompts}
4448
4549
  ></chat-section>
4449
4550
  </div>
4450
4551
  </dialog>
@@ -4495,6 +4596,7 @@ ${this.comment ? this.comment : E}</textarea
4495
4596
  .chatThreads=${this.chatThreads}
4496
4597
  .isLoadingThreads=${this.isLoadingThreads}
4497
4598
  .merchantImage=${this.merchantImage}
4599
+ .customPrompts=${this.customPrompts}
4498
4600
  ></chat-section>
4499
4601
  </div>
4500
4602
  `;
@@ -4545,6 +4647,10 @@ ${this.comment ? this.comment : E}</textarea
4545
4647
  n({ type: Object }),
4546
4648
  __metadata("design:type", Map)
4547
4649
  ], ShopGPT.prototype, "chatThreads", void 0);
4650
+ __decorate([
4651
+ n({ type: Array }),
4652
+ __metadata("design:type", Array)
4653
+ ], ShopGPT.prototype, "customPrompts", void 0);
4548
4654
  if (!customElements.get('shop-gpt')) {
4549
4655
  customElements.define('shop-gpt', ShopGPT);
4550
4656
  }
@@ -4566,7 +4672,7 @@ ${this.comment ? this.comment : E}</textarea
4566
4672
  shopGPT.merchantUrl = params.merchantUrl;
4567
4673
  shopGPT.profiles = params.profiles;
4568
4674
  shopGPT.productHandles = params.productHandles;
4569
- shopGPT.uiMode = params.uiMode;
4675
+ shopGPT.view = params.view;
4570
4676
  shopGPT.path = params.path;
4571
4677
  shopGPT.brandName = params.brandName;
4572
4678
  shopGPT.quickPrompts = params.quickPrompts;
package/index.mjs CHANGED
@@ -362,6 +362,50 @@ const usStates = new Map([
362
362
  ]);
363
363
  new Set([...isoCountries.keys(), ...usStates.keys()]);
364
364
 
365
+ const createEnabled = () => ({
366
+ name: 'enabled',
367
+ groupNames: new Set(),
368
+ groupName: '',
369
+ isEnabled: true,
370
+ });
371
+ const createDisabled = () => ({
372
+ name: 'disabled',
373
+ groupNames: new Set(),
374
+ groupName: '',
375
+ isEnabled: false,
376
+ });
377
+ const createABTest = ({ userId }) => {
378
+ const [sample] = userId.split('-');
379
+ const segment = parseInt(sample, 16) % 2;
380
+ return {
381
+ name: 'ab-test',
382
+ groupNames: new Set(['enabled', 'control']),
383
+ groupName: segment == 1 ? 'enabled' : 'control',
384
+ isEnabled: segment == 1,
385
+ };
386
+ };
387
+ const createPreview = ({ preview }) => {
388
+ return {
389
+ name: 'preview',
390
+ groupNames: new Set(['preview']),
391
+ groupName: preview ? 'preview' : '',
392
+ isEnabled: preview !== null && preview !== void 0 ? preview : false,
393
+ };
394
+ };
395
+ const getExperimentName = (mode) => (mode !== null && mode !== void 0 ? mode : 'disabled');
396
+ const createExperiment = (props) => {
397
+ switch (props.name) {
398
+ case 'enabled':
399
+ return createEnabled();
400
+ case 'disabled':
401
+ return createDisabled();
402
+ case 'ab-test':
403
+ return createABTest(props);
404
+ case 'preview':
405
+ return createPreview(props);
406
+ }
407
+ };
408
+
365
409
  const packageName = 'shopGPT';
366
410
  const DEFAULT_MAX_THREAD_AGE = 14;
367
411
  const previewKeyName = 'previewShopGPT';
@@ -528,6 +572,18 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
528
572
  throw new Error(`Failed to save feedback - ${response.status}: ${await response.text()}`);
529
573
  }
530
574
  };
575
+ const fetchCustomPrompts = async (threadId) => {
576
+ const response = await fetchImpl(getURL(`/custom-prompts?threadId=${threadId}`), {
577
+ method: 'GET',
578
+ headers: getHeaders(),
579
+ credentials: 'include',
580
+ });
581
+ if (!response.ok) {
582
+ throw new Error(`Could not fetch custom prompts - ${response.status}: ${await response.text()}`);
583
+ }
584
+ const data = (await response.json());
585
+ return data.customPrompts;
586
+ };
531
587
  return {
532
588
  processQuery,
533
589
  fetchChatHistory,
@@ -536,6 +592,7 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
536
592
  deleteSingleThread,
537
593
  deleteAllThreads,
538
594
  saveFeedback,
595
+ fetchCustomPrompts,
539
596
  };
540
597
  };
541
598
 
@@ -569,11 +626,15 @@ const init = (params) => {
569
626
  // exit if not in top window
570
627
  return;
571
628
  }
572
- const { enabled, devMode, merchantUrl, profiles, productHandles, targetPath, uiMode, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
573
- let shouldShowUI = enabled;
574
- if (!enabled && hasPreviewKey()) {
629
+ const { enabled, mode, devMode, merchantUrl, profiles, productHandles, targetPath, view, brandName, quickPrompts, merchantImage, latestThreadLoad, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
630
+ const experiment = createExperiment({
631
+ name: getExperimentName(mode),
632
+ userId: params.userId,
633
+ preview: hasPreviewKey(),
634
+ });
635
+ const shouldShowUI = enabled || experiment.isEnabled;
636
+ if (experiment.name === 'preview' && shouldShowUI) {
575
637
  logger.log('Enabling UI in preview mode');
576
- shouldShowUI = true;
577
638
  }
578
639
  if (shouldShowUI) {
579
640
  const uiImplementation = window[registryKey].ui;
@@ -590,7 +651,7 @@ const init = (params) => {
590
651
  storeAPI,
591
652
  shopGPTAPI,
592
653
  devMode,
593
- uiMode,
654
+ view,
594
655
  merchantUrl,
595
656
  profiles,
596
657
  productHandles,
@@ -1010,6 +1071,10 @@ const chatThreadsStyles = i$4 `
1010
1071
  &:hover {
1011
1072
  background: #091627;
1012
1073
  }
1074
+
1075
+ &:disabled {
1076
+ cursor: not-allowed;
1077
+ }
1013
1078
  }
1014
1079
 
1015
1080
  .history {
@@ -1255,6 +1320,7 @@ class ChatThreads extends r$2 {
1255
1320
  <span class="line"></span>
1256
1321
  <button
1257
1322
  class="btn-new-search"
1323
+ ?disabled=${this.isLoading || this.isTyping}
1258
1324
  @click=${() => this.setSelectedThreadId('')}
1259
1325
  >
1260
1326
  New Search
@@ -1263,7 +1329,7 @@ class ChatThreads extends r$2 {
1263
1329
  ${this.merchantUrl
1264
1330
  ? x `<div class="footer">
1265
1331
  Catalog:
1266
- <a href="${this.getDomain()}" target="_blank">
1332
+ <a href="${this.getDomain()}" target="_blank" rel="noopener">
1267
1333
  ${this.getDomain().replace('https://', '')}
1268
1334
  </a>
1269
1335
  </div>`
@@ -2234,6 +2300,7 @@ const chatSectionStyles = i$4 `
2234
2300
  padding: 10px;
2235
2301
  border-radius: 10px;
2236
2302
  border: 1px solid #a3b2c6;
2303
+ text-decoration: none;
2237
2304
 
2238
2305
  color: #4e647f;
2239
2306
  line-height: 21px;
@@ -2985,7 +3052,7 @@ const markdown = (text) => {
2985
3052
  stash[--si] = p4
2986
3053
  ? p2
2987
3054
  ? `<img src="${p4}" alt="${p3}"/>`
2988
- : `<a href="${p4}">${highlight(p3)}</a>`
3055
+ : `<a href="${p4}" rel="noopener">${highlight(p3)}</a>`
2989
3056
  : p6;
2990
3057
  return `${si}\uf8ff`;
2991
3058
  });
@@ -3636,7 +3703,7 @@ class ChatSection extends r$2 {
3636
3703
  </div>
3637
3704
  </div>`
3638
3705
  : E}
3639
- ${this.messages.map((message) => {
3706
+ ${o$1(this.messages, (message) => {
3640
3707
  if (message.sender === 'bot') {
3641
3708
  return this.botMessage(message);
3642
3709
  }
@@ -3658,28 +3725,39 @@ class ChatSection extends r$2 {
3658
3725
  </div>
3659
3726
  `;
3660
3727
  }
3661
- quickPrompts() {
3728
+ renderPrompts() {
3662
3729
  if (this.isLoadingHistory || this.isTyping || this.isLoadingThreads) {
3663
3730
  return E;
3664
3731
  }
3732
+ const isWelcomeMessage = this.messages.length === 1 && this.messages[0].sender === 'bot';
3665
3733
  const prompts = this.messages.length
3666
3734
  ? this.messages[0].welcomePrompts
3667
3735
  : this.prompts
3668
3736
  ? this.prompts.split(',').map((prompt) => prompt.trim())
3669
3737
  : ['Best Sellers'];
3670
- if (!prompts) {
3738
+ const customPrompts = !this.messages.length || isWelcomeMessage ? this.customPrompts : undefined;
3739
+ if (!prompts && !customPrompts) {
3671
3740
  return E;
3672
3741
  }
3673
3742
  return x `
3674
3743
  <div class="prompts btn">
3675
- ${prompts.map((prompt) => x `
3676
- <div
3677
- class="prompt"
3678
- @click=${(e) => this.processMessage(e, prompt)}
3679
- >
3680
- ${prompt}
3681
- </div>
3682
- `)}
3744
+ ${o$1(prompts, (prompt) => {
3745
+ return x `
3746
+ <div
3747
+ class="prompt"
3748
+ @click=${(e) => this.processMessage(e, prompt)}
3749
+ >
3750
+ ${prompt}
3751
+ </div>
3752
+ `;
3753
+ })}
3754
+ ${o$1(customPrompts, ({ prompt, link }) => {
3755
+ return x `
3756
+ <a class="prompt" href=${link} target="_blank" rel="noopener">
3757
+ ${prompt}
3758
+ </a>
3759
+ `;
3760
+ })}
3683
3761
  </div>
3684
3762
  `;
3685
3763
  }
@@ -3926,7 +4004,7 @@ class ChatSection extends r$2 {
3926
4004
  'modal-view': this.viewType === 'modal',
3927
4005
  })}
3928
4006
  >
3929
- ${this.chatWindow()} ${this.quickPrompts()}
4007
+ ${this.chatWindow()} ${this.renderPrompts()}
3930
4008
  <form class="chat-form" @submit=${this.onSubmit}>
3931
4009
  <input
3932
4010
  type="text"
@@ -4009,6 +4087,10 @@ __decorate([
4009
4087
  n({ type: String }),
4010
4088
  __metadata("design:type", Object)
4011
4089
  ], ChatSection.prototype, "prompts", void 0);
4090
+ __decorate([
4091
+ n({ type: Array }),
4092
+ __metadata("design:type", Object)
4093
+ ], ChatSection.prototype, "customPrompts", void 0);
4012
4094
  __decorate([
4013
4095
  n({ type: Boolean }),
4014
4096
  __metadata("design:type", Boolean)
@@ -4104,6 +4186,7 @@ class ShopGPT extends r$2 {
4104
4186
  this.products = [];
4105
4187
  this.messages = [];
4106
4188
  this.chatThreads = new Map();
4189
+ this.customPrompts = [];
4107
4190
  this.loadData = async () => {
4108
4191
  if (!this.shopGPTAPI) {
4109
4192
  return;
@@ -4126,7 +4209,7 @@ class ShopGPT extends r$2 {
4126
4209
  }
4127
4210
  connectedCallback() {
4128
4211
  super.connectedCallback();
4129
- if (!this.uiMode || this.uiMode === 'overlay') {
4212
+ if (!this.view || this.view === 'overlay') {
4130
4213
  if (!this.path) {
4131
4214
  return;
4132
4215
  }
@@ -4147,7 +4230,7 @@ class ShopGPT extends r$2 {
4147
4230
  init() {
4148
4231
  window.addEventListener('edgetag-initialized', this.loadData);
4149
4232
  window.addEventListener('popstate', this.onPopState);
4150
- if (!this.uiMode || this.uiMode === 'overlay') {
4233
+ if (!this.view || this.view === 'overlay') {
4151
4234
  delay(DIALOG_DELAY).then(() => {
4152
4235
  var _a;
4153
4236
  if (document.hidden) {
@@ -4286,10 +4369,25 @@ class ShopGPT extends r$2 {
4286
4369
  this.isLoadingHistory = false;
4287
4370
  }
4288
4371
  }
4372
+ async loadCustomPrompts(threadId) {
4373
+ try {
4374
+ if (!threadId) {
4375
+ this.customPrompts = [];
4376
+ return;
4377
+ }
4378
+ this.customPrompts = await this.shopGPTAPI.fetchCustomPrompts(threadId);
4379
+ }
4380
+ catch (e) {
4381
+ logger.error(e);
4382
+ }
4383
+ }
4289
4384
  async setSelectedThreadId(threadId) {
4290
4385
  this.isFailed = false;
4291
4386
  this.selectedThreadId = threadId;
4292
- await this.loadHistory(threadId);
4387
+ await Promise.all([
4388
+ this.loadHistory(threadId),
4389
+ this.loadCustomPrompts(threadId),
4390
+ ]);
4293
4391
  }
4294
4392
  async createChatThread(payload, loadInitialQuery) {
4295
4393
  try {
@@ -4300,7 +4398,9 @@ class ShopGPT extends r$2 {
4300
4398
  ]);
4301
4399
  this.selectedThreadId = thread.threadId;
4302
4400
  if (loadInitialQuery) {
4303
- await this.loadInitialQuery();
4401
+ await Promise.all([
4402
+ (this.loadInitialQuery(), this.loadCustomPrompts(thread.threadId)),
4403
+ ]);
4304
4404
  }
4305
4405
  }
4306
4406
  catch (e) {
@@ -4393,7 +4493,7 @@ class ShopGPT extends r$2 {
4393
4493
  return this.storeAPI.getSiteCurrency();
4394
4494
  }
4395
4495
  render() {
4396
- if (this.uiMode === 'modal') {
4496
+ if (this.view === 'modal') {
4397
4497
  return this.modalMode();
4398
4498
  }
4399
4499
  return this.overlayMode();
@@ -4442,6 +4542,7 @@ class ShopGPT extends r$2 {
4442
4542
  .profiles=${this.profiles}
4443
4543
  .viewType=${'overlay'}
4444
4544
  .isLoadingThreads=${this.isLoadingThreads}
4545
+ .customPrompts=${this.customPrompts}
4445
4546
  ></chat-section>
4446
4547
  </div>
4447
4548
  </dialog>
@@ -4492,6 +4593,7 @@ class ShopGPT extends r$2 {
4492
4593
  .chatThreads=${this.chatThreads}
4493
4594
  .isLoadingThreads=${this.isLoadingThreads}
4494
4595
  .merchantImage=${this.merchantImage}
4596
+ .customPrompts=${this.customPrompts}
4495
4597
  ></chat-section>
4496
4598
  </div>
4497
4599
  `;
@@ -4542,6 +4644,10 @@ __decorate([
4542
4644
  n({ type: Object }),
4543
4645
  __metadata("design:type", Map)
4544
4646
  ], ShopGPT.prototype, "chatThreads", void 0);
4647
+ __decorate([
4648
+ n({ type: Array }),
4649
+ __metadata("design:type", Array)
4650
+ ], ShopGPT.prototype, "customPrompts", void 0);
4545
4651
  if (!customElements.get('shop-gpt')) {
4546
4652
  customElements.define('shop-gpt', ShopGPT);
4547
4653
  }
@@ -4563,7 +4669,7 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
4563
4669
  shopGPT.merchantUrl = params.merchantUrl;
4564
4670
  shopGPT.profiles = params.profiles;
4565
4671
  shopGPT.productHandles = params.productHandles;
4566
- shopGPT.uiMode = params.uiMode;
4672
+ shopGPT.view = params.view;
4567
4673
  shopGPT.path = params.path;
4568
4674
  shopGPT.brandName = params.brandName;
4569
4675
  shopGPT.quickPrompts = params.quickPrompts;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-shop-gpt-sdk",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Shop GPT SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",