@kudoai/chatgpt.js 3.0.0 → 3.0.2

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.
@@ -20,7 +20,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
20
20
  instructions: 'https://chatgpt.com/backend-api/user_system_messages'
21
21
  }},
22
22
 
23
- actAs: function(persona) {
23
+ actAs(persona) {
24
24
  // Prompts ChatGPT to act as a persona from https://github.com/KudoAI/chat-prompts/blob/main/personas.json
25
25
 
26
26
  const promptsUrl = 'https://raw.githubusercontent.com/KudoAI/chat-prompts/main/dist/personas.min.json';
@@ -48,19 +48,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
48
48
  });
49
49
  },
50
50
 
51
- activateDarkMode: function() {
51
+ activateDarkMode() {
52
52
  document.documentElement.classList.replace('light', 'dark');
53
53
  document.documentElement.style.colorScheme = 'dark';
54
54
  localStorage.setItem('theme', 'dark');
55
55
  },
56
56
 
57
- activateLightMode: function() {
57
+ activateLightMode() {
58
58
  document.documentElement.classList.replace('dark', 'light');
59
59
  document.documentElement.style.colorScheme = 'light';
60
60
  localStorage.setItem('theme', 'light');
61
61
  },
62
62
 
63
- alert: function(title, msg, btns, checkbox, width) {
63
+ alert(title, msg, btns, checkbox, width) {
64
64
  // [ title/msg = strings, btns = [named functions], checkbox = named function, width (px) = int ] = optional
65
65
  // * Spaces are inserted into button labels by parsing function names in camel/kebab/snake case
66
66
 
@@ -288,7 +288,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
288
288
  },
289
289
 
290
290
  autoRefresh: {
291
- activate: function(interval) {
291
+ activate(interval) {
292
292
  if (this.isActive) { // already running, do nothing
293
293
  console.log('↻ ChatGPT >> [' + chatgpt.autoRefresh.nowTimeStamp() + '] Auto refresh already active!'); return; }
294
294
 
@@ -313,7 +313,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
313
313
  document.addEventListener('visibilitychange', this.toggle.beacons); }
314
314
  },
315
315
 
316
- deactivate: function() {
316
+ deactivate() {
317
317
  if (this.isActive) {
318
318
  this.toggle.refreshFrame();
319
319
  document.removeEventListener('visibilitychange', this.toggle.beacons);
@@ -322,7 +322,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
322
322
  } else { console.log('↻ ChatGPT >> [' + chatgpt.autoRefresh.nowTimeStamp() + '] Auto refresh already inactive!'); }
323
323
  },
324
324
 
325
- nowTimeStamp: function() {
325
+ nowTimeStamp() {
326
326
  const now = new Date();
327
327
  const hours = now.getHours() % 12 || 12; // Convert to 12-hour format
328
328
  let minutes = now.getMinutes(), seconds = now.getSeconds();
@@ -333,7 +333,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
333
333
 
334
334
  toggle: {
335
335
 
336
- beacons: function() {
336
+ beacons() {
337
337
  if (chatgpt.autoRefresh.beaconID) {
338
338
  clearInterval(chatgpt.autoRefresh.beaconID); chatgpt.autoRefresh.beaconID = null;
339
339
  console.log('↻ ChatGPT >> [' + chatgpt.autoRefresh.nowTimeStamp() + '] Beacons de-activated');
@@ -346,7 +346,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
346
346
  }
347
347
  },
348
348
 
349
- refreshFrame: function() {
349
+ refreshFrame() {
350
350
  let refreshFrame = document.querySelector('#refresh-frame');
351
351
  if (refreshFrame) refreshFrame.remove();
352
352
  else {
@@ -360,22 +360,22 @@ const chatgpt = { // eslint-disable-line no-redeclare
360
360
 
361
361
  browser: {
362
362
 
363
- isLightMode: function() { return window.matchMedia?.('(prefers-color-scheme: light)')?.matches; },
364
- isDarkMode: function() { return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches; },
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'); },
369
- isFirefox: function() { return navigator.userAgent.includes('Firefox'); },
363
+ isLightMode() { return window.matchMedia?.('(prefers-color-scheme: light)')?.matches; },
364
+ isDarkMode() { return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches; },
365
+ isChromium() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Chromium'); },
366
+ isChrome() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Chrome'); },
367
+ isEdge() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Edge'); },
368
+ isBrave() { return !!JSON.stringify(navigator.userAgentData?.brands)?.includes('Brave'); },
369
+ isFirefox() { return navigator.userAgent.includes('Firefox'); },
370
370
 
371
- isFullScreen: function() {
371
+ isFullScreen() {
372
372
  const userAgentStr = navigator.userAgent;
373
373
  return userAgentStr.includes('Chrome') ? window.matchMedia('(display-mode: fullscreen)').matches
374
374
  : userAgentStr.includes('Firefox') ? window.fullScreen
375
375
  : /MSIE|rv:/.test(userAgentStr) ? document.msFullscreenElement : document.webkitIsFullScreen;
376
376
  },
377
377
 
378
- isMobile: function() {
378
+ isMobile() {
379
379
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); }
380
380
  },
381
381
 
@@ -407,7 +407,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
407
407
  return chatgpt.code.extract(await chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'));
408
408
  },
409
409
 
410
- extract: function(msg) { // extract pure code from response (targets last block)
410
+ extract(msg) { // extract pure code from response (targets last block)
411
411
  const codeBlocks = msg.match(/(?<=```.*\n)[\s\S]*?(?=```)/g);
412
412
  return codeBlocks ? codeBlocks[codeBlocks.length - 1] : msg;
413
413
  },
@@ -498,7 +498,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
498
498
  }
499
499
  },
500
500
 
501
- continue: function() { chatgpt.response.continue(); },
501
+ continue() { chatgpt.response.continue(); },
502
502
 
503
503
  detectLanguage: async function(text) {
504
504
  if (!text) return console.error('Text argument not supplied. Pass some text!');
@@ -510,7 +510,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
510
510
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest');
511
511
  },
512
512
 
513
- executeCode: function() { chatgpt.code.execute(); },
513
+ executeCode() { chatgpt.code.execute(); },
514
514
 
515
515
  exportChat: async function(chatToGet, format) {
516
516
  // chatToGet = 'active' (default) | 'latest' | index|title|id of chat to get
@@ -609,16 +609,16 @@ const chatgpt = { // eslint-disable-line no-redeclare
609
609
  }
610
610
  },
611
611
 
612
- extractCode: function() { chatgpt.code.extract(); },
613
- focusChatbar: function() { chatgpt.getChatBox()?.focus(); },
612
+ extractCode() { chatgpt.code.extract(); },
613
+ focusChatbar() { chatgpt.getChatBox()?.focus(); },
614
614
 
615
- generateRandomIP: function() {
615
+ generateRandomIP() {
616
616
  const ip = Array.from({length: 4}, () => Math.floor(chatgpt.randomFloat() * 256)).join('.');
617
617
  console.info('IP generated: ' + ip);
618
618
  return ip;
619
619
  },
620
620
 
621
- get: function(targetType, targetName = '') {
621
+ get(targetType, targetName = '') {
622
622
  // targetType = 'button'|'link'|'div'|'response'
623
623
  // targetName = from get[targetName][targetType] methods, e.g. 'send'
624
624
 
@@ -651,7 +651,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
651
651
  return this[targetFuncName](); // call found function
652
652
  },
653
653
 
654
- getAccessToken: function() {
654
+ getAccessToken() {
655
655
  return new Promise((resolve, reject) => {
656
656
  if (Object.keys(chatgpt.openAIaccessToken).length > 0 && // populated
657
657
  (Date.parse(chatgpt.openAIaccessToken.expireDate) - Date.parse(new Date()) >= 0)) // not expired
@@ -672,7 +672,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
672
672
  });
673
673
  },
674
674
 
675
- getAccountDetails: function(...details) {
675
+ getAccountDetails(...details) {
676
676
  // details = [email|id|image|name|picture] = optional
677
677
 
678
678
  // Build details array
@@ -703,9 +703,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
703
703
  });
704
704
  },
705
705
 
706
- getChatBox: function() { return document.getElementById('prompt-textarea'); },
706
+ getChatBox() { return document.getElementById('prompt-textarea'); },
707
707
 
708
- getChatData: function(chatToGet = 1, detailsToGet = 'all', sender = 'all', msgToGet = 'all') {
708
+ getChatData(chatToGet = 1, detailsToGet = 'all', sender = 'all', msgToGet = 'all') {
709
709
  // chatToGet = 'active' | 'latest' | index|title|id of chat to get (defaults to active OpenAI chat > latest chat)
710
710
  // detailsToGet = 'all' | [ 'id' | 'title' | 'create_time' | 'update_time' | 'msg' ] (defaults to 'all', excludes msg's)
711
711
  // sender = ( 'all' | 'both' ) | 'user' | 'chatgpt' (defaults to 'all', requires 2nd param = 'msg')
@@ -856,35 +856,35 @@ const chatgpt = { // eslint-disable-line no-redeclare
856
856
  }));
857
857
  },
858
858
 
859
- getChatInput: function() { return chatgpt.getChatBox().value; },
859
+ getChatInput() { return chatgpt.getChatBox().value; },
860
860
 
861
- getContinueGeneratingButton: function() {
861
+ getContinueGeneratingButton() {
862
862
  for (const formBtnSVG of document.querySelectorAll('form button svg')) {
863
863
  if (formBtnSVG.querySelector('path[d*="M4.472 2.5a1"]'))
864
864
  return formBtnSVG.parentNode.parentNode;
865
865
  }},
866
866
 
867
- getFooterDiv: function() { return document.querySelector('main form').parentNode.parentNode.nextElementSibling; },
868
- getHeaderDiv: function() { return document.querySelector('main .sticky'); },
869
- getLastPrompt: function() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
870
- getLastResponse: function() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
867
+ getFooterDiv() { return document.querySelector('main form').parentNode.parentNode.nextElementSibling; },
868
+ getHeaderDiv() { return document.querySelector('main .sticky'); },
869
+ getLastPrompt() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
870
+ getLastResponse() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
871
871
 
872
- getNewChatButton: function() {
872
+ getNewChatButton() {
873
873
  for (const navBtnSVG of document.querySelectorAll('nav button svg'))
874
874
  if (navBtnSVG.querySelector('path[d*="M15.673 3.913a3.121"], ' // pencil-on-pad icon
875
875
  + 'path[d*="M3.07 10.876C3.623"]')) // refresh icon if temp chat
876
876
  return navBtnSVG.parentNode;
877
877
  },
878
878
 
879
- getNewChatLink: function() { return document.querySelector('nav a[href="/"]'); },
879
+ getNewChatLink() { return document.querySelector('nav a[href="/"]'); },
880
880
 
881
- getRegenerateButton: function() {
881
+ getRegenerateButton() {
882
882
  for (const mainSVG of document.querySelectorAll('main svg')) {
883
883
  if (mainSVG.querySelector('path[d*="M3.07 10.876C3.623"]')) // regen icon found
884
884
  return mainSVG.parentNode;
885
885
  }},
886
886
 
887
- getResponse: function() {
887
+ getResponse() {
888
888
  // * Returns response via DOM by index arg if OpenAI chat page is active, otherwise uses API w/ following args:
889
889
  // chatToGet = index|title|id of chat to get (defaults to latest if '' unpassed)
890
890
  // responseToGet = index of response to get (defaults to latest if '' unpassed)
@@ -893,30 +893,30 @@ const chatgpt = { // eslint-disable-line no-redeclare
893
893
  return chatgpt.response.get(...arguments);
894
894
  },
895
895
 
896
- getResponseFromAPI: function(chatToGet, responseToGet) { return chatgpt.response.getFromAPI(chatToGet, responseToGet); },
897
- getResponseFromDOM: function(pos) { return chatgpt.response.getFromDOM(pos); },
898
- getScrollToBottomButton: function() { return document.querySelector('button[class*="cursor"][class*="bottom"]'); },
896
+ getResponseFromAPI(chatToGet, responseToGet) { return chatgpt.response.getFromAPI(chatToGet, responseToGet); },
897
+ getResponseFromDOM(pos) { return chatgpt.response.getFromDOM(pos); },
898
+ getScrollToBottomButton() { return document.querySelector('button[class*="cursor"][class*="bottom"]'); },
899
899
 
900
- getSendButton: function() {
900
+ getSendButton() {
901
901
  return document.querySelector('[data-testid="send-button"]') // pre-GPT-4o
902
902
  || document.querySelector('path[d*="M15.192 8.906a1.143"]')?.parentNode.parentNode; // post-GPT-4o
903
903
  },
904
904
 
905
- getStopGeneratingButton: function() {
905
+ getStopGeneratingButton() {
906
906
  for (const svg of document.querySelectorAll('form button svg')) {
907
907
  if (svg.querySelector('path[d*="2 0 0 1 2"], rect'))
908
908
  return svg.parentNode;
909
909
  }},
910
910
 
911
- getUserLanguage: function() {
911
+ getUserLanguage() {
912
912
  return navigator.languages[0] || navigator.language || navigator.browserLanguage ||
913
913
  navigator.systemLanguage || navigator.userLanguage || ''; },
914
914
 
915
- hideFooter: function() { chatgpt.getFooterDiv().style.display = 'none'; },
916
- hideHeader: function() { chatgpt.getHeaderDiv().style.display = 'none'; },
915
+ hideFooter() { chatgpt.getFooterDiv().style.display = 'none'; },
916
+ hideHeader() { chatgpt.getHeaderDiv().style.display = 'none'; },
917
917
 
918
918
  history: {
919
- isLoaded: function() {
919
+ isLoaded() {
920
920
  return new Promise(resolve => {
921
921
  (function checkChatHistory() {
922
922
  document.querySelector('nav') ? resolve(true) : setTimeout(checkChatHistory, 200);
@@ -927,7 +927,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
927
927
  instructions: {
928
928
  // NOTE: DOM is not updated to reflect new instructions added/removed or toggle state (until session refresh)
929
929
 
930
- add: function(instruction, target) {
930
+ add(instruction, target) {
931
931
  if (!instruction) return console.error('Please provide an instruction');
932
932
  if (typeof instruction !== 'string') return console.error('Instruction must be a string');
933
933
  const validTargets = ['user', 'chatgpt']; // valid targets
@@ -953,7 +953,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
953
953
  });
954
954
  },
955
955
 
956
- clear: function(target) {
956
+ clear(target) {
957
957
  const validTargets = ['user', 'chatgpt']; // valid targets
958
958
  if (!target) return console.error('Please provide a valid target!');
959
959
  if (typeof target !== 'string') return console.error('Target must be a string');
@@ -974,7 +974,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
974
974
  });});
975
975
  },
976
976
 
977
- fetchData: function() {
977
+ fetchData() {
978
978
  // INTERNAL METHOD
979
979
  return new Promise(resolve => {
980
980
  chatgpt.getAccessToken().then(async token => {
@@ -982,7 +982,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
982
982
  });});
983
983
  },
984
984
 
985
- sendRequest: function(method, token, body) {
985
+ sendRequest(method, token, body) {
986
986
  // INTERNAL METHOD
987
987
  // Validate args
988
988
  for (let i = 0; i < arguments.length - 1; i++) if (typeof arguments[i] !== 'string')
@@ -1018,7 +1018,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1018
1018
  });
1019
1019
  },
1020
1020
 
1021
- turnOff: function() {
1021
+ turnOff() {
1022
1022
  return new Promise(resolve => {
1023
1023
  chatgpt.getAccessToken().then(async token => {
1024
1024
  const instructionsData = await this.fetchData();
@@ -1029,7 +1029,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1029
1029
  });
1030
1030
  },
1031
1031
 
1032
- turnOn: function() {
1032
+ turnOn() {
1033
1033
  return new Promise(resolve => {
1034
1034
  chatgpt.getAccessToken().then(async token => {
1035
1035
  const instructionsData = await this.fetchData();
@@ -1040,7 +1040,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1040
1040
  });
1041
1041
  },
1042
1042
 
1043
- toggle: function() {
1043
+ toggle() {
1044
1044
  return new Promise(resolve => {
1045
1045
  this.fetchData().then(async instructionsData => {
1046
1046
  await (instructionsData.enabled ? this.turnOff() : this.turnOn());
@@ -1049,32 +1049,32 @@ const chatgpt = { // eslint-disable-line no-redeclare
1049
1049
  }
1050
1050
  },
1051
1051
 
1052
- isDarkMode: function() { return document.documentElement.classList.toString().includes('dark'); },
1053
- isFullScreen: function() { return chatgpt.browser.isFullScreen(); },
1052
+ isDarkMode() { return document.documentElement.classList.toString().includes('dark'); },
1053
+ isFullScreen() { return chatgpt.browser.isFullScreen(); },
1054
1054
 
1055
- isIdle: function() {
1055
+ isIdle() {
1056
1056
  return new Promise(resolve => {
1057
1057
  (function checkIsIdle() {
1058
1058
  chatgpt.getRegenerateButton() ? resolve(true) : setTimeout(checkIsIdle, 200);
1059
1059
  })();
1060
1060
  });},
1061
1061
 
1062
- isLoaded: function() {
1062
+ isLoaded() {
1063
1063
  return new Promise(resolve => {
1064
1064
  (function checkIsLoaded() {
1065
1065
  chatgpt.getNewChatButton() ? resolve(true) : setTimeout(checkIsLoaded, 200);
1066
1066
  })();
1067
1067
  });},
1068
1068
 
1069
- isLightMode: function() { return document.documentElement.classList.toString().includes('light'); },
1069
+ isLightMode() { return document.documentElement.classList.toString().includes('light'); },
1070
1070
 
1071
- logout: function() { window.location.href = 'https://chat.openai.com/auth/logout'; },
1071
+ logout() { window.location.href = 'https://chat.openai.com/auth/logout'; },
1072
1072
 
1073
1073
  menu: {
1074
1074
  elements: [],
1075
1075
  addedEvent: false,
1076
1076
 
1077
- append: function(element, attrs = {}) {
1077
+ append(element, attrs = {}) {
1078
1078
  // element = 'button' | 'dropdown' REQUIRED (no default value)
1079
1079
  // attrs = { ... }
1080
1080
  // attrs for 'button': 'icon' = src string, 'label' = string, 'onclick' = function
@@ -1158,18 +1158,18 @@ const chatgpt = { // eslint-disable-line no-redeclare
1158
1158
  return newElement.id; // Return the element id
1159
1159
  },
1160
1160
 
1161
- close: function() {
1161
+ close() {
1162
1162
  try { document.querySelector('nav [id*="menu-button"][aria-expanded="true"]').click(); }
1163
1163
  catch (err) { console.error(err.message); }
1164
1164
  },
1165
1165
 
1166
- open: function() {
1166
+ open() {
1167
1167
  try { document.querySelector('nav [id*="menu-button"][aria-expanded="false"]').click(); }
1168
1168
  catch (err) { console.error(err.message); }
1169
1169
  }
1170
1170
  },
1171
1171
 
1172
- minify: function() { chatgpt.code.minify(); },
1172
+ minify() { chatgpt.code.minify(); },
1173
1173
 
1174
1174
  notify: async function(msg, position, notifDuration, shadow) {
1175
1175
  notifDuration = notifDuration ? +notifDuration : 1.75; // sec duration to maintain notification visibility
@@ -1281,9 +1281,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1281
1281
  }, { once: true });
1282
1282
  },
1283
1283
 
1284
- obfuscate: function() { chatgpt.code.obfuscate(); },
1284
+ obfuscate() { chatgpt.code.obfuscate(); },
1285
1285
 
1286
- printAllFunctions: function() {
1286
+ printAllFunctions() {
1287
1287
 
1288
1288
  // Define colors
1289
1289
  const colors = { // element: [light, dark]
@@ -1349,16 +1349,16 @@ const chatgpt = { // eslint-disable-line no-redeclare
1349
1349
  }
1350
1350
  },
1351
1351
 
1352
- randomFloat: function() {
1352
+ randomFloat() {
1353
1353
  // * Generates a random, cryptographically secure value between 0 (inclusive) & 1 (exclusive)
1354
1354
  const crypto = window.crypto || window.msCrypto;
1355
1355
  return crypto?.getRandomValues(new Uint32Array(1))[0] / 0xFFFFFFFF || Math.random();
1356
1356
  },
1357
1357
 
1358
- refactor: function() { chatgpt.code.refactor(); },
1359
- regenerate: function() { chatgpt.response.regenerate(); },
1358
+ refactor() { chatgpt.code.refactor(); },
1359
+ regenerate() { chatgpt.response.regenerate(); },
1360
1360
 
1361
- renderHTML: function(node) {
1361
+ renderHTML(node) {
1362
1362
  const reTags = /<([a-z\d]+)\b([^>]*)>([\s\S]*?)<\/\1>/g,
1363
1363
  reAttributes = /(\S+)=['"]?((?:.(?!['"]?\s+\S+=|[>']))+.)['"]?/g,
1364
1364
  nodeContent = node.childNodes;
@@ -1412,9 +1412,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1412
1412
  resend: async function() { chatgpt.send(await chatgpt.getChatData('latest', 'msg', 'user', 'latest')); },
1413
1413
 
1414
1414
  response: {
1415
- continue: function() { try { chatgpt.getContinueBtn().click(); } catch (err) { console.error(err.message); }},
1415
+ continue() { try { chatgpt.getContinueBtn().click(); } catch (err) { console.error(err.message); }},
1416
1416
 
1417
- get: function() {
1417
+ get() {
1418
1418
  // * Returns response via DOM by index arg if OpenAI chat page is active, otherwise uses API w/ following args:
1419
1419
  // chatToGet = index|title|id of chat to get (defaults to latest if '' unpassed)
1420
1420
  // responseToGet = index of response to get (defaults to latest if '' unpassed)
@@ -1425,7 +1425,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1425
1425
  else return this.getFromAPI.apply(null, arguments);
1426
1426
  },
1427
1427
 
1428
- getFromAPI: function(chatToGet, responseToGet) {
1428
+ getFromAPI(chatToGet, responseToGet) {
1429
1429
  // chatToGet = index|title|id of chat to get (defaults to latest if '' or unpassed)
1430
1430
  // responseToGet = index of response to get (defaults to latest if '' or unpassed)
1431
1431
 
@@ -1433,7 +1433,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1433
1433
  return chatgpt.getChatData(chatToGet, 'msg', 'chatgpt', responseToGet);
1434
1434
  },
1435
1435
 
1436
- getFromDOM: function(pos) {
1436
+ getFromDOM(pos) {
1437
1437
  const responseDivs = document.querySelectorAll('div[data-testid*="conversation-turn"]:nth-child(odd)'),
1438
1438
  strPos = pos.toString().toLowerCase();
1439
1439
  let response = '';
@@ -1470,15 +1470,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
1470
1470
  return response;
1471
1471
  },
1472
1472
 
1473
- getLast: function() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
1474
- regenerate: function() { try { chatgpt.getRegenerateBtn().click(); } catch (err) { console.error(err.message); }},
1475
- stopGenerating: function() { try { chatgpt.getStopBtn().click(); } catch (err) { console.error(err.message); }}
1473
+ getLast() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
1474
+ regenerate() { try { chatgpt.getRegenerateBtn().click(); } catch (err) { console.error(err.message); }},
1475
+ stopGenerating() { try { chatgpt.getStopBtn().click(); } catch (err) { console.error(err.message); }}
1476
1476
  },
1477
1477
 
1478
- reviewCode: function() { chatgpt.code.review(); },
1479
- scrollToBottom: function() { try { chatgpt.getScrollBtn().click(); } catch (err) { console.error(err.message); }},
1478
+ reviewCode() { chatgpt.code.review(); },
1479
+ scrollToBottom() { try { chatgpt.getScrollBtn().click(); } catch (err) { console.error(err.message); }},
1480
1480
 
1481
- send: function(msg, method='') {
1481
+ send(msg, method='') {
1482
1482
  for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] !== 'string')
1483
1483
  return console.error(`Argument ${ i + 1 } must be a string!`);
1484
1484
  const textArea = document.querySelector('form textarea'),
@@ -1494,7 +1494,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1494
1494
  }, 25);
1495
1495
  },
1496
1496
 
1497
- sendInNewChat: function(msg) {
1497
+ sendInNewChat(msg) {
1498
1498
  if (typeof msg !== 'string') return console.error('Message must be a string!');
1499
1499
  for (const navLink of document.querySelectorAll('nav a')) {
1500
1500
  if (/(new|clear) chat/i.test(navLink.text)) {
@@ -1504,9 +1504,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1504
1504
 
1505
1505
  settings: {
1506
1506
  scheme: {
1507
- isDark: function() { return document.documentElement.classList.contains('dark'); },
1508
- isLight: function() { return document.documentElement.classList.contains('light'); },
1509
- set: function(value) {
1507
+ isDark() { return document.documentElement.classList.contains('dark'); },
1508
+ isLight() { return document.documentElement.classList.contains('light'); },
1509
+ set(value) {
1510
1510
 
1511
1511
  // Validate value
1512
1512
  const validValues = ['dark', 'light', 'system'];
@@ -1522,7 +1522,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1522
1522
  // Toggle scheme if necessary
1523
1523
  if (!document.documentElement.classList.contains(schemeToSet)) this.toggle();
1524
1524
  },
1525
- toggle: function() {
1525
+ toggle() {
1526
1526
  const [schemeToRemove, schemeToAdd] = this.isDark() ? ['dark', 'light'] : ['light', 'dark'];
1527
1527
  document.documentElement.classList.replace(schemeToRemove, schemeToAdd);
1528
1528
  document.documentElement.style.colorScheme = schemeToAdd;
@@ -1542,9 +1542,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1542
1542
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest');
1543
1543
  },
1544
1544
 
1545
- setScheme: function(value) { chatgpt.settings.scheme.set(value); },
1545
+ setScheme(value) { chatgpt.settings.scheme.set(value); },
1546
1546
 
1547
- shareChat: function(chatToGet, method = 'clipboard') {
1547
+ shareChat(chatToGet, method = 'clipboard') {
1548
1548
  // chatToGet = index|title|id of chat to get (defaults to latest if '' or unpassed)
1549
1549
  // method = [ 'alert'|'clipboard' ] (defaults to 'clipboard' if '' or unpassed)
1550
1550
 
@@ -1623,13 +1623,13 @@ const chatgpt = { // eslint-disable-line no-redeclare
1623
1623
  });});});});});
1624
1624
  },
1625
1625
 
1626
- showFooter: function() { chatgpt.getFooterDiv().style.display = 'revert'; },
1627
- showHeader: function() { chatgpt.getHeaderDiv().style.display = 'flex'; },
1626
+ showFooter() { chatgpt.getFooterDiv().style.display = 'revert'; },
1627
+ showHeader() { chatgpt.getHeaderDiv().style.display = 'flex'; },
1628
1628
 
1629
1629
  sidebar: {
1630
1630
  elements: [], observer: {},
1631
1631
 
1632
- activateObserver: function() {
1632
+ activateObserver() {
1633
1633
 
1634
1634
  // Stop the previous observer to preserve resources
1635
1635
  if (this.observer instanceof MutationObserver)
@@ -1675,7 +1675,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1675
1675
  this.observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
1676
1676
  },
1677
1677
 
1678
- append: function(element, attrs = {}) {
1678
+ append(element, attrs = {}) {
1679
1679
  // element = 'button' | 'dropdown' REQUIRED (no default value)
1680
1680
  // attrs = { ... }
1681
1681
  // attrs for 'button': 'icon' = src string, 'label' = string, 'onclick' = function
@@ -1736,21 +1736,21 @@ const chatgpt = { // eslint-disable-line no-redeclare
1736
1736
  return newElement.id; // Return the element id
1737
1737
  },
1738
1738
 
1739
- hide: function() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!'); },
1740
- show: function() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1741
- isOff: function() { return !this.isOn(); },
1742
- isOn: function() {
1743
- const sidebar = document.querySelector('#__next > div > div');
1739
+ hide() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!'); },
1740
+ show() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1741
+ isOff() { return !this.isOn(); },
1742
+ isOn() {
1743
+ const sidebar = document.querySelector('body script + div > div');
1744
1744
  return chatgpt.browser.isMobile() ?
1745
1745
  document.documentElement.style.overflow == 'hidden'
1746
1746
  : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px';
1747
1747
  },
1748
1748
 
1749
- toggle: function() {
1749
+ toggle() {
1750
1750
  const isMobileDevice = chatgpt.browser.isMobile(),
1751
- navBtnSelector = isMobileDevice ? '#__next button' : 'nav button',
1751
+ navBtnSelector = isMobileDevice ? 'button' : 'nav button',
1752
1752
  isToggleBtn = isMobileDevice ? () => true // since 1st one is toggle
1753
- : btn => btn.querySelectorAll('svg path[d*="M8.857 3h6.286c1.084"]').length > 0;
1753
+ : btn => btn.querySelector('svg path[d*="M8.857 3h6.286c1.084"]');
1754
1754
  for (const btn of document.querySelectorAll(navBtnSelector))
1755
1755
  if (isToggleBtn(btn)) { btn.click(); return; }
1756
1756
  },
@@ -1768,8 +1768,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1768
1768
  }
1769
1769
  },
1770
1770
 
1771
- startNewChat: function() { try { chatgpt.getNewChatBtn().click(); } catch (err) { console.error(err.message); }},
1772
- stop: function() { chatgpt.response.stopGenerating(); },
1771
+ startNewChat() { try { chatgpt.getNewChatBtn().click(); } catch (err) { console.error(err.message); }},
1772
+ stop() { chatgpt.response.stopGenerating(); },
1773
1773
 
1774
1774
  suggest: async function(ideaType, details) {
1775
1775
  if (!ideaType) return console.error('ideaType (1st argument) not supplied'
@@ -1782,7 +1782,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1782
1782
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest');
1783
1783
  },
1784
1784
 
1785
- speak: function(msg, options = {}) {
1785
+ speak(msg, options = {}) {
1786
1786
  // Usage example: chatgpt.speak(await chatgpt.getLastResponse(), { voice: 1, pitch: 2, speed: 3 })
1787
1787
  // options.voice = index of voices available on user device
1788
1788
  // options.pitch = float for pitch of speech from 0 to 2
@@ -1818,7 +1818,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1818
1818
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest');
1819
1819
  },
1820
1820
 
1821
- toggleScheme: function() { chatgpt.settings.scheme.toggle(); },
1821
+ toggleScheme() { chatgpt.settings.scheme.toggle(); },
1822
1822
 
1823
1823
  translate: async function(text, outputLang) {
1824
1824
  if (!text) return console.error('Text (1st) argument not supplied. Pass some text!');
@@ -1832,9 +1832,9 @@ const chatgpt = { // eslint-disable-line no-redeclare
1832
1832
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest');
1833
1833
  },
1834
1834
 
1835
- unminify: function() { chatgpt.code.unminify(); },
1835
+ unminify() { chatgpt.code.unminify(); },
1836
1836
 
1837
- uuidv4: function() {
1837
+ uuidv4() {
1838
1838
  let d = new Date().getTime(); // get current timestamp in ms (to ensure UUID uniqueness)
1839
1839
  const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
1840
1840
  const r = ( // generate random nibble
@@ -1845,7 +1845,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
1845
1845
  return uuid;
1846
1846
  },
1847
1847
 
1848
- writeCode: function() { chatgpt.code.write(); }
1848
+ writeCode() { chatgpt.code.write(); }
1849
1849
  };
1850
1850
 
1851
1851
  chatgpt.scheme = { ...chatgpt.settings.scheme }; // copy `chatgpt.settings.scheme` methods into `chatgpt.scheme`
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "name": "ChatGPT Extension",
4
4
  "description": "A Chrome template to start using chatgpt.js like a boss!",
5
- "version": "2024.7.19",
5
+ "version": "2024.8.28",
6
6
  "author": "chatgpt.js",
7
7
  "icons": {
8
8
  "16": "icons/icon16.png",
@@ -3,13 +3,13 @@
3
3
  // @description A Greasemonkey template to start using chatgpt.js like a boss
4
4
  // @author chatgpt.js
5
5
  // @namespace https://chatgpt.js.org
6
- // @version 2024.7.19
6
+ // @version 2024.8.28
7
7
  // @license MIT
8
8
  // @match *://chatgpt.com/*
9
9
  // @match *://chat.openai.com/*
10
- // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.0.0/starters/greasemonkey/media/images/icons/robot/icon48.png
11
- // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.0.0/starters/greasemonkey/media/images/icons/robot/icon64.png
12
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.0.0/dist/chatgpt.min.js
10
+ // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.0.2/starters/greasemonkey/media/images/icons/robot/icon48.png
11
+ // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.0.2/starters/greasemonkey/media/images/icons/robot/icon64.png
12
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.0.2/dist/chatgpt.min.js
13
13
  // @grant GM_getValue
14
14
  // @grant GM_setValue
15
15
  // @noframes