mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix production deps
This commit is contained in:
Generated
+7
-28
@@ -5029,7 +5029,6 @@
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-7.2.1.tgz",
|
||||
"integrity": "sha512-+iAPGORAqLl+TcBF+JSLOfRq+PwTQG1NLts+AvN9D8C2czlbDpyjyeaAFSR+5wJlMEZ4wv2rdzt4jSS5T7x3XQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mikro-orm/sql": "7.2.1",
|
||||
@@ -10032,6 +10031,7 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bundle-name": {
|
||||
@@ -10489,21 +10489,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
|
||||
"engines": [
|
||||
"node >= 6.0"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.0.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.4.tgz",
|
||||
@@ -16264,14 +16249,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/multer": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-2.3.0.tgz",
|
||||
"integrity": "sha512-cjNbm3sttszgZeGfJR124D+jFEfkXCVAsoPBmFn9X7UxmDSFHWqE2CoEj0vrmSpuAFnqWR1Szcm9QTsiHr60Xw==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-2.4.0.tgz",
|
||||
"integrity": "sha512-7dqa0ZcFfzbefdTuIkzOSMvZWC0J7FLqBOjJUZvDCXShIURWKxAyTT1wHhnE5q19c7jOJf43IYYKjBmZVZmvhg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^1.6.0",
|
||||
"concat-stream": "^2.0.0",
|
||||
"type-is": "^1.6.18"
|
||||
},
|
||||
"engines": {
|
||||
@@ -20364,12 +20348,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
@@ -22286,11 +22264,13 @@
|
||||
"@aws-lite/client": "^0.23.7",
|
||||
"@aws-lite/s3": "^0.2.7",
|
||||
"@mikro-orm/cli": "^7.2.1",
|
||||
"@mikro-orm/core": "^7.2.1",
|
||||
"@mikro-orm/migrations": "^7.2.1",
|
||||
"@mikro-orm/nestjs": "^7.1.0",
|
||||
"@mikro-orm/postgresql": "^7.2.1",
|
||||
"@mikro-orm/seeder": "^7.2.1",
|
||||
"@mikro-orm/sql": "^7.2.1",
|
||||
"@mikro-orm/sqlite": "^7.2.1",
|
||||
"@modelcontextprotocol/sdk": "^1.30.0",
|
||||
"@nestjs/common": "^11.2.5",
|
||||
"@nestjs/config": "^4.0.4",
|
||||
@@ -22318,6 +22298,7 @@
|
||||
"json5": "^2.2.3",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"kysely": "^0.29.6",
|
||||
"multer": "^2.4.0",
|
||||
"nestjs-zod": "^5.5.0",
|
||||
"nodemailer": "^10.0.13",
|
||||
"otplib": "^12.0.1",
|
||||
@@ -22339,9 +22320,7 @@
|
||||
"devDependencies": {
|
||||
"@aws-lite/s3-types": "^0.2.8",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@mikro-orm/core": "^7.2.1",
|
||||
"@mikro-orm/entity-generator": "^7.2.1",
|
||||
"@mikro-orm/sqlite": "^7.2.1",
|
||||
"@nestjs/testing": "^11.2.5",
|
||||
"@swc/core": "^1.16.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
|
||||
+4
-3
@@ -38,11 +38,13 @@
|
||||
"@aws-lite/client": "^0.23.7",
|
||||
"@aws-lite/s3": "^0.2.7",
|
||||
"@mikro-orm/cli": "^7.2.1",
|
||||
"@mikro-orm/core": "^7.2.1",
|
||||
"@mikro-orm/migrations": "^7.2.1",
|
||||
"@mikro-orm/nestjs": "^7.1.0",
|
||||
"@mikro-orm/postgresql": "^7.2.1",
|
||||
"@mikro-orm/seeder": "^7.2.1",
|
||||
"@mikro-orm/sql": "^7.2.1",
|
||||
"@mikro-orm/sqlite": "^7.2.1",
|
||||
"@modelcontextprotocol/sdk": "^1.30.0",
|
||||
"@nestjs/common": "^11.2.5",
|
||||
"@nestjs/config": "^4.0.4",
|
||||
@@ -70,6 +72,7 @@
|
||||
"json5": "^2.2.3",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"kysely": "^0.29.6",
|
||||
"multer": "^2.4.0",
|
||||
"nestjs-zod": "^5.5.0",
|
||||
"nodemailer": "^10.0.13",
|
||||
"otplib": "^12.0.1",
|
||||
@@ -93,7 +96,7 @@
|
||||
"@hono/node-server": "^1.19.13",
|
||||
"picomatch": "^4.0.4",
|
||||
"ip-address": "^10.1.1",
|
||||
"multer": "^2.3.0",
|
||||
"multer": "^2.4.0",
|
||||
"ws": "^8.21.3",
|
||||
"qs": "^6.15.2",
|
||||
"file-type": "^21.3.4"
|
||||
@@ -101,9 +104,7 @@
|
||||
"devDependencies": {
|
||||
"@aws-lite/s3-types": "^0.2.8",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@mikro-orm/core": "^7.2.1",
|
||||
"@mikro-orm/entity-generator": "^7.2.1",
|
||||
"@mikro-orm/sqlite": "^7.2.1",
|
||||
"@nestjs/testing": "^11.2.5",
|
||||
"@swc/core": "^1.16.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import fs from 'node:fs';
|
||||
import { builtinModules } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
// The image installs the server with `npm ci --omit=dev` (Dockerfile), so a
|
||||
// package that src/ imports at runtime but package.json lists under
|
||||
// devDependencies is simply absent in production: the container boots, loads
|
||||
// dist/index.js and dies with MODULE_NOT_FOUND on the first require. Nothing
|
||||
// else catches that: typecheck, lint and every test run against a full
|
||||
// node_modules. This happened twice on the ORM branch (`tsx`, then
|
||||
// `@mikro-orm/sqlite`), so the rule is pinned here: everything src/ (and the
|
||||
// one script the image runs from source) imports must be a dependency.
|
||||
const serverRoot = path.resolve(__dirname, '../..');
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(serverRoot, 'package.json'), 'utf8')) as {
|
||||
dependencies: Record<string, string>;
|
||||
devDependencies: Record<string, string>;
|
||||
};
|
||||
|
||||
const builtins = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));
|
||||
|
||||
/** The npm package a specifier resolves to: `@scope/name` or the first segment. */
|
||||
const packageOf = (specifier: string): string =>
|
||||
specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0];
|
||||
|
||||
/** Runtime imports only: `import type` and `export type` load nothing. */
|
||||
const IMPORT_FROM = /^[ \t]*(?:import|export)\s+(?!type\s)[^;'"]*?\bfrom\s*['"]([^'"]+)['"]/gm;
|
||||
const BARE_IMPORT = /^[ \t]*import\s*['"]([^'"]+)['"]/gm;
|
||||
const REQUIRE_OR_DYNAMIC = /\b(?:require|import)\(\s*['"]([^'"]+)['"]\s*\)/g;
|
||||
|
||||
/** Comments go first so a docblock that mentions `require('x')` is not an import. */
|
||||
const stripComments = (source: string): string =>
|
||||
source.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^[ \t]*\/\/.*$/gm, '');
|
||||
|
||||
function externalImports(file: string): string[] {
|
||||
const source = stripComments(fs.readFileSync(file, 'utf8'));
|
||||
const specifiers = [IMPORT_FROM, BARE_IMPORT, REQUIRE_OR_DYNAMIC].flatMap((re) =>
|
||||
[...source.matchAll(re)].map((m) => m[1]),
|
||||
);
|
||||
return specifiers.filter((s) => !s.startsWith('.') && !s.startsWith('/') && !builtins.has(s)).map(packageOf);
|
||||
}
|
||||
|
||||
function* walk(dir: string): Generator<string> {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) yield* walk(full);
|
||||
else if (/\.ts$/.test(entry.name) && !/\.(test|d)\.ts$/.test(entry.name)) yield full;
|
||||
}
|
||||
}
|
||||
|
||||
describe('production dependencies', () => {
|
||||
const files = [...walk(path.join(serverRoot, 'src')), path.join(serverRoot, 'scripts', 'migrate-encryption.ts')];
|
||||
const usedBy = new Map<string, string[]>();
|
||||
for (const file of files) {
|
||||
for (const pkg of externalImports(file)) {
|
||||
const list = usedBy.get(pkg) ?? [];
|
||||
if (list.length < 3) list.push(path.relative(serverRoot, file));
|
||||
usedBy.set(pkg, list);
|
||||
}
|
||||
}
|
||||
|
||||
it('PRODDEPS-001: the scan sees the server (guards against matching nothing)', () => {
|
||||
expect(files.length).toBeGreaterThan(100);
|
||||
expect(usedBy.has('@nestjs/common')).toBe(true);
|
||||
expect(usedBy.has('@mikro-orm/sqlite')).toBe(true);
|
||||
});
|
||||
|
||||
it('PRODDEPS-002: every package src/ imports at runtime is a dependency, never a devDependency or undeclared', () => {
|
||||
// `@trek/shared` is the workspace package the image copies in as shared/dist;
|
||||
// `trek-plugin-sdk` is resolved inside the plugin child from its own install.
|
||||
const provided = new Set(['@trek/shared', 'trek-plugin-sdk']);
|
||||
const missing = [...usedBy.entries()]
|
||||
.filter(([pkg]) => !provided.has(pkg) && !(pkg in manifest.dependencies))
|
||||
.map(
|
||||
([pkg, where]) =>
|
||||
`${pkg} (${pkg in manifest.devDependencies ? 'devDependencies' : 'undeclared'}; e.g. ${where.join(', ')})`,
|
||||
);
|
||||
expect(missing).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user