Skip to content

Commit 969ce6b

Browse files
d-gubertclaude
andcommitted
feat(apps): generate deno-runtime config with resolved apps-engine path at spawn time
The static deno.jsonc used `"@rocket.chat/apps-engine/": "./../src/"` — a relative path that only works when deno-runtime/ and apps-engine/src/ are siblings in the same package. Now that deno-runtime lives in @rocket.chat/apps and the definition source lives in @rocket.chat/apps-engine, the relative path would resolve to the wrong location. Solution: generate a `deno_runtime.jsonc` into the temp directory before each Deno subprocess spawn. The generated config copies all settings from the static deno.jsonc and injects `@rocket.chat/apps-engine/` as an absolute `file:` URL resolved via `require.resolve('@rocket.chat/apps-engine/package.json')`. This works correctly in any environment (monorepo dev, Meteor bundle, CI) without assumptions about directory layout. Changes: - `getAppsEngineSourceDir()`: resolves apps-engine src/ via require.resolve - `generateRuntimeDenoConfig()`: reads static config, injects resolved path, writes to tempDir/deno_runtime.jsonc, returns the path - `spawnProcess()`: calls generateRuntimeDenoConfig, uses the generated config, adds appsEngineSrcDir to --allow-read - deno.jsonc: remove the now-redundant static @rocket.chat/apps-engine/ entry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7e1f8ff commit 969ce6b

2 files changed

Lines changed: 44 additions & 4 deletions

File tree

packages/apps/deno-runtime/deno.jsonc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"imports": {
33
"@msgpack/msgpack": "npm:@msgpack/msgpack@3.0.0-beta2",
4-
"@rocket.chat/apps-engine/": "./../src/",
54
"@rocket.chat/ui-kit": "npm:@rocket.chat/ui-kit@^0.31.22",
65
"@std/cli": "jsr:@std/cli@^1.0.9",
76
"@std/io": "jsr:@std/io@^0.225.3",

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,42 @@ export function getDenoConfigPath(): string {
8686
}
8787
}
8888

89+
/**
90+
* Resolves the absolute path to @rocket.chat/apps-engine's src/ directory.
91+
* Uses require.resolve so it works regardless of the runtime environment
92+
* (monorepo dev, Meteor bundle, standalone node_modules).
93+
*/
94+
export function getAppsEngineSourceDir(): string {
95+
const pkgJsonPath = require.resolve('@rocket.chat/apps-engine/package.json');
96+
return path.join(path.dirname(pkgJsonPath), 'src');
97+
}
98+
99+
/**
100+
* Generates a runtime deno.jsonc at `<tempDir>/deno_runtime.jsonc` by reading
101+
* the static config and injecting the resolved absolute path for
102+
* `@rocket.chat/apps-engine/`. This makes deno-runtime location-independent:
103+
* the path is always correct regardless of where this package is installed.
104+
*
105+
* Returns the path to the generated config file.
106+
*/
107+
export function generateRuntimeDenoConfig(staticConfigPath: string, tempDir: string): string {
108+
const staticConfig = JSON.parse(fs.readFileSync(staticConfigPath, 'utf8'));
109+
const appsEngineSrcUrl = `file://${getAppsEngineSourceDir()}/`;
110+
111+
const runtimeConfig = {
112+
...staticConfig,
113+
imports: {
114+
...staticConfig.imports,
115+
'@rocket.chat/apps-engine/': appsEngineSrcUrl,
116+
},
117+
};
118+
119+
const runtimeConfigPath = path.join(tempDir, 'deno_runtime.jsonc');
120+
fs.writeFileSync(runtimeConfigPath, JSON.stringify(runtimeConfig, null, '\t'));
121+
122+
return runtimeConfigPath;
123+
}
124+
89125
type AbortFunction = (reason?: any) => void;
90126

91127
export class DenoRuntimeSubprocessController extends EventEmitter implements IRuntimeController {
@@ -171,19 +207,24 @@ export class DenoRuntimeSubprocessController extends EventEmitter implements IRu
171207
const denoExePath = 'deno';
172208

173209
const denoWrapperPath = this.denoRuntimePath;
174-
// During development, the appsEngineDir is enough to run the deno process
210+
// The apps package dir (where deno-runtime/ and .deno-cache/ live)
175211
const appsEngineDir = path.dirname(path.join(this.denoConfigPath, '..'));
176212
const DENO_DIR = process.env.DENO_DIR ?? path.join(appsEngineDir, '.deno-cache');
177213
// When running in production, we're likely inside a node_modules which the Deno
178214
// process must be able to read in order to include files that use NPM packages
179215
const parentNodeModulesDir = path.dirname(path.join(appsEngineDir, '..'));
216+
// The definition/ source files from @rocket.chat/apps-engine that deno-runtime imports
217+
const appsEngineSrcDir = getAppsEngineSourceDir();
218+
219+
const allowedDirs = [appsEngineDir, parentNodeModulesDir, appsEngineSrcDir, this.tempFilePath];
180220

181-
const allowedDirs = [appsEngineDir, parentNodeModulesDir, this.tempFilePath];
221+
// Generate a runtime config with the resolved absolute path for @rocket.chat/apps-engine/
222+
const runtimeConfigPath = generateRuntimeDenoConfig(this.denoConfigPath, this.tempFilePath);
182223

183224
const options = [
184225
'run',
185226
'--cached-only',
186-
`--config=${this.denoConfigPath}`,
227+
`--config=${runtimeConfigPath}`,
187228
`--allow-read=${allowedDirs.join(',')}`,
188229
`--allow-env=${ALLOWED_ENVIRONMENT_VARIABLES.join(',')}`,
189230
denoWrapperPath,

0 commit comments

Comments
 (0)