Skip to content

Commit 31e654f

Browse files
d-gubertclaude
andcommitted
chore(apps): add build config for server code and deno-runtime
- package.json: add all runtime deps from apps-engine (msgpack, adm-zip, esbuild, jose, semver, etc.), deno-related devDeps (npm-run-all, rimraf, ts-node), build/test scripts, and include deno-runtime/ and scripts/ in published files - tsconfig.json: enable experimentalDecorators and emitDecoratorMetadata required by the incoming server code - turbo.json: declare build outputs (dist/, deno-runtime/, .deno-cache/) - scripts/deno-cache.js: copied from apps-engine; validates Deno version and pre-caches deno-runtime dependencies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d58ded7 commit 31e654f

4 files changed

Lines changed: 133 additions & 5 deletions

File tree

packages/apps/package.json

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,50 @@
55
"main": "./dist/index.js",
66
"typings": "./dist/index.d.ts",
77
"files": [
8-
"/dist"
8+
"/dist",
9+
"/deno-runtime",
10+
"/scripts"
911
],
1012
"scripts": {
11-
"build": "rm -rf dist && tsc -p tsconfig.json",
13+
"build": "run-s build:clean build:default build:deno-cache",
14+
"build:clean": "rimraf dist",
15+
"build:default": "tsc -p tsconfig.json",
16+
"build:deno-cache": "node scripts/deno-cache.js",
1217
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
1318
"lint": "eslint .",
14-
"lint:fix": "eslint --fix ."
19+
"lint:fix": "eslint --fix .",
20+
"test:deno": "cd deno-runtime && deno task test",
21+
"test:node": "NODE_ENV=test node --require ts-node/register/transpile-only --test-reporter spec --test \"tests/**/*.test.ts\""
1522
},
1623
"dependencies": {
1724
"@rocket.chat/apps-engine": "workspace:^",
1825
"@rocket.chat/core-typings": "workspace:^",
19-
"@rocket.chat/model-typings": "workspace:^"
26+
"@rocket.chat/model-typings": "workspace:^",
27+
"@msgpack/msgpack": "3.0.0-beta2",
28+
"adm-zip": "^0.5.16",
29+
"debug": "^4.3.7",
30+
"esbuild": "~0.27.3",
31+
"jose": "^4.15.9",
32+
"jsonrpc-lite": "^2.2.0",
33+
"lodash.clonedeep": "^4.5.0",
34+
"semver": "^7.6.3",
35+
"stack-trace": "0.0.10",
36+
"uuid": "~11.0.5"
2037
},
2138
"devDependencies": {
2239
"@rocket.chat/tsconfig": "workspace:*",
40+
"@seald-io/nedb": "^4.1.2",
41+
"@types/adm-zip": "^0.5.7",
42+
"@types/debug": "^4.1.12",
43+
"@types/lodash.clonedeep": "^4.5.9",
44+
"@types/node": "~22.16.5",
45+
"@types/semver": "^7.5.8",
46+
"@types/stack-trace": "0.0.33",
47+
"@types/uuid": "~10.0.0",
2348
"eslint": "~9.39.3",
49+
"npm-run-all": "^4.1.5",
50+
"rimraf": "^6.0.1",
51+
"ts-node": "^6.2.0",
2452
"typescript": "~5.9.3"
2553
},
2654
"volta": {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
const childProcess = require('child_process');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
const SHELL_ERR_CMD_NOT_FOUND = 127;
6+
const { CI } = process.env;
7+
8+
/**
9+
* Matches 'deno 2.3.1' or 'Deno 2.7.11-alpha3.24' or even 'some deno and-anything in between 1.43.5' (as long as everything is in the same line)
10+
* and extracts the correct version string from those ('2.3.1', '2.7.11' and '1.43.5' respectively).
11+
*
12+
* Doesn't match 'denoing 2.3.1' or 'deno2.3.1' or 'mydeno 2.7.11alpha3.24' or 'deno\n1.43.5'
13+
*
14+
* The expression gets a bit complicated because the word boundary assertion (\b) identifies the dash (-) as a valid word boundary,
15+
* but that is not the case for use, as we don't want to match "make-deno" for instance. So, for correctness, we use a negative lookbehind
16+
* assertion ("(?<!)") BEFORE words to make sure our match is not preceded by a word character (\w), a dash (-) or a dot (.), e.g. it won't
17+
* match "mydeno", "my-deno", "my.deno", etc. The negative lookbehind also allows us to match "deno" in the start of the input, something that
18+
* simply using the expression itself wouldn't match. In most other cases, these would be replaced by simply "\b"
19+
*
20+
* The exact expression tries find the first line to match a sequence as follows:
21+
* - A character "D" or "d" that is not preceded by a word character, dash or dot (negative lookbehind)
22+
* - Followed by the literal sequence "eno"
23+
* - Followed by any character that is not a word character, dash or dot
24+
* - Followed by a sequence of zero or more occurrences of any character (non multi line)
25+
* - Followed by a sequence of one or more numbers, then a dot, then one or more numbers, then a dot, then one or more numbers ("version" capture group)
26+
* that is NOT preceded by a word character, a dash, or dot (negative lookbehind)
27+
* - Followed by a word boundary (here we're less picky with the "\b" assertion, as we're out of the capture group)
28+
*/
29+
const extractDenoVersion = (input) => /(?<![\w-.])[Dd]eno[^\w-.].*(?<![\w-.])(?<version>\d+\.\d+\.\d+)\b/.exec(input)?.groups?.version;
30+
31+
try {
32+
const toolVersionsPath = path.resolve(__dirname, '..', '..', '..', '.tool-versions');
33+
const denoToolVersion = extractDenoVersion(fs.readFileSync(toolVersionsPath).toString());
34+
35+
if (!denoToolVersion) {
36+
throw new Error(`Invalid Deno version in ${toolVersionsPath}, aborting...`);
37+
}
38+
39+
const installedVersion = extractDenoVersion(childProcess.execSync('deno --version').toString());
40+
41+
if (!installedVersion) {
42+
throw new Error(
43+
`Couldn't determine version of installed Deno. Try validating the version with 'deno --version' and make sure it is a valid Deno installation`,
44+
);
45+
}
46+
47+
if (installedVersion !== denoToolVersion) {
48+
const message = `Incorrect Deno version. Required '${denoToolVersion}', found '${installedVersion}'.${CI ? '' : " The server will likely work, but it may cause your deno.lock to change - do not commit it. Make sure your Deno version matches the required one so you don't see this message again."}`;
49+
50+
if (CI) {
51+
throw new Error(message);
52+
}
53+
54+
// We don't need to fail if a dev environment doesn't have a matching Deno version, just the warning is enough
55+
console.warn(message);
56+
}
57+
} catch (e) {
58+
if (e.status === SHELL_ERR_CMD_NOT_FOUND) {
59+
console.error(
60+
new Error(
61+
[
62+
'Could not execute "deno" in the system. It is now a requirement for the Apps-Engine framework, and Rocket.Chat apps will not work without it.',
63+
'Make sure to install Deno and run the installation process for the Apps-Engine again. More info on https://docs.deno.com/runtime/manual/getting_started/installation',
64+
].join('\n'),
65+
{ cause: e },
66+
),
67+
);
68+
} else {
69+
console.error(e);
70+
}
71+
72+
process.exit(1);
73+
}
74+
75+
const rootPath = path.join(__dirname, '..');
76+
const denoRuntimePath = path.join(rootPath, 'deno-runtime');
77+
const DENO_DIR = process.env.DENO_DIR ?? path.join(rootPath, '.deno-cache');
78+
79+
// In CI envs, break if lockfile changes; in dev envs, it's alright
80+
const commandLine = CI ? 'deno install --frozen --entrypoint main.ts' : 'deno install --entrypoint main.ts';
81+
82+
childProcess.execSync(commandLine, {
83+
cwd: denoRuntimePath,
84+
env: {
85+
...process.env,
86+
DENO_DIR,
87+
},
88+
stdio: 'inherit',
89+
});

packages/apps/tsconfig.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"compilerOptions": {
44
"declaration": true,
55
"rootDir": "./src",
6-
"outDir": "./dist"
6+
"outDir": "./dist",
7+
"experimentalDecorators": true,
8+
"emitDecoratorMetadata": true
79
},
810
"include": ["./src/**/*"]
911
}

packages/apps/turbo.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": ["//"],
3+
"tasks": {
4+
"build": {
5+
"dependsOn": ["^build"],
6+
"outputs": ["dist/**", "deno-runtime/**", "scripts/**", ".deno-cache/**"]
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)