From 4e815eaebaa6fdd433ad572534a8f4bd96d2afa7 Mon Sep 17 00:00:00 2001 From: redman13 Date: Tue, 5 Aug 2025 10:01:46 -0700 Subject: [PATCH 1/7] the changes --- .../crash-message/crash-message.jsx | 9 ++- src/components/menu-bar/menu-bar.jsx | 22 ++----- src/lib/pm-log-capture.js | 65 ++++++++++++++++--- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/components/crash-message/crash-message.jsx b/src/components/crash-message/crash-message.jsx index aa4a3a9b1ac..67b003e2e87 100644 --- a/src/components/crash-message/crash-message.jsx +++ b/src/components/crash-message/crash-message.jsx @@ -5,6 +5,7 @@ import {FormattedMessage} from 'react-intl'; import styles from './crash-message.css'; import reloadIcon from './reload.svg'; +import { downloadLogs } from '../../lib/pm-log-capture.js'; const CrashMessage = props => (
@@ -25,7 +26,7 @@ const CrashMessage = props => ( defaultMessage={'We are so sorry, but it looks like the page has crashed.' + ' Please refresh your page to try' + ' again.' + - ' If the problem persists, please report this error to our Discord.'} + ' If the problem persists, please report the downloadable error below to our Discord.'} description="Message to inform the user that page has crashed." id="tw.gui.crashMessage.description" /> @@ -57,6 +58,12 @@ const CrashMessage = props => ( id="gui.crashMessage.reload" /> +
); diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 7a504d204c7..7c8d216a1c0 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -85,7 +85,7 @@ import sharedMessages from '../../lib/shared-messages'; import SeeInsideButton from './tw-see-inside.jsx'; import { notScratchDesktop } from '../../lib/isScratchDesktop.js'; -//import { consoleLogs } from '../../lib/pm-log-capture.js'; +import { downloadLogs } from '../../lib/pm-log-capture.js'; const ariaMessages = defineMessages({ language: { @@ -207,6 +207,7 @@ class MenuBar extends React.Component { 'handleClickPackager', 'handleClickRestorePoints', 'handleClickSeeCommunity', + 'handleClickDownloadLogs', 'handleClickShare', 'handleKeyPress', 'handleLanguageMouseUp', @@ -422,21 +423,7 @@ class MenuBar extends React.Component { this.props.onRequestCloseAbout(); }; } - /* - - hidden until this is actually helpful for developers - - unhide when a solution is found for not blocking error tracking/using 3rd parties - handleClickDownloadLogs() { - const str = JSON.stringify(consoleLogs); - const a = document.createElement('a'); - a.style.display = 'none'; - document.body.append(a); - const url = window.URL.createObjectURL(new Blob([str])); - a.href = url; - a.download = 'pm-log-trace.json'; - a.click(); - window.URL.revokeObjectURL(url); - a.remove(); - }*/ + handleClickDownloadLogs() { downloadLogs(); } render() { const saveNowMessage = ( + + Download Logs + diff --git a/src/lib/pm-log-capture.js b/src/lib/pm-log-capture.js index e22189b3da5..5bab0fa9021 100644 --- a/src/lib/pm-log-capture.js +++ b/src/lib/pm-log-capture.js @@ -142,18 +142,63 @@ const parseStack = (stack, url, line, column) => { if (stack.split('\n', 2)[0].includes('@')) return _parseFirefoxStack(stack); return _parseChromeStack(stack); }; +const downloadLogs = async () => { + const str = JSON.stringify(consoleLogs); + let blob = new Blob([str]); + let filename = 'pm-error-download.json'; + // if we can, include the project + if (vm) { + filename = 'pm-error-download.pmp'; + const archive = vm._saveProjectZip(); + archive.file('logs.json', blob); + blob = await archive.generateAsync({ + type: 'blob', + mimeType: 'application/x.scratch.sb3', + compression: 'DEFLATE' + }); + } + const a = document.createElement('a'); + a.style.display = 'none'; + document.body.append(a); + const url = window.URL.createObjectURL(blob); + a.href = url; + a.download = filename; + a.click(); + window.URL.revokeObjectURL(url); + a.remove(); +}; +window.downloadLogs = downloadLogs; window.addEventListener('error', e => push('error', e.message, parseStack(e.error.stack, e.filename, e.lineno, e.colno))); window.addEventListener('unhandledrejection', e => push('promiseError', e.reason, [])); -for (const name of ['log', 'warn', 'error', 'debug', 'info']) { - const item = window.console[name]; - window.console[name] = (...args) => { - let stack = []; - if (browserHasStack) stack = parseStack(new Error().stack); - push(name, args, stack); - item(...args); - }; +class StackTrace extends Error { + constructor() { + super(''); + if (this.stack.split('\n', 2)[0].includes('@')) + this.stack = this.stack + .split('\n') + .slice(2, 3) + .join('\n'); + else { + // chrome is weird ngl + const lines = this.stack + .split('\n') + .slice(0, 3); + lines.splice(1, 2); + this.stack = lines.join('\n'); + } + } } - -export { consoleLogs, parseStack, push }; +if (!String(window.location.href).startsWith(`http://localhost:`)) { + for (const name of ['log', 'warn', 'error', 'debug', 'info']) { + const item = window.console[name]; + window.console[name] = (...args) => { + let stack = []; + if (browserHasStack) stack = parseStack(new Error().stack); + push(name, args, stack); + item.call(console, ...args, new StackTrace()); + }; + } +} +export { consoleLogs, parseStack, push, downloadLogs }; From 560295129eb2451ec2be43f72fd5d7b26cf8b304 Mon Sep 17 00:00:00 2001 From: redman13 Date: Tue, 5 Aug 2025 11:17:01 -0700 Subject: [PATCH 2/7] actually, dont include save file --- src/lib/pm-log-capture.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/pm-log-capture.js b/src/lib/pm-log-capture.js index 5bab0fa9021..5c9d0b79780 100644 --- a/src/lib/pm-log-capture.js +++ b/src/lib/pm-log-capture.js @@ -146,6 +146,7 @@ const downloadLogs = async () => { const str = JSON.stringify(consoleLogs); let blob = new Blob([str]); let filename = 'pm-error-download.json'; + /* actually, this is a bad idea // if we can, include the project if (vm) { filename = 'pm-error-download.pmp'; @@ -157,6 +158,7 @@ const downloadLogs = async () => { compression: 'DEFLATE' }); } + */ const a = document.createElement('a'); a.style.display = 'none'; document.body.append(a); From 61e36b5c2c66be9b68edc826739cb00ee8c2ebc1 Mon Sep 17 00:00:00 2001 From: redman13 Date: Wed, 6 Aug 2025 13:58:02 -0700 Subject: [PATCH 3/7] add local files into the logs when required --- src/lib/pm-log-capture.js | 27 ++++++++++++++++++++++++--- src/lib/uid.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/lib/uid.js diff --git a/src/lib/pm-log-capture.js b/src/lib/pm-log-capture.js index 5c9d0b79780..8dcaf3cde12 100644 --- a/src/lib/pm-log-capture.js +++ b/src/lib/pm-log-capture.js @@ -1,3 +1,6 @@ +import JSZip from 'jszip'; +import uid from './uid'; + /** * String.prototype.indexOf, but it returns NaN not -1 on failure * @param {string} str The string to check in @@ -143,9 +146,27 @@ const parseStack = (stack, url, line, column) => { return _parseChromeStack(stack); }; const downloadLogs = async () => { - const str = JSON.stringify(consoleLogs); - let blob = new Blob([str]); - let filename = 'pm-error-download.json'; + const files = new JSZip(); + files.file('logs.json', JSON.stringify(consoleLogs)); + const index = {}; + // get files + // sadly, this may just dead ass fail to get files due to blob lifecycle + // and i dont want to make these files get stored at runtime, cause poopy doo doo ram + for (const log of consoleLogs) { + for (const trace of log.trace) { + if (index[trace.url]) continue; + const id = uid(); + const content = await fetch(trace.url) + .then(res => res.ok ? res.text() : null) + .catch(() => {}); + if (!content) continue; + files.file(id, content); + index[trace.url] = id; + } + } + files.file('index.json', JSON.stringify(index)); + let blob = await files.generateAsync({ type: 'blob', compression: 'DEFLATE' }); + let filename = 'pm-error-download.pml'; /* actually, this is a bad idea // if we can, include the project if (vm) { diff --git a/src/lib/uid.js b/src/lib/uid.js new file mode 100644 index 00000000000..2c8d093841b --- /dev/null +++ b/src/lib/uid.js @@ -0,0 +1,29 @@ +/** + * @fileoverview UID generator, from Blockly. + */ + +/** + * Legal characters for the unique ID. + * Should be all on a US keyboard. No XML special characters or control codes. + * Removed $ due to issue 251. + * Removed all symbols due to use in files + * @private + */ +const soup_ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + +/** + * Generate a unique ID, from Blockly. This should be globally unique. + * 87 characters ^ 20 length > 128 bits (better than a UUID). + * @return {string} A globally unique ID string. + */ +const uid = function () { + const length = 20; + const soupLength = soup_.length; + const id = []; + for (let i = 0; i < length; i++) { + id[i] = soup_.charAt(Math.random() * soupLength); + } + return id.join(''); +}; + +export default uid; From 154368e6890be333b828a86cd8df08cbce0a8396 Mon Sep 17 00:00:00 2001 From: redman13 Date: Tue, 12 Aug 2025 13:28:44 -0700 Subject: [PATCH 4/7] gui-side unclamp direction --- .../tw-settings-modal/settings-modal.jsx | 24 +++++++++++++++++++ src/containers/tw-settings-modal.jsx | 10 +++++++- src/lib/project-fetcher-hoc.jsx | 1 + src/lib/tw-state-manager-hoc.jsx | 12 ++++++++++ src/reducers/tw.js | 1 + 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/components/tw-settings-modal/settings-modal.jsx b/src/components/tw-settings-modal/settings-modal.jsx index 91b42136f17..c4e9481e085 100644 --- a/src/components/tw-settings-modal/settings-modal.jsx +++ b/src/components/tw-settings-modal/settings-modal.jsx @@ -314,6 +314,26 @@ const DisableOffscreenRendering = props => ( // slug="out-of-bounds-rendering" /> ); +const DisableDirectionClamping = props => ( + + } + help={ + + } + // slug="out-of-bounds-rendering" + /> +); const WarpTimer = props => ( ( value={props.dangerousOptimizations} onChange={props.onEnableDangerousOptimizationsChange} /> +
({ removeFencing: !state.scratchGui.tw.runtimeOptions.fencing, removeLimits: !state.scratchGui.tw.runtimeOptions.miscLimits, disableOffscreenRendering: state.scratchGui.tw.runtimeOptions.disableOffscreenRendering, + disableDirectionClamping: state.scratchGui.tw.runtimeOptions.disableDirectionClamping, dangerousOptimizations: state.scratchGui.tw.runtimeOptions.dangerousOptimizations, warpTimer: state.scratchGui.tw.compilerOptions.warpTimer, customStageSize: state.scratchGui.customStageSize, diff --git a/src/lib/project-fetcher-hoc.jsx b/src/lib/project-fetcher-hoc.jsx index ba0cd8fd3ce..8480484fbe5 100644 --- a/src/lib/project-fetcher-hoc.jsx +++ b/src/lib/project-fetcher-hoc.jsx @@ -120,6 +120,7 @@ const ProjectFetcherHOC = function (WrappedComponent) { ) { this.props.vm.setFramerate(30); this.props.vm.setRuntimeOptions({ + disableDirectionClamping: false, dangerousOptimizations: false, disableOffscreenRendering: false, fencing: true, diff --git a/src/lib/tw-state-manager-hoc.jsx b/src/lib/tw-state-manager-hoc.jsx index 59eaec7934e..6a922a0f0ba 100644 --- a/src/lib/tw-state-manager-hoc.jsx +++ b/src/lib/tw-state-manager-hoc.jsx @@ -405,6 +405,12 @@ const TWStateManager = function (WrappedComponent) { }); } + if (urlParams.has('nodirectionclamping')) { + this.props.vm.setRuntimeOptions({ + disableDirectionClamping: true + }); + } + for (const extension of urlParams.getAll('extension')) { this.props.vm.extensionManager.loadExtensionURL(extension); } @@ -535,6 +541,12 @@ const TWStateManager = function (WrappedComponent) { searchParams.delete('nooffscreen'); } + if (runtimeOptions.disableDirectionClamping) { + searchParams.set('nodirectionclamping', ''); + } else { + searchParams.delete('nodirectionclamping'); + } + setSearchParams(searchParams); } } diff --git a/src/reducers/tw.js b/src/reducers/tw.js index f26aa9a8661..93409f6eabd 100644 --- a/src/reducers/tw.js +++ b/src/reducers/tw.js @@ -34,6 +34,7 @@ export const initialState = { miscLimits: true, dangerousOptimizations: false, disableOffscreenRendering: false, + disableDirectionClamping: false, fencing: true }, isWindowFullScreen: false, From d82d7b41e6c07cf25ebb2e169e9be3256bbac03f Mon Sep 17 00:00:00 2001 From: redman13 Date: Thu, 14 Aug 2025 17:45:51 -0700 Subject: [PATCH 5/7] no source maps at all --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index a51db434dcb..a35495f11eb 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -27,7 +27,7 @@ jobs: with: node-version: 16.x - name: Install dependencies and build site - run: npm i -g pnpm@v6 && pnpm up && pnpm i --shamefully-hoist --force && SOURCEMAP="cheap-source-map" NODE_ENV="production" webpack --bail + run: npm i -g pnpm@v6 && pnpm up && pnpm i --shamefully-hoist --force && NODE_ENV="production" webpack --bail - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: From ff1f82feb3aa08de89f4a5576ab2098a4b5759f3 Mon Sep 17 00:00:00 2001 From: redman13 Date: Sun, 17 Aug 2025 20:34:07 -0700 Subject: [PATCH 6/7] doooont include theeee log capturer in traces --- src/lib/pm-log-capture.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/pm-log-capture.js b/src/lib/pm-log-capture.js index 8dcaf3cde12..2e59c21baa8 100644 --- a/src/lib/pm-log-capture.js +++ b/src/lib/pm-log-capture.js @@ -59,7 +59,7 @@ const push = (type, message, trace) => { trace }); }; -const _parseFirefoxStack = stack => stack.split('\n') +const _parseFirefoxStack = stack => stack.split('\n').slice(1) .map(line => { const at = line.indexOf('@'); const secondCol = line.lastIndexOf(':'); @@ -90,7 +90,7 @@ const _parseFirefoxStack = stack => stack.split('\n') origin }; }); -const _parseChromeStack = stack => stack.split('\n').slice(1) +const _parseChromeStack = stack => stack.split('\n').slice(2) .map(line => { // we have no use for the human readable fluff line = line.slice(7); From ef8be2f4943aa03ae7beb632b9957a296aae559a Mon Sep 17 00:00:00 2001 From: redman13 Date: Sun, 17 Aug 2025 20:51:17 -0700 Subject: [PATCH 7/7] haha rizz --- src/lib/analytics.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/analytics.js b/src/lib/analytics.js index b123c673c1f..5b795e69a52 100644 --- a/src/lib/analytics.js +++ b/src/lib/analytics.js @@ -4,3 +4,4 @@ const GoogleAnalytics = { }; export default GoogleAnalytics; + \ No newline at end of file