Skip to content

Commit 297df1a

Browse files
fix(apps): resolve deno-runtime module not found after upgrade (#40947)
1 parent 7a360be commit 297df1a

2 files changed

Lines changed: 38 additions & 7 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/apps': patch
3+
---
4+
5+
Fixes an issue that would cause apps to fail with 'Module not found' errors in some cases

packages/apps/src/server/runtime/deno/AppsEngineDenoRuntime.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,38 @@ function generateEphemeralDenoConfig(targetPath: string, denoConfigPath: string,
4747
fs.writeFileSync(targetPath, JSON.stringify(runtimeConfig, null, '\t'));
4848
}
4949

50+
/**
51+
* Ensures a directory symlink exists at `symlinkPath` pointing to `targetPath`.
52+
*
53+
* First removes whatever currently lives at `symlinkPath` (broken symlink,
54+
* wrong target, or a non-symlink entry), ignoring ENOENT if nothing is there.
55+
* Then creates the symlink, catching EEXIST to guard against race conditions.
56+
*/
57+
export function ensureSymlink(symlinkPath: string, targetPath: string): void {
58+
try {
59+
const currentTarget = fs.readlinkSync(symlinkPath);
60+
61+
if (currentTarget === targetPath) {
62+
return;
63+
}
64+
65+
fs.rmSync(symlinkPath, { recursive: true, force: true });
66+
} catch (err: unknown) {
67+
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
68+
fs.rmSync(symlinkPath, { recursive: true, force: true });
69+
}
70+
}
71+
72+
// Create the symlink; guard against a concurrent creator
73+
try {
74+
fs.symlinkSync(targetPath, symlinkPath, 'dir');
75+
} catch (err: unknown) {
76+
if ((err as NodeJS.ErrnoException).code !== 'EEXIST') {
77+
throw err;
78+
}
79+
}
80+
}
81+
5082
export class DenoRuntimeSubprocessController extends BaseRuntimeSubprocessController {
5183
private readonly denoBin = 'deno';
5284

@@ -75,13 +107,7 @@ export class DenoRuntimeSubprocessController extends BaseRuntimeSubprocessContro
75107
* Deno 2.x refuses to run scripts inside the node_modules, so we create a symlink to the deno runtime files in the temp directory
76108
* The temp directory is the same we are given by the host to store temporary upload files
77109
*/
78-
try {
79-
fs.symlinkSync(path.dirname(this.denoConfigPath), path.dirname(this.denoRuntimePath), 'dir');
80-
} catch (reason: unknown) {
81-
if ((reason as NodeJS.ErrnoException).code !== 'EEXIST') {
82-
throw reason;
83-
}
84-
}
110+
ensureSymlink(path.dirname(this.denoRuntimePath), path.dirname(this.denoConfigPath));
85111

86112
// Generate a runtime config with the resolved absolute path for @rocket.chat/apps-engine/ and @rocket.chat/apps/ paths
87113
generateEphemeralDenoConfig(this.denoEphemeralConfigPath, this.denoConfigPath, this.appsEnginePath, this.packagePath);

0 commit comments

Comments
 (0)