-
Notifications
You must be signed in to change notification settings - Fork 53
fix(desktop): patch trpc-electron for Electron 39 compatibility #422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,77 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bun | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should possibly fork electron-trpc and add it as a package in our repo - it's no longer maintained so we probably will have to do similar stuff to make it work :/ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Patches trpc-electron to fix compatibility with Electron 39+ / Node.js 22+ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Node.js 22+ has Symbol.asyncDispose built-in on AsyncIterators, which causes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * trpc-electron to throw "Symbol.asyncDispose already exists" when trying to | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * add its own dispose function. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * This patch removes the existence check and allows overwriting the symbol. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { readFileSync, writeFileSync, existsSync } from "node:fs"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { join } from "node:path"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const nodeModulesPath = join(import.meta.dir, "..", "node_modules"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const trpcElectronPath = join(nodeModulesPath, "trpc-electron"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!existsSync(trpcElectronPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("trpc-electron not found, skipping patch"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Patch the source TypeScript file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const utilsPath = join(trpcElectronPath, "src", "main", "utils.ts"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (existsSync(utilsPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = readFileSync(utilsPath, "utf-8"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const originalContent = content; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove the check that throws when Symbol.asyncDispose exists | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /\/\/ eslint-disable-next-line no-restricted-syntax\s*\n\s*if \(it\[Symbol\.asyncDispose\]\) \{\s*\n\s*throw new Error\('Symbol\.asyncDispose already exists'\);\s*\n\s*\}\s*\n/, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "// Node.js 22+ / Electron 39+ has Symbol.asyncDispose built-in on AsyncIterators\n // We overwrite it with our custom dispose function\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (content !== originalContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeFileSync(utilsPath, content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Patched trpc-electron/src/main/utils.ts"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+23
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add validation to detect when patches fail to apply. The regex pattern is extremely brittle and depends on exact formatting, variable names ( 🔎 Suggested improvementsAdd validation to ensure the patch was applied or was already present: const utilsPath = join(trpcElectronPath, "src", "main", "utils.ts");
if (existsSync(utilsPath)) {
let content = readFileSync(utilsPath, "utf-8");
const originalContent = content;
+ // Check if already patched
+ const isAlreadyPatched = !content.includes("Symbol.asyncDispose already exists");
+ const needsPatch = content.includes("Symbol.asyncDispose already exists");
+
// Remove the check that throws when Symbol.asyncDispose exists
content = content.replace(
/\/\/ eslint-disable-next-line no-restricted-syntax\s*\n\s*if \(it\[Symbol\.asyncDispose\]\) \{\s*\n\s*throw new Error\('Symbol\.asyncDispose already exists'\);\s*\n\s*\}\s*\n/,
"// Node.js 22+ / Electron 39+ has Symbol.asyncDispose built-in on AsyncIterators\n // We overwrite it with our custom dispose function\n"
);
if (content !== originalContent) {
writeFileSync(utilsPath, content);
console.log("Patched trpc-electron/src/main/utils.ts");
+ } else if (needsPatch) {
+ console.error("ERROR: Failed to patch trpc-electron/src/main/utils.ts - regex pattern may be outdated");
+ process.exit(1);
}
}Apply similar validation to the dist file patches (lines 41-75). 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Patch the ESM dist file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mainMjsPath = join(trpcElectronPath, "dist", "main.mjs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (existsSync(mainMjsPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = readFileSync(mainMjsPath, "utf-8"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const originalContent = content; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove the check in the Fe function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /function Fe\(r, e\) \{\s*\n\s*const t = r;\s*\n\s*if \(t\[Symbol\.asyncDispose\]\)\s*\n\s*throw new Error\("Symbol\.asyncDispose already exists"\);\s*\n\s*return t\[Symbol\.asyncDispose\] = e, t;\s*\n\}/, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'function Fe(r, e) {\n const t = r;\n // Allow overwriting Symbol.asyncDispose for Node.js 22+ / Electron 39+ compatibility\n return t[Symbol.asyncDispose] = e, t;\n}' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (content !== originalContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeFileSync(mainMjsPath, content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Patched trpc-electron/dist/main.mjs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Patch the CJS dist file (minified) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mainCjsPath = join(trpcElectronPath, "dist", "main.cjs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (existsSync(mainCjsPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = readFileSync(mainCjsPath, "utf-8"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const originalContent = content; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove the check in the minified ke function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = content.replace( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /function ke\(r,e\)\{const t=r;if\(t\[Symbol\.asyncDispose\]\)throw new Error\("Symbol\.asyncDispose already exists"\);return t\[Symbol\.asyncDispose\]=e,t\}/, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "function ke(r,e){const t=r;return t[Symbol.asyncDispose]=e,t}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (content !== originalContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeFileSync(mainCjsPath, content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Patched trpc-electron/dist/main.cjs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("trpc-electron patch complete"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 582
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 407
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 133
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 118
🏁 Script executed:
cat scripts/patch-trpc-electron.ts | head -100Repository: superset-sh/superset
Length of output: 126
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 3076
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 3076
🏁 Script executed:
Repository: superset-sh/superset
Length of output: 3076
Pin trpc-electron to an exact version to prevent silent patch failures.
The postinstall script patches trpc-electron using fragile regex patterns that depend on specific code structure and minification artifacts (e.g., function names like
Fe,ke). These patterns target three locations: the source TypeScript file, ESM dist, and minified CJS dist. With caret versioning (^0.1.2), any patch/minor release of trpc-electron could change its code structure or minification scheme, causing the patches to silently fail to apply (the script only logs but doesn't error on failed matches). This leaves the app running with an unpatched dependency that will break on Node.js 22+ or Electron 39+.Change to exact version pinning:
Revert to caret versioning only after trpc-electron provides an upstream fix for Symbol.asyncDispose compatibility.
🤖 Prompt for AI Agents