@kudoai/chatgpt.js 3.8.4 → 3.9.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.
package/LICENSE.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  # MIT License
28
28
 
29
- **Copyright © 2023–2025 [KudoAI](https://github.com/KudoAI) & [contributors](.#-contributors)**
29
+ **Copyright © 2023–2026 [KudoAI](https://github.com/KudoAI) & [contributors](.#-contributors)**
30
30
 
31
31
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
32
32
 
package/README.md CHANGED
@@ -45,31 +45,25 @@
45
45
 
46
46
  <div id="shields" align="center">
47
47
 
48
- <a href="https://github.com/KudoAI/chatgpt.js/stargazers" target="_blank" rel="noopener">
49
- <img src="https://img.shields.io/github/stars/KudoAI/chatgpt.js?label=Stars&color=af68ff&logo=github&logoColor=white&labelColor=464646&style=for-the-badge"></a>
50
48
  <a href="https://github.com/KudoAI/chatgpt.js/blob/main/LICENSE.md" target="_blank" rel="noopener">
51
- <img src="https://img.shields.io/badge/License-MIT-fc4f2d.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
49
+ <img src="https://img.shields.io/badge/License-MIT-orange.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
52
50
  <a href="https://www.npmjs.com/package/@kudoai/chatgpt.js/v/latest" target="_blank" rel="noopener">
53
51
  <img src="https://img.shields.io/npm/v/%40kudoai%2Fchatgpt.js?logo=npm&logoColor=white&labelColor=464646&color=blue&style=for-the-badge&label=Latest+Release"></a>
54
- <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.4/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
- <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.4&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
52
+ <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.9.0/dist/chatgpt.min.js" target="_blank" rel="noopener">
53
+ <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.9.0&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
56
54
  <a href="https://www.codefactor.io/repository/github/kudoai/chatgpt.js" target="_blank" rel="noopener">
57
55
  <img src="https://img.shields.io/codefactor/grade/github/kudoai/chatgpt.js?label=Code+Quality&logo=codefactor&logoColor=white&labelColor=464646&color=1acc6c&style=for-the-badge"></a>
58
56
  <a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js" target="_blank" rel="noopener">
59
57
  <img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fsonarcloud.io%2Fapi%2Fmeasures%2Fcomponent%3Fcomponent%3Dkudoai_chatgpt.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold"></a>
60
58
  <a href="https://github.com/sindresorhus/awesome-chatgpt#javascript" target="_blank" rel="noopener">
61
- <img src="https://img.shields.io/badge/Mentioned_in-Awesome-cca8c4?logo=awesomelists&logoColor=white&labelColor=464646&style=for-the-badge"></a>
62
- <a href="https://opentools.ai/tools/chatgptjs">
63
- <img alt="[Voted Top Tool on OpenTools.ai]" src="https://img.shields.io/badge/Voted_Top_Tool-OpenTools.ai-f43f5e?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTAiIGhlaWdodD0iMzUwIiBzdHlsZT0ic2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbjt0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247aW1hZ2UtcmVuZGVyaW5nOm9wdGltaXplUXVhbGl0eTtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZCI+PHBhdGggZmlsbD0iI2ZlZmZmZSIgZD0iTTM2LjUgMzAuNWM5My44MzItMSAxODcuODMyLTEuMzMzIDI4Mi0xIC4xNjcgOTQuMDAxIDAgMTg4LjAwMS0uNSAyODJsLTc4LTc4Yy0uNS00MS42NjUtLjY2Ny04My4zMzItLjUtMTI1LTQxLjY2OC4xNjctODMuMzM1IDAtMTI1LS41YTg1MzcuOTUgODUzNy45NSAwIDAgMC03OC03Ny41WiIgc3R5bGU9Im9wYWNpdHk6Ljk4NCIvPjxwYXRoIGZpbGw9IiNmZWZmZmUiIGQ9Ik0yOS41IDM1LjVhMjkyNC4wMjQgMjkyNC4wMjQgMCAwIDEgNzguNSA3OWMuNSA0MS42NjUuNjY3IDgzLjMzMi41IDEyNSA0Mi4wMDEtLjE2NyA4NC4wMDEgMCAxMjYgLjVhODQzMy4xNiA4NDMzLjE2IDAgMCAxIDc3IDc3LjVjLTkzLjk5OCAxLTE4Ny45OTggMS4zMzMtMjgyIDF2LTI4M1oiIHN0eWxlPSJvcGFjaXR5Oi45ODEiLz48L3N2Zz4=&logoColor=white&labelColor=464646&style=for-the-badge"></a>
64
- <a href="https://www.producthunt.com/posts/chatgpt-js" target="_blank" rel="noopener">
65
- <img src="https://img.shields.io/badge/Featured_on-Product_Hunt-ff6154?logo=producthunt&logoColor=white&labelColor=464646&style=for-the-badge"></a>
66
- <a href="https://trendshift.io/repositories/2896" target="_blank" rel="noopener">
67
- <img src="https://img.shields.io/badge/Trended-Top_20_Repository-869da0?logo=github&logoColor=white&labelColor=464646&style=for-the-badge"></a>
59
+ <img src="https://img.shields.io/badge/Mentioned_in-Awesome-af68ff?logo=awesomelists&logoColor=white&labelColor=464646&style=for-the-badge"></a>
68
60
  <a href="#">
69
61
  <img src="https://img.shields.io/badge/jsDelivr_Requests-2,000,000+-2bbbd8.svg?logo=jsdelivr&logoColor=white&labelColor=464646&style=for-the-badge"></a>
70
62
 
71
63
  </div>
72
64
 
65
+ <br><br>
66
+
73
67
  <img height=8px width="100%" src="https://assets.chatgptjs.org/images/separators/gradient-aqua.png?v=e638eac">
74
68
 
75
69
  <div id="intro">
@@ -120,7 +114,7 @@
120
114
 
121
115
  ```js
122
116
  (async () => {
123
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
117
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.9.0/dist/chatgpt.min.js');
124
118
  // Your code here...
125
119
  })();
126
120
  ```
@@ -129,7 +123,7 @@
129
123
 
130
124
  ```js
131
125
  var xhr = new XMLHttpRequest();
132
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
126
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.9.0/dist/chatgpt.min.js');
133
127
  xhr.onload = function () {
134
128
  if (xhr.status === 200) {
135
129
  var chatgptJS = document.createElement('script');
@@ -152,7 +146,7 @@ function yourCode() {
152
146
 
153
147
  ```js
154
148
  ...
155
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js
149
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.9.0/dist/chatgpt.min.js
156
150
  // ==/UserScript==
157
151
 
158
152
  // Your code here...
@@ -222,7 +216,7 @@ chatgpt.get('reply', 'last');
222
216
 
223
217
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
224
218
 
225
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
219
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.9.0/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
226
220
 
227
221
  <img height=8px width="100%" src="https://assets.chatgptjs.org/images/separators/gradient-aqua.png?v=e638eac">
228
222
 
@@ -419,6 +413,8 @@ This library exists thanks to code, translations, issues & ideas from the follow
419
413
  <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-handling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
420
414
  <a href="https://github.com/ahnupeng" target="_blank" rel="noopener">
421
415
  <img title="@ahnupeng" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5319112?first-contrib=2025.9.4-suggested-allow-edit-slider-vals&h=47&w=47&mask=circle&maxage=7d"></a>
416
+ <a href="https://github.com/geghamyan" target="_blank" rel="noopener">
417
+ <img title="@geghamyan" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/12634915?first-contrib=2026.1.2-fixed-console-err-bug&h=47&w=47&mask=circle&maxage=7d"></a>
422
418
  <a href="https://github.com/dependabot" target="_blank" rel="noopener">
423
419
  <img title="Dependabot" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=47&w=47&mask=circle&maxage=7d"></a>
424
420
  <a href="https://chatgpt.com" target="_blank" rel="noopener">
@@ -482,7 +478,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
482
478
  <div align="center">
483
479
 
484
480
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
485
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md) /
481
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.9.0/docs/USERGUIDE.md) /
486
482
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
487
483
  [Back to top ↑](#top)
488
484
 
package/chatgpt.js CHANGED
@@ -1,12 +1,8 @@
1
- // © 2023–2025 KudoAI & contributors under the MIT license.
1
+ // © 2023–2026 KudoAI & contributors under the MIT license.
2
2
  // Source: https://github.com/KudoAI/chatgpt.js
3
3
  // User guide: https://chatgptjs.org/userguide
4
4
  // Latest minified release: https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js/chatgpt.min.js
5
5
 
6
- // Init feedback props
7
- localStorage.alertQueue = JSON.stringify([])
8
- localStorage.notifyProps = JSON.stringify({ queue: { topRight: [], bottomRight: [], bottomLeft: [], topLeft: [] }})
9
-
10
6
  // Define chatgpt API
11
7
  const chatgpt = {
12
8
 
@@ -25,21 +21,21 @@ const chatgpt = {
25
21
  selectors: {
26
22
  btns: {
27
23
  continue: 'button:has(svg[class*=rotate] > path[d^="M4.47189"])',
28
- createImage: 'button[data-testid=composer-create-image]',
29
- deepResearch: 'button[data-testid=composer-deep-research]',
24
+ createImage: 'button[data-testid=composer-button-create-image]',
30
25
  login: 'button[data-testid*=login]',
31
26
  newChat: 'a[href="/"]:has(svg),' // Pencil button (when logged in)
32
27
  + 'button:has([d^="M3.06957"])', // Cycle Arrows button (in temp chat logged out)
33
28
  regen: 'button[data-testid*=regenerate],' // oval button in place of chatbar on errors
34
- // 'Try Again' entry of model selector below msg
35
- + 'div[role=menuitem] div:has(svg):has(path[d^="M3.06957"])',
36
- scroll: 'button:has(> svg > path[d^="M12 21C11.7348"])',
29
+ + 'button:has(use[href$="sprites-core-k5zux585.svg#ec66f0"])', // 'Try again...' button below msg
30
+ scroll: 'button:has(use[href$="sprites-core-k5zux585.svg#ac89a7"])',
37
31
  search: 'button[data-testid=composer-button-search]',
38
- reason: 'button[data-testid=composer-button-reason]',
39
32
  send: 'button[data-testid=send-button]',
40
- sidebar: 'div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]',
41
- stop: 'div:has(> svg > path[d^="M10 2.08496C14.3713"])',
42
- upload: 'button:has(> svg > path[d^="M12 3C12.5523"])',
33
+ sidebar: 'div[style*=-sidebar-width] button[data-testid=close-sidebar-button],'
34
+ + 'div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]',
35
+ signup: 'button[data-testid=signup-button]',
36
+ stop: 'button[data-testid=stop-button]',
37
+ upload: 'div[data-testid=composer-action-file-upload],' // tall chatbar
38
+ + 'button#composer-plus-btn', // short chatbar
43
39
  voice: 'button[data-testid*=composer-speech-button]'
44
40
  },
45
41
  chatDivs: {
@@ -338,7 +334,7 @@ const chatgpt = {
338
334
  modalContainer.append(modal) ; document.body.append(modalContainer)
339
335
 
340
336
  // Enqueue alert
341
- let alertQueue = JSON.parse(localStorage.alertQueue)
337
+ let alertQueue = JSON.parse(localStorage.alertQueue ??= JSON.stringify([]))
342
338
  alertQueue.push(modalContainer.id)
343
339
  localStorage.alertQueue = JSON.stringify(alertQueue)
344
340
 
@@ -371,7 +367,7 @@ const chatgpt = {
371
367
  document.removeEventListener('keydown', handlers.dismiss.key) // prevent memory leaks
372
368
 
373
369
  // Check for pending alerts in queue
374
- if (alertQueue.length > 0) {
370
+ if (alertQueue.length) {
375
371
  const nextAlert = document.getElementById(alertQueue[0])
376
372
  setTimeout(() => {
377
373
  nextAlert.style.display = ''
@@ -409,7 +405,7 @@ const chatgpt = {
409
405
  }
410
406
  scheduleRefreshes(interval)
411
407
  }, (interval + randomDelay) * 1000)
412
- };
408
+ }
413
409
  scheduleRefreshes( interval ? parseInt(interval, 10) : 30 )
414
410
  console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh activated`)
415
411
 
@@ -432,7 +428,7 @@ const chatgpt = {
432
428
  const now = new Date()
433
429
  const hours = now.getHours() % 12 || 12 // convert to 12h format
434
430
  let minutes = now.getMinutes(), seconds = now.getSeconds()
435
- if (minutes < 10) minutes = '0' + minutes; if (seconds < 10) seconds = '0' + seconds
431
+ if (minutes < 10) minutes = '0' + minutes ; if (seconds < 10) seconds = '0' + seconds
436
432
  const meridiem = now.getHours() < 12 ? 'AM' : 'PM'
437
433
  return `${hours}:${minutes}:${seconds} ${meridiem}`
438
434
  },
@@ -574,7 +570,7 @@ const chatgpt = {
574
570
 
575
571
  async refactor(code, objective) {
576
572
  if (!code) return console.error('Code (1st) argument not supplied. Pass some code!')
577
- for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
573
+ for (let i = 0 ; i < arguments.length ; i++) if (typeof arguments[i] != 'string')
578
574
  return console.error(`Argument ${ i + 1 } must be a string.`)
579
575
  chatgpt.send(`Refactor the following code for ${ objective || 'brevity' }:\n\n${code}`)
580
576
  console.info('Refactoring code...')
@@ -603,7 +599,7 @@ const chatgpt = {
603
599
  async write(prompt, outputLang) {
604
600
  if (!prompt) return console.error('Prompt (1st) argument not supplied. Pass a prompt!')
605
601
  if (!outputLang) return console.error('outputLang (2nd) argument not supplied. Pass a language!')
606
- for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
602
+ for (let i = 0 ; i < arguments.length ; i++) if (typeof arguments[i] != 'string')
607
603
  return console.error(`Argument ${ i + 1 } must be a string.`)
608
604
  chatgpt.send(`${prompt}\n\nWrite this as code in ${outputLang}`)
609
605
  console.info('Writing code...')
@@ -657,7 +653,7 @@ const chatgpt = {
657
653
  if (!chatDivs.length) return console.error('Chat is empty!')
658
654
  const msgs = [] ; let isUserMsg = true
659
655
  chatDivs.forEach(div => {
660
- const sender = isUserMsg ? 'USER' : 'CHATGPT'; isUserMsg = !isUserMsg
656
+ const sender = isUserMsg ? 'USER' : 'CHATGPT' ; isUserMsg = !isUserMsg
661
657
  const msg = [...div.childNodes].map(node => node.innerText)
662
658
  .join('\n\n') // insert double line breaks between paragraphs
663
659
  .replace('Copy code', '')
@@ -686,7 +682,7 @@ const chatgpt = {
686
682
  cssLinks.forEach(link => {
687
683
  const href = link.getAttribute('href')
688
684
  if (href?.startsWith('/')) link.setAttribute('href', 'https://chat.openai.com' + href)
689
- });
685
+ })
690
686
 
691
687
  // Serialize updated HTML to string
692
688
  transcript = new XMLSerializer().serializeToString(parsedHtml)
@@ -711,7 +707,7 @@ const chatgpt = {
711
707
 
712
708
  if (format == 'md') { // remove extraneous HTML + fix file extension
713
709
  const mdMatch = /<.*<h1(.|\n)*?href=".*?continue[^"]*".*?\/a>.*?<[^/]/.exec(transcript)[1]
714
- transcript = mdMatch || transcript; filename = filename.replace('.html', '.md')
710
+ transcript = mdMatch || transcript ; filename = filename.replace('.html', '.md')
715
711
  }
716
712
  const blob = new Blob([transcript],
717
713
  { type: 'text/' + ( format == 'html' ? 'html' : format == 'md' ? 'markdown' : 'plain' )})
@@ -769,7 +765,7 @@ const chatgpt = {
769
765
  }}
770
766
  if (!targetNames.includes(targetName.toLowerCase()))
771
767
  throw new Error(`Invalid targetName: ${targetName}. `
772
- + (targetNames.length > 0 ? 'Valid values are: ' + JSON.stringify(targetNames)
768
+ + (targetNames.length ? 'Valid values are: ' + JSON.stringify(targetNames)
773
769
  : 'targetType ' + targetType.toLowerCase() + ' does not require additional options.'))
774
770
 
775
771
  // Call target function using pre-validated name components
@@ -927,7 +923,7 @@ const chatgpt = {
927
923
 
928
924
  // Fill [userMessages]
929
925
  for (const key in data)
930
- if (data[key].message != null && data[key].message.author.role == 'user')
926
+ if (data[key]?.message?.author?.role == 'user')
931
927
  userMessages.push({ id: data[key].id, msg: data[key].message })
932
928
  userMessages.sort((a, b) => a.msg.create_time - b.msg.create_time) // sort in chronological order
933
929
 
@@ -938,12 +934,10 @@ const chatgpt = {
938
934
  // Fill [chatGPTMessages]
939
935
  for (const userMessage of userMessages) {
940
936
  let sub = []
941
- for (const key in data) {
942
- if (data[key].message != null && data[key].message.author.role == 'assistant'
943
- && isUserMsgAncestor(key, userMessage.id)) {
944
- sub.push(data[key].message)
945
- }
946
- }
937
+ for (const key in data)
938
+ if (data[key]?.message?.author?.role == 'assistant'
939
+ && isUserMsgAncestor(key, userMessage.id)
940
+ ) sub.push(data[key].message)
947
941
  sub.sort((a, b) => a.create_time - b.create_time) // sort in chronological order
948
942
  sub = sub.map(x => { // pull out msgs after sorting
949
943
  switch(x.content.content_type) {
@@ -961,7 +955,8 @@ const chatgpt = {
961
955
  msgsToReturn.push(userMessages[userMessage].msg.content.parts[0])
962
956
  else if (sender == 'chatgpt') // Fill [msgsToReturn] with ChatGPT responses
963
957
  for (const chatGPTMessage of chatGPTMessages)
964
- msgsToReturn.push(msgToGet == 'latest' ? chatGPTMessages[chatGPTMessages.length - 1] : chatGPTMessage );
958
+ msgsToReturn.push(msgToGet == 'latest' ? chatGPTMessages[chatGPTMessages.length - 1]
959
+ : chatGPTMessage )
965
960
  else { // Fill [msgsToReturn] with objects of user messages and chatgpt response(s)
966
961
  let i = 0
967
962
  for (const message in userMessages) {
@@ -1077,9 +1072,9 @@ const chatgpt = {
1077
1072
  else if (target == 'chatgpt') instructionsData.about_model_message += instruction
1078
1073
 
1079
1074
  await this.sendRequest('POST', token, instructionsData)
1080
- return resolve();
1081
- });
1082
- });
1075
+ return resolve()
1076
+ })
1077
+ })
1083
1078
  },
1084
1079
 
1085
1080
  clear(target) {
@@ -1134,7 +1129,7 @@ const chatgpt = {
1134
1129
  xhr.onload = () => {
1135
1130
  const responseData = JSON.parse(xhr.responseText)
1136
1131
  if (xhr.status == 422)
1137
- return reject('🤖 chatgpt.js >> Character limit exceeded. Custom instructions can have a maximum length of 1500 characters.');
1132
+ return reject('🤖 chatgpt.js >> Character limit exceeded. Custom instructions can have a maximum length of 1500 characters.')
1138
1133
  else if (xhr.status == 403 && responseData.detail.reason == 'content_policy')
1139
1134
  return reject('🤖 chatgpt.js >> ' + responseData.detail.description)
1140
1135
  else if (xhr.status != 200)
@@ -1259,7 +1254,7 @@ const chatgpt = {
1259
1254
  if (!attrs.items.every(el => typeof el == 'object')) // the entries of the array are not objects
1260
1255
  return console.error('\'items\' must be an array of objects!')
1261
1256
 
1262
- newElem.style = 'background-color: #000; width: 100%; border: none;'
1257
+ newElem.style = 'background-color: #000 ; width: 100% ; border: none'
1263
1258
 
1264
1259
  attrs.items.forEach(item => {
1265
1260
  const optionElement = document.createElement('option')
@@ -1302,7 +1297,7 @@ const chatgpt = {
1302
1297
  }
1303
1298
  },
1304
1299
 
1305
- minify() { chatgpt.code.minify(); },
1300
+ minify() { chatgpt.code.minify() },
1306
1301
 
1307
1302
  notify(...args) {
1308
1303
  const scheme = chatgpt.isDarkMode() ? 'dark' : 'light'
@@ -1310,7 +1305,7 @@ const chatgpt = {
1310
1305
  if (typeof args[0] == 'object' && !Array.isArray(args[0]))
1311
1306
  ({ msg, position, notifDuration, shadow, toast } = args[0])
1312
1307
  else [msg, position, notifDuration, shadow] = args
1313
- notifDuration = notifDuration ? +notifDuration : 1.75; // sec duration to maintain notification visibility
1308
+ notifDuration = notifDuration ? +notifDuration : 1.75 // sec duration to maintain notification visibility
1314
1309
  const fadeDuration = 0.35, // sec duration of fade-out
1315
1310
  vpYoffset = 23, vpXoffset = 27 // px offset from viewport border
1316
1311
 
@@ -1323,7 +1318,7 @@ const chatgpt = {
1323
1318
 
1324
1319
  // Create/append close button
1325
1320
  const closeBtn = document.createElement('div')
1326
- closeBtn.title = 'Dismiss'; closeBtn.classList.add('notif-close-btn', 'no-mobile-tap-outline')
1321
+ closeBtn.title = 'Dismiss' ; closeBtn.classList.add('notif-close-btn', 'no-mobile-tap-outline')
1327
1322
  const closeSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
1328
1323
  closeSVG.setAttribute('height', '8px')
1329
1324
  closeSVG.setAttribute('viewBox', '0 0 14 14')
@@ -1333,7 +1328,7 @@ const chatgpt = {
1333
1328
  closeSVGpath.setAttribute('fill-rule', 'evenodd')
1334
1329
  closeSVGpath.setAttribute('clip-rule', 'evenodd')
1335
1330
  closeSVGpath.setAttribute('fill', 'white')
1336
- closeSVGpath.setAttribute('d', 'M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z');
1331
+ closeSVGpath.setAttribute('d', 'M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z')
1337
1332
  closeSVG.append(closeSVGpath) ; closeBtn.append(closeSVG) ; notificationDiv.append(closeBtn)
1338
1333
 
1339
1334
  // Determine div position/quadrant
@@ -1384,7 +1379,8 @@ const chatgpt = {
1384
1379
  }
1385
1380
 
1386
1381
  // Enqueue notification
1387
- let notifyProps = JSON.parse(localStorage.notifyProps)
1382
+ let notifyProps = JSON.parse(localStorage.notifyProps
1383
+ ??= JSON.stringify({ queue: { topRight: [], bottomRight: [], bottomLeft: [], topLeft: [] }}))
1388
1384
  notifyProps.queue[notificationDiv.quadrant].push(notificationDiv.id)
1389
1385
  localStorage.notifyProps = JSON.stringify(notifyProps)
1390
1386
 
@@ -1420,7 +1416,7 @@ const chatgpt = {
1420
1416
 
1421
1417
  // Add notification dismissal to timeout schedule + button clicks
1422
1418
  const dismissNotif = () => {
1423
- notificationDiv.style.animation = `notif-zoom-fade-out ${fadeDuration}s ease-out`;
1419
+ notificationDiv.style.animation = `notif-zoom-fade-out ${fadeDuration}s ease-out`
1424
1420
  clearTimeout(dismissFuncTID)
1425
1421
  }
1426
1422
  const dismissFuncTID = setTimeout(dismissNotif, hideDelay * 1000) // maintain visibility for `hideDelay` secs, then dismiss
@@ -1472,7 +1468,7 @@ const chatgpt = {
1472
1468
 
1473
1469
  // Print methods
1474
1470
  const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches,
1475
- baseFontStyles = 'font-family: monospace ; font-size: larger ; '
1471
+ baseFontStyles = 'font-family: monospace ; font-size: larger ;'
1476
1472
  console.log('\n%c🤖 chatgpt.js methods\n', 'font-family: sans-serif ; font-size: xxx-large ; font-weight: bold')
1477
1473
  for (const functionName of functionNames) {
1478
1474
  const isChatGptObjParent = /chatgpt|other/.test(functionName[0]),
@@ -1535,7 +1531,7 @@ const chatgpt = {
1535
1531
  elems = [...text.matchAll(reTags)]
1536
1532
 
1537
1533
  // Process 1st element to render
1538
- if (elems.length > 0) {
1534
+ if (elems.length) {
1539
1535
  const elem = elems[0],
1540
1536
  [tagContent, tagName, tagAttrs, tagText] = elem.slice(0, 4),
1541
1537
  tagNode = document.createElement(tagName) ; tagNode.textContent = tagText
@@ -1585,7 +1581,7 @@ const chatgpt = {
1585
1581
  // chatToGet = index|title|id of chat to get (defaults to latest if '' or unpassed)
1586
1582
  // responseToGet = index of response to get (defaults to latest if '' or unpassed)
1587
1583
 
1588
- chatToGet = chatToGet || 'latest'; responseToGet = responseToGet || 'latest'
1584
+ chatToGet = chatToGet || 'latest' ; responseToGet = responseToGet || 'latest'
1589
1585
  return chatgpt.getChatData(chatToGet, 'msg', 'chatgpt', responseToGet)
1590
1586
  },
1591
1587
 
@@ -1638,15 +1634,15 @@ const chatgpt = {
1638
1634
  return console.error(`Argument ${ i + 1 } must be a string!`)
1639
1635
  const textArea = chatgpt.getChatBox()
1640
1636
  if (!textArea) return console.error('Chatbar element not found!')
1641
- const msgP = document.createElement('p'); msgP.textContent = msg
1637
+ const msgP = document.createElement('p') ; msgP.textContent = msg
1642
1638
  textArea.querySelector('p').replaceWith(msgP)
1643
1639
  textArea.dispatchEvent(new Event('input', { bubbles: true })) // enable send button
1644
1640
  setTimeout(function delaySend() {
1645
1641
  const sendBtn = chatgpt.getSendButton()
1646
- if (!sendBtn?.hasAttribute('disabled')) { // send msg
1642
+ if (!sendBtn?.hasAttribute('disabled')) // send msg
1647
1643
  method.toLowerCase() == 'click' || chatgpt.browser.isMobile() ? sendBtn.click()
1648
1644
  : textArea.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
1649
- } else setTimeout(delaySend, 222)
1645
+ else setTimeout(delaySend, 222)
1650
1646
  }, 222)
1651
1647
  },
1652
1648
 
@@ -1688,7 +1684,7 @@ const chatgpt = {
1688
1684
  },
1689
1685
 
1690
1686
  async sentiment(text, entity) {
1691
- for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
1687
+ for (let i = 0 ; i < arguments.length ; i++) if (typeof arguments[i] != 'string')
1692
1688
  return console.error(`Argument ${ i + 1 } must be a string.`)
1693
1689
  chatgpt.send('What is the sentiment of the following text'
1694
1690
  + ( entity ? ` towards the entity ${entity},` : '')
@@ -1840,15 +1836,13 @@ const chatgpt = {
1840
1836
  return console.error(`🤖 chatgpt.js >> Invalid element! Valid elems are [${validElems}]`)
1841
1837
 
1842
1838
  const newElem = document.createElement(elem == 'dropdown' ? 'select' : elem)
1843
- newElem.id = Math.floor(chatgpt.randomFloat() * 1000000) + Date.now() // Add random id to the element
1839
+ newElem.id = Math.floor(chatgpt.randomFloat() * 1000000) + Date.now()
1844
1840
 
1845
1841
  if (elem == 'button') {
1846
- newElem.textContent = attrs?.label && typeof attrs.label == 'string'
1847
- ? attrs.label
1848
- : 'chatgpt.js button'
1842
+ newElem.textContent = attrs?.label && typeof attrs.label == 'string' ? attrs.label : 'chatgpt.js button'
1849
1843
  const icon = document.createElement('img')
1850
- icon.src = attrs?.icon && typeof attrs.icon == 'string' // Can also be base64 encoded image string
1851
- ? attrs.icon // Add icon to button element if given, else default one
1844
+ icon.src = attrs?.icon && typeof attrs.icon == 'string' // can also be base64 encoded image string
1845
+ ? attrs.icon // add icon to button element if given, else default one
1852
1846
  : `${chatgpt.endpoints.assets}/starters/chrome/extension/icons/icon128.png`
1853
1847
  icon.width = 18
1854
1848
  newElem.firstChild.before(icon)
@@ -1856,9 +1850,9 @@ const chatgpt = {
1856
1850
  }
1857
1851
 
1858
1852
  else if (elem == 'dropdown') {
1859
- if (!attrs?.items || // There no are options to add
1853
+ if (!attrs?.items || // there no are options to add
1860
1854
  !Array.isArray(attrs.items) || // It's not an array
1861
- !attrs.items.length) // The array is empty
1855
+ !attrs.items.length) // the array is empty
1862
1856
  attrs.items = [{ text: '🤖 chatgpt.js option', value: 'chatgpt.js option value' }] // Set default dropdown entry
1863
1857
 
1864
1858
  if (!attrs.items.every(el => typeof el == 'object')) // The entries of the array are not objects
@@ -1883,7 +1877,7 @@ const chatgpt = {
1883
1877
  return newElem.id // Return the element id
1884
1878
  },
1885
1879
 
1886
- exists() { return !!chatgpt.getNewChatLink(); },
1880
+ exists() { return !!chatgpt.getNewChatLink() },
1887
1881
  hide() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!') },
1888
1882
  show() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!') },
1889
1883
  isOff() { return !this.isOn() },
@@ -1917,12 +1911,12 @@ const chatgpt = {
1917
1911
  },
1918
1912
 
1919
1913
  startNewChat() { try { chatgpt.getNewChatBtn().click() } catch (err) { console.error(err.message) }},
1920
- stop() { chatgpt.response.stopGenerating(); },
1914
+ stop() { chatgpt.response.stopGenerating() },
1921
1915
 
1922
1916
  async suggest(ideaType, details) {
1923
1917
  if (!ideaType) return console.error('ideaType (1st argument) not supplied'
1924
1918
  + `(e.g. 'gifts', 'names', 'recipes', etc.)`)
1925
- for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
1919
+ for (let i = 0 ; i < arguments.length ; i++) if (typeof arguments[i] != 'string')
1926
1920
  return console.error(`Argument ${ i + 1 } must be a string.`)
1927
1921
  chatgpt.send('Suggest some names. ' + ( details || '' ))
1928
1922
  console.info(`Creating ${ideaType}...`)
@@ -1966,7 +1960,7 @@ const chatgpt = {
1966
1960
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest')
1967
1961
  },
1968
1962
 
1969
- toggleScheme() { chatgpt.settings.scheme.toggle(); },
1963
+ toggleScheme() { chatgpt.settings.scheme.toggle() },
1970
1964
 
1971
1965
  async translate(text, outputLang) {
1972
1966
  if (!text) return console.error('Text (1st) argument not supplied. Pass some text!')
@@ -1991,7 +1985,7 @@ const chatgpt = {
1991
1985
  const r = ( // generate random nibble
1992
1986
  ( d + (window.crypto.getRandomValues(new Uint32Array(1))[0] / (Math.pow(2, 32) - 1))*16)%16 | 0 )
1993
1987
  d = Math.floor(d/16) // correspond each UUID digit to unique 4-bit chunks of timestamp
1994
- return ( c == 'x' ? r : (r&0x3|0x8) ).toString(16); // generate random hexadecimal digit
1988
+ return ( c == 'x' ? r : (r&0x3|0x8) ).toString(16) // generate random hexadecimal digit
1995
1989
  })
1996
1990
  return uuid
1997
1991
  }
@@ -2092,8 +2086,8 @@ const cjsFuncSynonyms = [
2092
2086
  ['temp', 'temporary'],
2093
2087
  ['typing', 'generating'],
2094
2088
  ['unminify', 'beautify', 'prettify', 'prettyPrint']
2095
- ];
2096
- (function createCJSaliasFuncs(obj = chatgpt) {
2089
+ ]
2090
+ ;(function createCJSaliasFuncs(obj = chatgpt) {
2097
2091
  for (const prop in obj) {
2098
2092
  if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue // skip inherited props
2099
2093
  if (typeof obj[prop] == 'object') createCJSaliasFuncs(obj[prop]) // recurse thru objs to find deeper functions
@@ -2134,11 +2128,13 @@ function toCamelCase(words) {
2134
2128
  // Prefix console logs w/ '🤖 chatgpt.js >> '
2135
2129
  const consolePrefix = '🤖 chatgpt.js >> ', ogError = console.error, ogInfo = console.info
2136
2130
  console.error = (...args) => {
2137
- if (!args[0].startsWith(consolePrefix)) ogError(consolePrefix + args[0], ...args.slice(1))
2138
- else ogError(...args)
2131
+ if (typeof args[0] == 'string') {
2132
+ if (!args[0].startsWith(consolePrefix)) ogError(consolePrefix + args[0], ...args.slice(1))
2133
+ else ogError(...args)
2134
+ } else ogError(consolePrefix, ...args)
2139
2135
  }
2140
2136
  console.info = (msg) => {
2141
- if (!msg.startsWith(consolePrefix)) ogInfo(consolePrefix + msg);
2137
+ if (!msg.startsWith(consolePrefix)) ogInfo(consolePrefix + msg)
2142
2138
  else ogInfo(msg)
2143
2139
  }
2144
2140