@kudoai/chatgpt.js 2.9.3 → 3.0.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/README.md CHANGED
@@ -45,8 +45,8 @@
45
45
  [![](https://img.shields.io/github/stars/KudoAI/chatgpt.js?label=Stars&color=af68ff&logo=github&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/stargazers)
46
46
  [![](https://img.shields.io/badge/License-MIT-green.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/blob/main/LICENSE.md)
47
47
  [![](https://img.shields.io/github/commit-activity/m/KudoAI/chatgpt.js?label=Commits&logo=github&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/commits/main)
48
- ![](https://img.shields.io/badge/Clones-2.8k/month-869da0?logo=github&logoColor=white&labelColor=464646&style=for-the-badge)
49
- [![](https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v2.9.3&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/tree/v2.9.3/dist/chatgpt.min.js)
48
+ ![](https://img.shields.io/badge/Clones-2K/month-869da0?logo=github&logoColor=white&labelColor=464646&style=for-the-badge)
49
+ [![](https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.0.0&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/tree/v3.0.0/dist/chatgpt.min.js)
50
50
  [![](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)](https://www.codefactor.io/repository/github/kudoai/chatgpt.js)
51
51
  [![](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)](https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js)
52
52
  [![](https://img.shields.io/badge/Mentioned_in-Awesome-cca8c4?logo=awesomelists&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/sindresorhus/awesome-chatgpt#javascript)
@@ -63,7 +63,7 @@
63
63
 
64
64
  </div>
65
65
 
66
- <span style="color: white">chatgpt.js</span> is a <span style="color: white">powerful</span> JavaScript library that allows for <span style="color: white">super easy</span> interaction w/ the ChatGPT DOM.
66
+ <span style="color: white"><b>chatgpt.js</b></span> is a <span style="color: white">powerful</span> JavaScript library that allows for <span style="color: white">super easy</span> interaction w/ the ChatGPT DOM.
67
67
 
68
68
  - Feature-rich
69
69
  - Object-oriented
@@ -84,7 +84,7 @@
84
84
 
85
85
  ```js
86
86
  (async () => {
87
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.3/dist/chatgpt.min.js');
87
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.0.0/dist/chatgpt.min.js');
88
88
  // Your code here...
89
89
  })();
90
90
  ```
@@ -93,7 +93,7 @@
93
93
 
94
94
  ```js
95
95
  var xhr = new XMLHttpRequest();
96
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.3/dist/chatgpt.min.js');
96
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.0.0/dist/chatgpt.min.js');
97
97
  xhr.onload = function () {
98
98
  if (xhr.status === 200) {
99
99
  var chatgptJS = document.createElement('script');
@@ -115,7 +115,7 @@ function yourCode() {
115
115
 
116
116
  ```js
117
117
  ...
118
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.3/dist/chatgpt.min.js
118
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.0.0/dist/chatgpt.min.js
119
119
  // ==/UserScript==
120
120
 
121
121
  // Your code here...
@@ -190,7 +190,7 @@ chatgpt.get('reply', 'last');
190
190
 
191
191
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
192
192
 
193
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.9.3/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!
193
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.0.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!
194
194
 
195
195
  <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
196
196
 
@@ -204,6 +204,13 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
204
204
 
205
205
  #
206
206
 
207
+ ### <img src="https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon48.png" width=20> [AmazonGPT](https://amazongpt.kudoai.com)
208
+
209
+ > Add AI to Amazon shopping.
210
+ <br>[Install](https://greasyfork.org/scripts/500663-amazongpt) /
211
+ [Readme](https://amazongpt.kudoai.com/#readme) /
212
+ [Discuss](https://amazongpt.kudoai.com/discussions)
213
+
207
214
  ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://media.autoclearchatgpt.com/images/icons/openai/white/icon48.png?cece513"><img width=21 src="https://media.autoclearchatgpt.com/images/icons/openai/black/icon48.png?cece513"></picture> [Autoclear ChatGPT History](https://autoclearchatgpt.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://media.autoclearchatgpt.com/images/badges/awesome/badge.svg?2c0d9fc" style="margin:0 0 -2px 5px"></a>
208
215
 
209
216
  > Auto-clear your ChatGPT query history for maximum privacy.
@@ -213,7 +220,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
213
220
 
214
221
  ### <img width=24 src="https://media.bravegpt.com/images/icons/bravegpt/icon48.png?0a9e287"> [BraveGPT](https://bravegpt.com) &nbsp;<a href="https://www.producthunt.com/posts/bravegpt?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-bravegpt" target="_blank" rel="noopener"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=385630&theme=light" style="width: 112px; height: 24px; margin:0 0 -4px 5px;" width="112" height="24" /></a>
215
222
 
216
- > Display ChatGPT answers in Brave Search sidebar (powered by GPT-4!)
223
+ > Adds AI answers to Brave Search (powered by GPT-4o!)
217
224
  <br>[Install](https://docs.bravegpt.com/#-installation) /
218
225
  [Readme](https://docs.bravegpt.com/#readme) /
219
226
  [Discuss](https://github.bravegpt.com/discussions)
@@ -225,6 +232,13 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
225
232
  [Readme](https://docs.chatgptautocontinue.com/#readme) /
226
233
  [Discuss](https://github.chatgptautocontinue.com/discussions)
227
234
 
235
+ ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/adamlui/chatgpt-auto-talk@eb7f285/assets/images/icons/openai/white/icon64.png"><img width=21 src="https://cdn.jsdelivr.net/gh/adamlui/chatgpt-auto-talk@eb7f285/assets/images/icons/openai/black/icon64.png"></picture> [ChatGPT Auto-Talk 📣](https://github.com/adamlui/chatgpt-auto-talk)
236
+
237
+ > Auto-play ChatGPT responses.
238
+ <br>[Install](https://greasyfork.org/scripts/500940-chatgpt-auto-talk) /
239
+ [Readme](https://github.com/adamlui/chatgpt-auto-talk#readme) /
240
+ [Discuss](https://github.com/adamlui/chatgpt-auto-talk/discussions)
241
+
228
242
  ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://media.chatgptautorefresh.com/images/icons/openai/white/icon48.png?a45cf1e"><img width=21 src="https://media.chatgptautorefresh.com/images/icons/openai/black/icon48.png?a45cf1e"></picture> [ChatGPT Auto Refresh ↻](https://chatgptautorefresh.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://media.chatgptautorefresh.com/images/badges/awesome/badge.svg?1080f44" style="margin:0 0 -2px 5px"></a>
229
243
 
230
244
  > Keeps ChatGPT sessions fresh to eliminate network errors + Cloudflare checks.
@@ -234,19 +248,19 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
234
248
 
235
249
  ### <img width=23 src="https://media.ddgpt.com/images/icons/duckduckgpt/icon48.png?af89302"> [DuckDuckGPT](https://duckduckgpt.com) &nbsp;<a href="https://www.producthunt.com/posts/duckduckgpt?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-duckduckgpt" target="_blank" rel="noopener"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=379261&theme=light" style="width: 112px; height: 24px; margin:0 0 -4px 5px;" width="112" height="24" /></a>
236
250
 
237
- > Display ChatGPT answers in DuckDuckGo sidebar (powered by GPT-4!)
251
+ > Adds AI answers to DuckDuckGo (powered by GPT-4o!)
238
252
  <br>[Install](https://docs.ddgpt.com/#-installation) /
239
253
  [Readme](https://docs.ddgpt.com/#readme) /
240
254
  [Discuss](https://github.ddgpt.com/discussions)
241
255
 
242
256
  ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://media.googlegpt.io/images/icons/googlegpt/white/icon32.png?8652a6e"><img width=21 src="https://media.googlegpt.io/images/icons/googlegpt/black/icon32.png?8652a6e"></picture> [GoogleGPT](https://googlegpt.io) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://media.googlegpt.io/images/badges/awesome/badge.svg?699c63d" style="margin:0 0 -2px 5px"></a>
243
257
 
244
- > Display ChatGPT answers in Google Search sidebar (powered by GPT-4!)
245
- <br>[Install](https://greasyfork.org/scripts/478597-googlegpt) /
258
+ > Adds AI answers to Google Search (powered by Google Gemma + GPT-4o!)
259
+ <br>[Install](https://greasyfork.googlegpt.io) /
246
260
  [Readme](https://docs.googlegpt.io/#readme) /
247
261
  [Discuss](https://github.googlegpt.io/discussions)
248
262
 
249
- ### <img width=23 src="https://media.chatgptjs.org/images/icons/platforms/thunderbird/icon32.png?313a9c5"> [ThunderAI](https://micz.it/thunderdbird-addon-thunderai/)
263
+ ### <img width=23 src="https://media.chatgptjs.org/images/icons/platforms/thunderbird/icon32.png?313a9c5"> [ThunderAI](https://micz.it/thunderdbird-addon-thunderai/) &nbsp;<a href="https://addons.thunderbird.net/thunderbird/addon/thunderai/reviews"><picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://media.chatgptjs.org/images/badges/5-star/blue-stars.png?0943672"><img width=92 alt="[Rated 5-stars]" src="https://media.chatgptjs.org/images/badges/5-star/yellow-stars-in-white-pill.png?0943672"></picture></a>
250
264
 
251
265
  > Use ChatGPT in Thunderbird to enhance you emails, even with a free account!
252
266
  <br>[Install](https://addons.thunderbird.net/thunderbird/addon/thunderai/) /
@@ -310,6 +324,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
310
324
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/111466842?first-contrib=2024.2.15-add-en-gb-locale&h=47&w=47&mask=circle&maxage=7d "@Luwa-Tech")](https://github.com/Luwa-Tech)
311
325
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/61795?first-contrib=2024.5.9-update-css-selector-for-getregeneratebutton&h=47&w=47&mask=circle&maxage=7d "@micz")](https://github.com/micz)
312
326
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/17583722?first-contrib=2024.5.17-chrome-starter-manifest-matches-outdated-alert&h=47&w=47&mask=circle&maxage=7d "@imranaalam")](https://github.com/imranaalam)
327
+ [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/50076933?first-contrib=2024.6.22-code.isidle-request&h=47&w=47&mask=circle&maxage=7d "@grayfallstown")](https://github.com/grayfallstown)
313
328
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=47&w=47&mask=circle&maxage=7d "Dependabot")](https://github.com/dependabot)
314
329
  <a href="https://chatgpt.com"><picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/chatgpt/black-on-white/icon189.png?h=46&w=46&mask=circle&maxage=7d"><img src="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/chatgpt/white-on-black/icon189.png?h=46&w=46&mask=circle&maxage=7d" title="ChatGPT"></picture></a>
315
330
  <a href="https://poe.com"><picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/poe/w-purple-blue-stripes/black-on-white/icon175.png?h=46&w=46&mask=circle&maxage=7d"><img src="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/poe/w-purple-blue-stripes/white-on-black/icon175.png?h=46&w=46&mask=circle&maxage=7d" title="Poe"></picture></a>
@@ -343,7 +358,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
343
358
  <div align="center">
344
359
 
345
360
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
346
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.9.3/docs/USERGUIDE.md) /
361
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.0.0/docs/USERGUIDE.md) /
347
362
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
348
363
  <a href="#--------------------------------------------------------------------------------english---------简体中文---------繁體中文---------日本---------한국인---------हिंदी---------नेपाली---------deutsch---------español---------français---------italiano---------nederlands---------português---------việt----">Back to top ↑</a>
349
364
 
package/chatgpt.js CHANGED
@@ -3,8 +3,13 @@
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 endpoints
7
- const endpoints = {
6
+ // Init feedback props
7
+ localStorage.alertQueue = JSON.stringify([]);
8
+ localStorage.notifyProps = JSON.stringify({ queue: { topRight: [], bottomRight: [], bottomLeft: [], topLeft: [] }});
9
+
10
+ // Define chatgpt API
11
+ const chatgpt = { // eslint-disable-line no-redeclare
12
+ openAIaccessToken: {}, endpoints: {
8
13
  assets: 'https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js',
9
14
  openAI: {
10
15
  session: 'https://chatgpt.com/api/auth/session',
@@ -13,16 +18,7 @@ const endpoints = {
13
18
  share_create: 'https://chatgpt.com/backend-api/share/create',
14
19
  share: 'https://chatgpt.com/backend-api/share',
15
20
  instructions: 'https://chatgpt.com/backend-api/user_system_messages'
16
- }
17
- };
18
-
19
- // Init feedback properties
20
- localStorage.alertQueue = JSON.stringify([]);
21
- localStorage.notifyProps = JSON.stringify({ queue: { topRight: [], bottomRight: [], bottomLeft: [], topLeft: [] }});
22
-
23
- // Define chatgpt.methods
24
- const chatgpt = { // eslint-disable-line no-redeclare
25
- openAIaccessToken: {},
21
+ }},
26
22
 
27
23
  actAs: function(persona) {
28
24
  // Prompts ChatGPT to act as a persona from https://github.com/KudoAI/chat-prompts/blob/main/personas.json
@@ -127,8 +123,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
127
123
  + 'background-color: ' + ( scheme == 'dark' ? '#00cfff' : '#9cdaff' ) + ';'
128
124
  + 'box-shadow: 2px 1px ' + ( scheme == 'dark' ? '54px #00cfff' : '30px #9cdaff' ) + '}'
129
125
  + '.modal-close-btn {'
130
- + 'cursor: pointer ; width: 20px ; height: 20px ; float: right ; position: relative ; right: -2px }'
131
- + '.modal-close-btn svg { margin: 5px 5px }' // center SVG for hover overlay
126
+ + 'cursor: pointer ; width: 29px ; height: 29px ; border-radius: 17px ;'
127
+ + 'float: right ; position: relative ; right: -6px ; top: -5px }'
128
+ + '.modal-close-btn svg { margin: 10px }' // center SVG for hover underlay
132
129
  + `.modal-close-btn:hover { background-color: #f2f2f2${ scheme == 'dark' ? '00' : '' }}`
133
130
 
134
131
  // Checkbox styles
@@ -226,7 +223,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
226
223
  modalContainer.style.display = '';
227
224
  setTimeout(() => { // delay non-0 opacity's for transition fx
228
225
  modalContainer.style.backgroundColor = (
229
- `rgba(67, 70, 72, ${ scheme === 'dark' ? 0.62 : 0 })`);
226
+ `rgba(67, 70, 72, ${ scheme === 'dark' ? 0.62 : 0.1 })`);
230
227
  modalContainer.classList.add('animated'); }, 100);
231
228
  }
232
229
 
@@ -234,13 +231,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
234
231
  const clickHandler = event => { // explicitly defined to support removal post-dismissal
235
232
  if (event.target == event.currentTarget || event.target instanceof SVGPathElement) dismissAlert(); };
236
233
  const keyHandler = event => { // to dismiss active alert
237
- const dismissKeys = [13, 27]; // enter/esc
238
- if (dismissKeys.includes(event.keyCode)) {
234
+ const dismissKeys = [' ', 'Spacebar', 'Enter', 'Return', 'Escape', 'Esc'],
235
+ dismissKeyCodes = [32, 13, 27];
236
+ if (dismissKeys.includes(event.key) || dismissKeyCodes.includes(event.keyCode)) {
239
237
  for (const alertId of alertQueue) { // look to handle only if triggering alert is active
240
238
  const alert = document.getElementById(alertId);
241
239
  if (alert && alert.style.display !== 'none') { // active alert found
242
- if (event.keyCode === 27) dismissAlert(); // if esc pressed, dismiss alert & do nothing
243
- else if (event.keyCode === 13) { // else if enter pressed
240
+ if (event.key.includes('Esc') || event.keyCode == 27) // esc pressed
241
+ dismissAlert(); // dismiss alert & do nothing
242
+ else if ([' ', 'Spacebar', 'Enter', 'Return'].includes(event.key) || [32, 13].includes(event.keyCode)) { // space/enter pressed
244
243
  const mainButton = alert.querySelector('.modal-buttons').lastChild; // look for main button
245
244
  if (mainButton) { mainButton.click(); event.preventDefault(); } // click if found
246
245
  } return;
@@ -363,7 +362,10 @@ const chatgpt = { // eslint-disable-line no-redeclare
363
362
 
364
363
  isLightMode: function() { return window.matchMedia?.('(prefers-color-scheme: light)')?.matches; },
365
364
  isDarkMode: function() { return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches; },
366
- isChromium: function() { return navigator.userAgent.includes('Chrome'); },
365
+ isChromium: function() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Chromium'); },
366
+ isChrome: function() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Chrome'); },
367
+ isEdge: function() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Edge'); },
368
+ isBrave: function() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Brave'); },
367
369
  isFirefox: function() { return navigator.userAgent.includes('Firefox'); },
368
370
 
369
371
  isFullScreen: function() {
@@ -377,49 +379,20 @@ const chatgpt = { // eslint-disable-line no-redeclare
377
379
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); }
378
380
  },
379
381
 
380
- clearChats: async function(method) {
381
-
382
- // Validate method arg
383
- const validMethods = ['api', 'dom'];
384
- method = (method || 'dom').trim().toLowerCase(); // set to 'dom' by default
385
- if (method && !validMethods.includes(method))
386
- return console.error(`Method argument must be one of: [${validMethods}]`);
387
-
388
- if (method == 'dom') {
389
- const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
390
- try {
391
- chatgpt.menu.open(); await delay(10);
392
- const settingsBtn = document.querySelector(
393
- 'a[role="menuitem"] svg path[d*="M12.003 10.5a1.5"]').parentNode.parentNode;
394
- settingsBtn.click(); await delay(333);
395
- const settingsBtns = document.querySelectorAll('[id*=radix] button'),
396
- deleteBtn = settingsBtns[settingsBtns.length - 1];
397
- deleteBtn.click(); await delay(10);
398
- document.querySelector('button[class*="danger"').click(); // confirm clear
399
- return console.info('Chats successfully cleared.');
400
- } catch (err) {
401
- console.error(err.message);
402
- if (arguments.length == 0) {
403
- console.info('Using backend API method instead.'); chatgpt.clearChats('api'); }
404
- }
405
-
406
- } else { // API method
407
- // NOTE: DOM is not updated to reflect new empty chat list (until session refresh)
408
-
409
- return new Promise((resolve, reject) => {
410
- chatgpt.getAccessToken().then(token => {
411
- const xhr = new XMLHttpRequest();
412
- xhr.open('PATCH', endpoints.openAI.chats, true);
413
- xhr.setRequestHeader('Content-Type', 'application/json');
414
- xhr.setRequestHeader('Authorization', 'Bearer ' + token);
415
- xhr.onload = () => {
416
- if (xhr.status !== 200) return reject('🤖 chatgpt.js >> Request failed. Cannot clear chats.');
417
- console.info('Chats successfully cleared'); resolve();
418
- };
419
- xhr.send(JSON.stringify({ is_visible: false }));
420
- }).catch(err => reject(new Error(err.message)));
421
- });
422
- }
382
+ clearChats: async function() { // back-end method
383
+ return new Promise((resolve, reject) => {
384
+ chatgpt.getAccessToken().then(token => {
385
+ const xhr = new XMLHttpRequest();
386
+ xhr.open('PATCH', chatgpt.endpoints.openAI.chats, true);
387
+ xhr.setRequestHeader('Content-Type', 'application/json');
388
+ xhr.setRequestHeader('Authorization', 'Bearer ' + token);
389
+ xhr.onload = () => {
390
+ if (xhr.status !== 200) return reject('🤖 chatgpt.js >> Request failed. Cannot clear chats.');
391
+ console.info('Chats successfully cleared'); resolve();
392
+ };
393
+ xhr.send(JSON.stringify({ is_visible: false }));
394
+ }).catch(err => reject(new Error(err.message)));
395
+ });
423
396
  },
424
397
 
425
398
  code: {
@@ -439,6 +412,34 @@ const chatgpt = { // eslint-disable-line no-redeclare
439
412
  return codeBlocks ? codeBlocks[codeBlocks.length - 1] : msg;
440
413
  },
441
414
 
415
+ isIdle: async function() {
416
+ await new Promise(resolve => { // when in conversation page
417
+ (function checkConvoPage() {
418
+ document.querySelector('div[data-message-author-role]') ? resolve(true)
419
+ : setTimeout(checkConvoPage, 200); })();
420
+ });
421
+ await new Promise(resolve => { // when reply starts generating
422
+ (function checkReplyExists() {
423
+ const msgDivs = document.querySelectorAll('div[data-message-author-role]');
424
+ msgDivs[msgDivs.length - 1].dataset.messageAuthorRole == 'assistant' ? resolve(true)
425
+ : setTimeout(checkReplyExists, 200); })();
426
+ });
427
+ const lastReplyDiv = await new Promise(resolve => { // when code starts generating
428
+ (function checkPreExists() {
429
+ const replyDivs = document.querySelectorAll('div[data-message-author-role="assistant"]'),
430
+ lastReplyDiv = replyDivs[replyDivs.length - 1];
431
+ lastReplyDiv.querySelector('pre') ? resolve(lastReplyDiv)
432
+ : setTimeout(checkPreExists, 200); })();
433
+ });
434
+ return Promise.race([
435
+ new Promise(resolve => { // when code block not last child of reply div
436
+ (function checkPreNotLast() {
437
+ lastReplyDiv.querySelector('pre').nextElementSibling ? resolve(true)
438
+ : setTimeout(checkPreNotLast, 200); })();
439
+ }), chatgpt.isIdle() // ...or reply stopped generating
440
+ ]);
441
+ },
442
+
442
443
  minify: async function(code) {
443
444
  if (!code) return console.error('Code argument not supplied. Pass some code!');
444
445
  if (typeof code !== 'string') return console.error('Code argument must be a string!');
@@ -609,6 +610,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
609
610
  },
610
611
 
611
612
  extractCode: function() { chatgpt.code.extract(); },
613
+ focusChatbar: function() { chatgpt.getChatBox()?.focus(); },
612
614
 
613
615
  generateRandomIP: function() {
614
616
  const ip = Array.from({length: 4}, () => Math.floor(chatgpt.randomFloat() * 256)).join('.');
@@ -625,9 +627,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
625
627
  throw new TypeError('Invalid arguments. Both arguments must be strings.'); }
626
628
 
627
629
  // Validate targetType
628
- if (!targetTypes.includes(targetType.toLowerCase())) {
630
+ if (!cjsTargetTypes.includes(targetType.toLowerCase())) {
629
631
  throw new Error('Invalid targetType: ' + targetType
630
- + '. Valid values are: ' + JSON.stringify(targetTypes)); }
632
+ + '. Valid values are: ' + JSON.stringify(cjsTargetTypes)); }
631
633
 
632
634
  // Validate targetName scoped to pre-validated targetType
633
635
  const targetNames = [], reTargetName = new RegExp('^get(.*)' + targetType + '$', 'i');
@@ -655,7 +657,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
655
657
  (Date.parse(chatgpt.openAIaccessToken.expireDate) - Date.parse(new Date()) >= 0)) // not expired
656
658
  return resolve(chatgpt.openAIaccessToken.token);
657
659
  const xhr = new XMLHttpRequest();
658
- xhr.open('GET', endpoints.openAI.session, true);
660
+ xhr.open('GET', chatgpt.endpoints.openAI.session, true);
659
661
  xhr.setRequestHeader('Content-Type', 'application/json');
660
662
  xhr.onload = () => {
661
663
  if (xhr.status !== 200) return reject('🤖 chatgpt.js >> Request failed. Cannot retrieve access token.');
@@ -688,7 +690,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
688
690
  // Return account details
689
691
  return new Promise((resolve, reject) => {
690
692
  const xhr = new XMLHttpRequest();
691
- xhr.open('GET', endpoints.openAI.session, true);
693
+ xhr.open('GET', chatgpt.endpoints.openAI.session, true);
692
694
  xhr.setRequestHeader('Content-Type', 'application/json');
693
695
  xhr.onload = () => {
694
696
  if (xhr.status === 200) {
@@ -744,7 +746,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
744
746
  const re_chatID = /\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/;
745
747
  return new Promise((resolve, reject) => {
746
748
  const xhr = new XMLHttpRequest();
747
- xhr.open('GET', endpoints.openAI.chats, true);
749
+ xhr.open('GET', chatgpt.endpoints.openAI.chats, true);
748
750
  xhr.setRequestHeader('Content-Type', 'application/json');
749
751
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
750
752
  xhr.onload = () => {
@@ -784,7 +786,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
784
786
  return new Promise((resolve, reject) => {
785
787
  const xhr = new XMLHttpRequest();
786
788
  getChatDetails(token, ['id']).then(chat => {
787
- xhr.open('GET', `${endpoints.openAI.chat}/${chat.id}`, true);
789
+ xhr.open('GET', `${chatgpt.endpoints.openAI.chat}/${chat.id}`, true);
788
790
  xhr.setRequestHeader('Content-Type', 'application/json');
789
791
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
790
792
  xhr.onload = () => {
@@ -917,8 +919,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
917
919
  isLoaded: function() {
918
920
  return new Promise(resolve => {
919
921
  (function checkChatHistory() {
920
- if (document.querySelector('nav')) resolve(true);
921
- else setTimeout(checkChatHistory, 200);
922
+ document.querySelector('nav') ? resolve(true) : setTimeout(checkChatHistory, 200);
922
923
  })();
923
924
  });}
924
925
  },
@@ -996,7 +997,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
996
997
 
997
998
  return new Promise((resolve, reject) => {
998
999
  const xhr = new XMLHttpRequest();
999
- xhr.open(method, endpoints.openAI.instructions, true);
1000
+ xhr.open(method, chatgpt.endpoints.openAI.instructions, true);
1000
1001
  // Set headers
1001
1002
  xhr.setRequestHeader('Accept-Language', 'en-US');
1002
1003
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
@@ -1048,29 +1049,24 @@ const chatgpt = { // eslint-disable-line no-redeclare
1048
1049
  }
1049
1050
  },
1050
1051
 
1051
- isChromium: function() { return chatgpt.browser.isChromium(); },
1052
1052
  isDarkMode: function() { return document.documentElement.classList.toString().includes('dark'); },
1053
- isFirefox: function() { return chatgpt.browser.isFirefox(); },
1054
1053
  isFullScreen: function() { return chatgpt.browser.isFullScreen(); },
1055
1054
 
1056
1055
  isIdle: function() {
1057
1056
  return new Promise(resolve => {
1058
1057
  (function checkIsIdle() {
1059
- if (chatgpt.getRegenerateButton()) resolve(true);
1060
- else setTimeout(checkIsIdle, 200);
1058
+ chatgpt.getRegenerateButton() ? resolve(true) : setTimeout(checkIsIdle, 200);
1061
1059
  })();
1062
1060
  });},
1063
1061
 
1064
1062
  isLoaded: function() {
1065
1063
  return new Promise(resolve => {
1066
1064
  (function checkIsLoaded() {
1067
- if (chatgpt.getNewChatButton()) resolve(true);
1068
- else setTimeout(checkIsLoaded, 200);
1065
+ chatgpt.getNewChatButton() ? resolve(true) : setTimeout(checkIsLoaded, 200);
1069
1066
  })();
1070
1067
  });},
1071
1068
 
1072
1069
  isLightMode: function() { return document.documentElement.classList.toString().includes('light'); },
1073
- isMobileDevice: function() { return chatgpt.browser.isMobile(); },
1074
1070
 
1075
1071
  logout: function() { window.location.href = 'https://chat.openai.com/auth/logout'; },
1076
1072
 
@@ -1106,7 +1102,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1106
1102
  const icon = document.createElement('img');
1107
1103
  icon.src = attrs?.icon && typeof attrs.icon == 'string' // can also be base64 encoded image string
1108
1104
  ? attrs.icon // add icon to button element if given, else default one
1109
- : ( endpoints.assets + '/starters/chrome/extension/icons/icon128.png' );
1105
+ : ( chatgpt.endpoints.assets + '/starters/chrome/extension/icons/icon128.png' );
1110
1106
  icon.width = 18;
1111
1107
  newElement.insertBefore(icon, newElement.firstChild);
1112
1108
 
@@ -1177,7 +1173,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1177
1173
 
1178
1174
  notify: async function(msg, position, notifDuration, shadow) {
1179
1175
  notifDuration = notifDuration ? +notifDuration : 1.75; // sec duration to maintain notification visibility
1180
- const fadeDuration = 0.3, // sec duration of fade-out
1176
+ const fadeDuration = 0.35, // sec duration of fade-out
1181
1177
  vpYoffset = 23, vpXoffset = 27; // px offset from viewport border
1182
1178
 
1183
1179
  // Create/append notification div
@@ -1560,7 +1556,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1560
1556
  return new Promise((resolve, reject) => {
1561
1557
  const xhr = new XMLHttpRequest();
1562
1558
  chatgpt.getChatData(chatToGet).then(chat => {
1563
- xhr.open('GET', `${ endpoints.openAI.chat }/${ chat.id }`, true);
1559
+ xhr.open('GET', `${ chatgpt.endpoints.openAI.chat }/${ chat.id }`, true);
1564
1560
  xhr.setRequestHeader('Content-Type', 'application/json');
1565
1561
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
1566
1562
  xhr.onload = () => {
@@ -1575,7 +1571,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1575
1571
  return new Promise((resolve, reject) => {
1576
1572
  const xhr = new XMLHttpRequest();
1577
1573
  chatgpt.getChatData(chatToGet).then(chat => {
1578
- xhr.open('POST', endpoints.openAI.share_create, true);
1574
+ xhr.open('POST', chatgpt.endpoints.openAI.share_create, true);
1579
1575
  xhr.setRequestHeader('Content-Type', 'application/json');
1580
1576
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
1581
1577
  xhr.onload = () => {
@@ -1593,7 +1589,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1593
1589
  const confirmShareChat = (token, data) => {
1594
1590
  return new Promise((resolve, reject) => {
1595
1591
  const xhr = new XMLHttpRequest();
1596
- xhr.open('PATCH', `${ endpoints.openAI.share }/${ data.share_id }`, true);
1592
+ xhr.open('PATCH', `${ chatgpt.endpoints.openAI.share }/${ data.share_id }`, true);
1597
1593
  xhr.setRequestHeader('Content-Type', 'application/json');
1598
1594
  xhr.setRequestHeader('Authorization', 'Bearer ' + token);
1599
1595
  xhr.onload = () => {
@@ -1703,7 +1699,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1703
1699
  const icon = document.createElement('img');
1704
1700
  icon.src = attrs?.icon && typeof attrs.icon == 'string' // Can also be base64 encoded image string
1705
1701
  ? attrs.icon // Add icon to button element if given, else default one
1706
- : ( endpoints.assets + '/starters/chrome/extension/icons/icon128.png' );
1702
+ : ( chatgpt.endpoints.assets + '/starters/chrome/extension/icons/icon128.png' );
1707
1703
  icon.width = 18;
1708
1704
  newElement.insertBefore(icon, newElement.firstChild);
1709
1705
 
@@ -1752,12 +1748,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1752
1748
 
1753
1749
  toggle: function() {
1754
1750
  const isMobileDevice = chatgpt.browser.isMobile(),
1755
- isGPT4oUI = !!document.documentElement.className.includes(' '),
1756
- navBtnSelector = isMobileDevice ? '#__next button' : isGPT4oUI ? 'nav button' : 'main button',
1751
+ navBtnSelector = isMobileDevice ? '#__next button' : 'nav button',
1757
1752
  isToggleBtn = isMobileDevice ? () => true // since 1st one is toggle
1758
- : isGPT4oUI ? btn => btn.querySelectorAll('svg path[d*="M8.857 3h6.286c1.084"]').length > 0
1759
- : /* post-GPT-4o desktop */ btn => [...btn.querySelectorAll('*')]
1760
- .some(child => child.style.transform.includes('translateY'));
1753
+ : btn => btn.querySelectorAll('svg path[d*="M8.857 3h6.286c1.084"]').length > 0;
1761
1754
  for (const btn of document.querySelectorAll(navBtnSelector))
1762
1755
  if (isToggleBtn(btn)) { btn.click(); return; }
1763
1756
  },
@@ -1767,8 +1760,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1767
1760
  return Promise.race([
1768
1761
  new Promise(resolve => {
1769
1762
  (function checkNewChatLink() {
1770
- if (chatgpt.getNewChatLink()) resolve(true);
1771
- else setTimeout(checkNewChatLink, 200);
1763
+ chatgpt.getNewChatLink() ? resolve(true) : setTimeout(checkNewChatLink, 200);
1772
1764
  })();
1773
1765
  }),
1774
1766
  new Promise(resolve => setTimeout(resolve, 5000)) // since New Chat link not always present
@@ -1859,9 +1851,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1859
1851
  chatgpt.scheme = { ...chatgpt.settings.scheme }; // copy `chatgpt.settings.scheme` methods into `chatgpt.scheme`
1860
1852
 
1861
1853
  // Create chatgpt.[actions]Button(identifier) functions
1862
- const buttonActions = ['click', 'get'], targetTypes = [ 'button', 'link', 'div', 'response' ];
1863
- for (const buttonAction of buttonActions) {
1864
- chatgpt[buttonAction + 'Button'] = function handleButton(buttonIdentifier) {
1854
+ const cjsBtnActions = ['click', 'get'], cjsTargetTypes = [ 'button', 'link', 'div', 'response' ];
1855
+ for (const btnAction of cjsBtnActions) {
1856
+ chatgpt[btnAction + 'Button'] = function handleButton(buttonIdentifier) {
1865
1857
  const button = /^[.#]/.test(buttonIdentifier) ? document.querySelector(buttonIdentifier)
1866
1858
  : /send/i.test(buttonIdentifier) ? document.querySelector('form button[class*="bottom"]')
1867
1859
  : /scroll/i.test(buttonIdentifier) ? document.querySelector('button[class*="cursor"]')
@@ -1872,12 +1864,12 @@ for (const buttonAction of buttonActions) {
1872
1864
  for (const navLink of document.querySelectorAll('nav a')) { // try nav links if no button
1873
1865
  if (navLink.textContent.toLowerCase().includes(buttonIdentifier.toLowerCase())) {
1874
1866
  return navLink; }}})();
1875
- if (buttonAction == 'click') { button.click(); } else { return button; }
1867
+ if (btnAction == 'click') { button.click(); } else { return button; }
1876
1868
  };
1877
1869
  }
1878
1870
 
1879
1871
  // Create alias functions
1880
- const funcAliases = [
1872
+ const cjsFuncAliases = [
1881
1873
  ['actAs', 'actas', 'act', 'become', 'persona', 'premadePrompt', 'preMadePrompt', 'prePrompt', 'preprompt', 'roleplay', 'rolePlay', 'rp'],
1882
1874
  ['activateAutoRefresh', 'activateAutoRefresher', 'activateRefresher', 'activateSessionRefresher',
1883
1875
  'autoRefresh', 'autoRefresher', 'autoRefreshSession', 'refresher', 'sessionRefresher'],
@@ -1917,7 +1909,7 @@ const funcAliases = [
1917
1909
  ['unminify', 'unminifyCode', 'codeUnminify'],
1918
1910
  ['writeCode', 'codeWrite']
1919
1911
  ];
1920
- const synonyms = [
1912
+ const cjsFuncSynonyms = [
1921
1913
  ['account', 'acct'],
1922
1914
  ['activate', 'turnOn'],
1923
1915
  ['analyze', 'check', 'evaluate', 'review'],
@@ -1930,6 +1922,7 @@ const synonyms = [
1930
1922
  ['data', 'details'],
1931
1923
  ['deactivate', 'deActivate', 'turnOff'],
1932
1924
  ['execute', 'interpret', 'interpreter', 'run'],
1925
+ ['firefox', 'ff'],
1933
1926
  ['generating', 'generation'],
1934
1927
  ['minify', 'uglify'],
1935
1928
  ['refactor', 'rewrite'],
@@ -1946,7 +1939,7 @@ const camelCaser = (words) => {
1946
1939
  for (const prop in chatgpt) {
1947
1940
 
1948
1941
  // Create new function for each alias
1949
- for (const subAliases of funcAliases) {
1942
+ for (const subAliases of cjsFuncAliases) {
1950
1943
  if (subAliases.includes(prop)) {
1951
1944
  if (subAliases.some(element => element.includes('.'))) {
1952
1945
  const nestedFunction = subAliases.find(element => element.includes('.')).split('.')[1];
@@ -1966,7 +1959,7 @@ for (const prop in chatgpt) {
1966
1959
  if (typeof chatgpt[funcName] == 'function') {
1967
1960
  const funcWords = funcName.split(/(?=[A-Zs])/); // split function name into constituent words
1968
1961
  for (const funcWord of funcWords) {
1969
- const synonymValues = [].concat(...synonyms // flatten into single array w/ word's synonyms
1962
+ const synonymValues = [].concat(...cjsFuncSynonyms // flatten into single array w/ word's cjsFuncSynonyms
1970
1963
  .filter(arr => arr.includes(funcWord.toLowerCase())) // filter in relevant synonym sub-arrays
1971
1964
  .map(arr => arr.filter(synonym => synonym !== funcWord.toLowerCase()))); // filter out matching word
1972
1965
  for (const synonym of synonymValues) { // create function per synonym