@creeperhost/modlens-mcp 1.6.17 → 1.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -10
- package/TESTING.md +69 -0
- package/dist/cli.js +21 -5
- package/dist/cli.js.map +1 -1
- package/dist/curseforge.d.ts +9 -7
- package/dist/curseforge.d.ts.map +1 -1
- package/dist/curseforge.js +48 -55
- package/dist/curseforge.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +34 -3
- package/dist/db.js.map +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +1 -0
- package/dist/embeddings.js.map +1 -1
- package/dist/feed-the-beast.d.ts +5 -5
- package/dist/feed-the-beast.d.ts.map +1 -1
- package/dist/feed-the-beast.js +5 -21
- package/dist/feed-the-beast.js.map +1 -1
- package/dist/generated/sqlite/internal/class.js +2 -2
- package/dist/generated/sqlite/internal/class.js.map +1 -1
- package/dist/java-tools.d.ts +1 -0
- package/dist/java-tools.d.ts.map +1 -1
- package/dist/java-tools.js +31 -7
- package/dist/java-tools.js.map +1 -1
- package/dist/launcher.js +15 -0
- package/dist/launcher.js.map +1 -1
- package/dist/mappings.d.ts +4 -1
- package/dist/mappings.d.ts.map +1 -1
- package/dist/mappings.js +120 -52
- package/dist/mappings.js.map +1 -1
- package/dist/minecraft.d.ts +0 -4
- package/dist/minecraft.d.ts.map +1 -1
- package/dist/minecraft.js +7 -23
- package/dist/minecraft.js.map +1 -1
- package/dist/mod-artifacts.d.ts +4 -0
- package/dist/mod-artifacts.d.ts.map +1 -0
- package/dist/mod-artifacts.js +58 -0
- package/dist/mod-artifacts.js.map +1 -0
- package/dist/modpacks-ch.d.ts +72 -46
- package/dist/modpacks-ch.d.ts.map +1 -1
- package/dist/modpacks-ch.js +134 -20
- package/dist/modpacks-ch.js.map +1 -1
- package/dist/modrinth.d.ts +14 -6
- package/dist/modrinth.d.ts.map +1 -1
- package/dist/modrinth.js +70 -55
- package/dist/modrinth.js.map +1 -1
- package/dist/platform-adapter.d.ts +1 -0
- package/dist/platform-adapter.d.ts.map +1 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +20 -44
- package/dist/platform.js.map +1 -1
- package/dist/processor.d.ts +5 -0
- package/dist/processor.d.ts.map +1 -1
- package/dist/processor.js +166 -46
- package/dist/processor.js.map +1 -1
- package/dist/registry-submission.d.ts +34 -0
- package/dist/registry-submission.d.ts.map +1 -0
- package/dist/registry-submission.js +128 -0
- package/dist/registry-submission.js.map +1 -0
- package/dist/repositories/array-fields.d.ts +3 -0
- package/dist/repositories/array-fields.d.ts.map +1 -0
- package/dist/repositories/array-fields.js +8 -0
- package/dist/repositories/array-fields.js.map +1 -0
- package/dist/repositories/embeddings-sqlite.d.ts +1 -0
- package/dist/repositories/embeddings-sqlite.d.ts.map +1 -1
- package/dist/repositories/embeddings-sqlite.js +26 -58
- package/dist/repositories/embeddings-sqlite.js.map +1 -1
- package/dist/repositories/embeddings.d.ts.map +1 -1
- package/dist/repositories/embeddings.js +26 -3
- package/dist/repositories/embeddings.js.map +1 -1
- package/dist/repositories/index.d.ts +1 -1
- package/dist/repositories/index.d.ts.map +1 -1
- package/dist/repositories/mod.d.ts +8 -5
- package/dist/repositories/mod.d.ts.map +1 -1
- package/dist/repositories/mod.js +25 -11
- package/dist/repositories/mod.js.map +1 -1
- package/dist/repositories/packs.d.ts.map +1 -1
- package/dist/repositories/packs.js +10 -2
- package/dist/repositories/packs.js.map +1 -1
- package/dist/search-adapter.d.ts +2 -0
- package/dist/search-adapter.d.ts.map +1 -1
- package/dist/search-adapter.js +21 -9
- package/dist/search-adapter.js.map +1 -1
- package/dist/security.d.ts +2 -0
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +5 -1
- package/dist/security.js.map +1 -1
- package/dist/server.js +63 -25
- package/dist/server.js.map +1 -1
- package/dist/sqlite-json.d.ts +3 -0
- package/dist/sqlite-json.d.ts.map +1 -0
- package/dist/sqlite-json.js +78 -0
- package/dist/sqlite-json.js.map +1 -0
- package/dist/sqlite-parameters.d.ts +3 -0
- package/dist/sqlite-parameters.d.ts.map +1 -0
- package/dist/sqlite-parameters.js +19 -0
- package/dist/sqlite-parameters.js.map +1 -0
- package/dist/sqlite-schema.d.ts +4 -0
- package/dist/sqlite-schema.d.ts.map +1 -0
- package/dist/sqlite-schema.js +76 -0
- package/dist/sqlite-schema.js.map +1 -0
- package/dist/tools/catalog.d.ts +1 -6
- package/dist/tools/catalog.d.ts.map +1 -1
- package/dist/tools/catalog.js +10 -14
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/compat-check.d.ts.map +1 -1
- package/dist/tools/compat-check.js +18 -30
- package/dist/tools/compat-check.js.map +1 -1
- package/dist/tools/diagnostics.js.map +1 -1
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +8 -3
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/embed-registry.d.ts +20 -4
- package/dist/tools/embed-registry.d.ts.map +1 -1
- package/dist/tools/embed-registry.js +30 -19
- package/dist/tools/embed-registry.js.map +1 -1
- package/dist/tools/graphify.d.ts +19 -4
- package/dist/tools/graphify.d.ts.map +1 -1
- package/dist/tools/graphify.js +61 -13
- package/dist/tools/graphify.js.map +1 -1
- package/dist/tools/ingest.d.ts.map +1 -1
- package/dist/tools/ingest.js +4 -4
- package/dist/tools/ingest.js.map +1 -1
- package/dist/tools/kubejs.js +1 -1
- package/dist/tools/kubejs.js.map +1 -1
- package/dist/tools/mc-fts.d.ts.map +1 -1
- package/dist/tools/mc-fts.js +9 -4
- package/dist/tools/mc-fts.js.map +1 -1
- package/dist/tools/mcmeta.d.ts +10 -1
- package/dist/tools/mcmeta.d.ts.map +1 -1
- package/dist/tools/mcmeta.js +43 -29
- package/dist/tools/mcmeta.js.map +1 -1
- package/dist/tools/mixin-scan.d.ts +12 -6
- package/dist/tools/mixin-scan.d.ts.map +1 -1
- package/dist/tools/mixin-scan.js +12 -7
- package/dist/tools/mixin-scan.js.map +1 -1
- package/dist/tools/mod-data.d.ts.map +1 -1
- package/dist/tools/mod-data.js +40 -27
- package/dist/tools/mod-data.js.map +1 -1
- package/dist/tools/modpacks-ch.d.ts +9 -5
- package/dist/tools/modpacks-ch.d.ts.map +1 -1
- package/dist/tools/modpacks-ch.js +54 -33
- package/dist/tools/modpacks-ch.js.map +1 -1
- package/dist/tools/packtools.js +3 -3
- package/dist/tools/packtools.js.map +1 -1
- package/dist/tools/platform.d.ts +2 -2
- package/dist/tools/platform.d.ts.map +1 -1
- package/dist/tools/platform.js +33 -23
- package/dist/tools/platform.js.map +1 -1
- package/dist/tools/project.d.ts +342 -0
- package/dist/tools/project.d.ts.map +1 -0
- package/dist/tools/project.js +519 -0
- package/dist/tools/project.js.map +1 -0
- package/dist/tools/reports.d.ts.map +1 -1
- package/dist/tools/reports.js +5 -3
- package/dist/tools/reports.js.map +1 -1
- package/dist/tools/vanilla-data.d.ts.map +1 -1
- package/dist/tools/vanilla-data.js +3 -33
- package/dist/tools/vanilla-data.js.map +1 -1
- package/dist/tools/vanilla.d.ts +3 -1
- package/dist/tools/vanilla.d.ts.map +1 -1
- package/dist/tools/vanilla.js +26 -12
- package/dist/tools/vanilla.js.map +1 -1
- package/dist/tools/version-diff.d.ts.map +1 -1
- package/dist/tools/version-diff.js +4 -24
- package/dist/tools/version-diff.js.map +1 -1
- package/dist/version-ranges.d.ts +5 -0
- package/dist/version-ranges.d.ts.map +1 -0
- package/dist/version-ranges.js +93 -0
- package/dist/version-ranges.js.map +1 -0
- package/package.json +8 -3
- package/prisma/backends/template.db +0 -0
- package/scripts/build-template-db.mjs +5 -2
- package/scripts/enable-sqlite-vec.mjs +2 -106
- package/scripts/gradle/modlens.init.gradle +154 -0
- package/scripts/project-upload.mjs +74 -0
- package/scripts/test-minecraft-eras.mjs +202 -0
- package/scripts/test-package.mjs +217 -0
- package/scripts/test-project-gradle.mjs +76 -0
- package/scripts/test-project-http.mjs +98 -0
- package/scripts/test-setup.mjs +18 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Real Gradle -> export -> ModLens source/member/search assertions. No game launch.
|
|
2
|
+
// Set MODLENS_TEST_GRADLE_HOME and JAVA_HOME. Optional argument: moddev (NeoForge 1.21.1).
|
|
3
|
+
// Uses a disposable fixture; retained on failure for diagnosis.
|
|
4
|
+
import assert from 'node:assert/strict';
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
|
+
import { mkdtemp, mkdir, writeFile, readFile, readdir, rm } from 'node:fs/promises';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { dirname, join, resolve } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { ProjectStore } from '../dist/tools/project.js';
|
|
11
|
+
|
|
12
|
+
const moddev = process.argv[2] === 'moddev';
|
|
13
|
+
const root = await mkdtemp(join(tmpdir(), 'modlens-gradle-smoke-'));
|
|
14
|
+
const repo = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
15
|
+
const gradleHome = process.env.MODLENS_TEST_GRADLE_HOME;
|
|
16
|
+
if (!gradleHome || !process.env.JAVA_HOME) throw new Error('Set MODLENS_TEST_GRADLE_HOME and JAVA_HOME');
|
|
17
|
+
const launcher = (await readdir(join(gradleHome, 'lib'))).find(n => /^gradle-launcher-.*\.jar$/.test(n));
|
|
18
|
+
if (!launcher) throw new Error('Gradle launcher JAR missing');
|
|
19
|
+
const java = join(process.env.JAVA_HOME, 'bin', process.platform === 'win32' ? 'java.exe' : 'java');
|
|
20
|
+
const write = async (path, text) => { await mkdir(dirname(join(root, path)), { recursive: true }); await writeFile(join(root, path), text); };
|
|
21
|
+
const run = (sourceSet = 'main') => execFileSync(java, ['-classpath', join(gradleHome, 'lib', launcher), 'org.gradle.launcher.GradleMain',
|
|
22
|
+
'--no-daemon', '--console=plain', '--no-configuration-cache', '-I', join(repo, 'scripts/gradle/modlens.init.gradle'), `-PmodlensSourceSet=${sourceSet}`, ':modlensExport'],
|
|
23
|
+
{ cwd: root, env: process.env, stdio: 'inherit', timeout: 1200_000 });
|
|
24
|
+
let passed = false;
|
|
25
|
+
try {
|
|
26
|
+
if (moddev) {
|
|
27
|
+
await write('settings.gradle', "pluginManagement { repositories { gradlePluginPortal(); maven { url = 'https://maven.neoforged.net/releases' } } }\nrootProject.name = 'modlens-at-smoke'\n");
|
|
28
|
+
await write('build.gradle', "plugins { id 'java'; id 'net.neoforged.moddev' version '2.0.141' }\njava { toolchain { languageVersion = JavaLanguageVersion.of(21) } }\nneoForge { version = '21.1.209' }\n");
|
|
29
|
+
await write('gradle.properties', 'minecraft_version=1.21.1\norg.gradle.jvmargs=-Xmx3G\n');
|
|
30
|
+
await write('src/main/resources/META-INF/accesstransformer.cfg', '# baseline\n');
|
|
31
|
+
} else {
|
|
32
|
+
await write('settings.gradle', "rootProject.name = 'modlens-classpath-smoke'\ninclude 'library'\n");
|
|
33
|
+
await write('build.gradle', "plugins { id 'java' }\ndependencies { implementation project(':library') }\nsourceSets { client { compileClasspath = sourceSets.main.compileClasspath } }\n");
|
|
34
|
+
await write('library/build.gradle', "plugins { id 'java' }\n");
|
|
35
|
+
await write('library/src/main/java/example/Target.java', 'package example; public class Target { private final int counter = 7; public int read() { return counter; } }\n');
|
|
36
|
+
}
|
|
37
|
+
run();
|
|
38
|
+
const key = (await readFile(join(root, '.gradle/modlens/project-key.txt'), 'utf8')).trim();
|
|
39
|
+
const store = new ProjectStore(join(root, 'server-projects'));
|
|
40
|
+
const first = await store.importBuffer(key, await readFile(join(root, 'build/modlens/main/environment.zip')));
|
|
41
|
+
const target = moddev ? 'net.minecraft.world.level.Level' : 'example.Target';
|
|
42
|
+
const fieldName = moddev ? 'isDebug' : 'counter';
|
|
43
|
+
const field = async id => (await store.members(key, id, target)).result.fields.find(f => f.name === fieldName);
|
|
44
|
+
const before = await field(first.environmentId);
|
|
45
|
+
assert.ok(before, `Missing ${fieldName}`);
|
|
46
|
+
assert.ok(before.access & 0x10, 'baseline field must be final');
|
|
47
|
+
if (moddev) await write('src/main/resources/META-INF/accesstransformer.cfg', 'public-f net.minecraft.world.level.Level isDebug\n');
|
|
48
|
+
else await write('library/src/main/java/example/Target.java', 'package example; public class Target { public int counter = 7; public int read() { return counter; } }\n');
|
|
49
|
+
run();
|
|
50
|
+
assert.equal((await readFile(join(root, '.gradle/modlens/project-key.txt'), 'utf8')).trim(), key, 'export must preserve private key');
|
|
51
|
+
const second = await store.importBuffer(key, await readFile(join(root, 'build/modlens/main/environment.zip')));
|
|
52
|
+
assert.notEqual(first.environmentId, second.environmentId);
|
|
53
|
+
const after = await field(second.environmentId);
|
|
54
|
+
assert.ok(after.access & 1, 'transformed field must be public');
|
|
55
|
+
assert.equal(after.access & 0x10, 0, 'transformed field must not be final');
|
|
56
|
+
assert.ok((await field(first.environmentId)).access & 0x10, 'baseline must stay final');
|
|
57
|
+
const source = await store.source(key, second.environmentId, target, 1, 1000);
|
|
58
|
+
assert.match(source.source, new RegExp(`public (?!final)\\w+ ${fieldName}`));
|
|
59
|
+
if (moddev) assert.equal(source.origin, 'gradle-sources', 'adapter must supply actual transformed sources');
|
|
60
|
+
const search = await store.search(key, second.environmentId, `public ${moddev ? 'boolean' : 'int'} ${fieldName}`, 200);
|
|
61
|
+
assert.ok(search.results.some(r => r.className === target.replaceAll('.', '/')));
|
|
62
|
+
assert.equal((await store.list('f'.repeat(64))).length, 0);
|
|
63
|
+
if (!moddev) {
|
|
64
|
+
run('client'); // sibling :library has no client source set and must not break this export
|
|
65
|
+
const client = await store.importBuffer(key, await readFile(join(root, 'build/modlens/client/environment.zip')));
|
|
66
|
+
assert.equal(client.sourceSet, 'client');
|
|
67
|
+
assert.equal((await field(client.environmentId)).access, 1);
|
|
68
|
+
}
|
|
69
|
+
console.log(JSON.stringify({ passed: true, toolchain: second.toolchain, beforeAccess: before.access, afterAccess: after.access,
|
|
70
|
+
classCount: second.classCount, sourceCount: second.sourceCount, first: first.environmentId, second: second.environmentId }, null, 2));
|
|
71
|
+
// Keep a bundle for the optional HTTP smoke, without copying any project key into the repository.
|
|
72
|
+
if (process.env.MODLENS_KEEP_FIXTURE !== '1') passed = true;
|
|
73
|
+
} finally {
|
|
74
|
+
if (passed) await rm(root, { recursive: true, force: true });
|
|
75
|
+
else console.log(`Fixture retained: ${root}`);
|
|
76
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Real HTTP MCP transport and shipped uploader smoke. Uses a disposable server/cache on loopback.
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
5
|
+
import { mkdtemp, writeFile, readFile, rm } from 'node:fs/promises';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { createServer } from 'node:net';
|
|
10
|
+
import { once } from 'node:events';
|
|
11
|
+
import AdmZip from 'adm-zip';
|
|
12
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
13
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
14
|
+
|
|
15
|
+
const repo = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
|
+
const root = await mkdtemp(join(tmpdir(), 'modlens-http-smoke-'));
|
|
17
|
+
const listener = createServer();
|
|
18
|
+
listener.listen(0, '127.0.0.1'); await once(listener, 'listening');
|
|
19
|
+
const port = listener.address().port;
|
|
20
|
+
await new Promise(resolveClose => listener.close(resolveClose));
|
|
21
|
+
const endpoint = `http://127.0.0.1:${port}/mcp`;
|
|
22
|
+
const keyFile = process.argv[3] ?? join(root, 'key.txt');
|
|
23
|
+
const bundlePath = process.argv[2] ?? join(root, 'environment.zip');
|
|
24
|
+
const target = process.argv[4] ?? 'example.Target';
|
|
25
|
+
const key = process.argv[3] ? (await readFile(keyFile, 'utf8')).trim() : randomBytes(32).toString('hex');
|
|
26
|
+
if (!process.argv[2]) {
|
|
27
|
+
await writeFile(keyFile, `${key}\n`);
|
|
28
|
+
const jar = new AdmZip();
|
|
29
|
+
jar.addFile('example/Target.class', Buffer.from('test class entry'));
|
|
30
|
+
jar.addFile('example/Target.java', Buffer.from('package example; public class Target { public int counter; }'));
|
|
31
|
+
// An incompressible payload exercises multiple full upload chunks.
|
|
32
|
+
jar.addFile('payload.bin', randomBytes(2 * 1024 * 1024));
|
|
33
|
+
const bytes = jar.toBuffer();
|
|
34
|
+
const bundle = new AdmZip();
|
|
35
|
+
bundle.addFile('artifacts/0.jar', bytes);
|
|
36
|
+
bundle.addFile('manifest.json', Buffer.from(JSON.stringify({ format: 'modlens-project-v1', project: 'http-smoke:', sourceSet: 'main',
|
|
37
|
+
toolchain: 'gradle-compile-classpath', minecraftVersion: '', loaderVersion: '', mappings: 'compile-classpath', javaVersion: 21, transformations: [],
|
|
38
|
+
artifacts: [{ path: 'artifacts/0.jar', name: 'prepared.jar', size: bytes.length, sha256: createHash('sha256').update(bytes).digest('hex'), kind: 'classpath' }] })));
|
|
39
|
+
await writeFile(bundlePath, bundle.toBuffer());
|
|
40
|
+
}
|
|
41
|
+
const env = { ...process.env, MCP_PORT: String(port), MCP_HOST: '127.0.0.1', MODLENS_AUTO_EMBED: '0',
|
|
42
|
+
MODLENS_CACHE_ROOT: join(root, 'cache'), MODLENS_HOME: root, DATABASE_URL: `file:${join(root, 'unused.db')}`, MODLENS_VERBOSE: '1' };
|
|
43
|
+
const server = spawn(process.execPath, [join(repo, 'dist/server.js')], { cwd: root, env, stdio: ['ignore', 'ignore', 'pipe'] });
|
|
44
|
+
let logs = '';
|
|
45
|
+
server.stderr.on('data', b => { logs += b; });
|
|
46
|
+
const stopped = once(server, 'exit');
|
|
47
|
+
const client = new Client({ name: 'project-http-test', version: '1.0.0' });
|
|
48
|
+
let passed = false;
|
|
49
|
+
try {
|
|
50
|
+
await new Promise((resolveReady, reject) => {
|
|
51
|
+
const timer = setTimeout(() => reject(new Error('HTTP server startup timed out')), 30_000);
|
|
52
|
+
const ready = () => { if (logs.includes('listening on')) { clearTimeout(timer); server.stderr.off('data', ready); resolveReady(); } };
|
|
53
|
+
server.stderr.on('data', ready);
|
|
54
|
+
server.once('error', reject);
|
|
55
|
+
server.once('exit', () => { clearTimeout(timer); reject(new Error(`Server exited before startup: ${logs}`)); });
|
|
56
|
+
ready();
|
|
57
|
+
});
|
|
58
|
+
const uploader = spawn(process.execPath, [join(repo, 'scripts/project-upload.mjs'), endpoint, bundlePath, keyFile], { cwd: root, env, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
59
|
+
let output = ''; let error = '';
|
|
60
|
+
uploader.stdout.on('data', b => { output += b; }); uploader.stderr.on('data', b => { error += b; });
|
|
61
|
+
const [code] = await once(uploader, 'exit');
|
|
62
|
+
assert.equal(code, 0, error);
|
|
63
|
+
assert.ok(!output.includes(key), 'uploader must not print project key');
|
|
64
|
+
const imported = JSON.parse(output);
|
|
65
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(endpoint)));
|
|
66
|
+
const call = (action, args = {}) => client.callTool({ name: 'project', arguments: { action, projectKey: key, environmentId: imported.environmentId, ...args } }, undefined, { timeout: 300_000 });
|
|
67
|
+
const tools = await client.listTools();
|
|
68
|
+
assert.ok(tools.tools.some(t => t.name === 'project'));
|
|
69
|
+
const source = await call('source', { className: target });
|
|
70
|
+
assert.ok(!source.isError, JSON.stringify(source));
|
|
71
|
+
assert.ok(JSON.parse(source.content[0].text).source.length > 0);
|
|
72
|
+
if (process.argv[5]) {
|
|
73
|
+
const members = await call('members', { className: target });
|
|
74
|
+
assert.ok(!members.isError, JSON.stringify(members));
|
|
75
|
+
const field = JSON.parse(members.content[0].text).result.fields.find(f => f.name === process.argv[5]);
|
|
76
|
+
assert.equal(field?.access, 1, 'remote member view must preserve the public, non-final AT result');
|
|
77
|
+
const searched = await call('search', { query: `public boolean ${process.argv[5]}`, limit: 200 });
|
|
78
|
+
assert.ok(!searched.isError, JSON.stringify(searched));
|
|
79
|
+
assert.ok(JSON.parse(searched.content[0].text).results.some(r => r.className === target.replaceAll('.', '/')));
|
|
80
|
+
}
|
|
81
|
+
const wrongKey = await call('info', { projectKey: randomBytes(32).toString('hex') });
|
|
82
|
+
assert.ok(wrongKey.isError);
|
|
83
|
+
const local = await call('import_local', { bundlePath });
|
|
84
|
+
assert.ok(local.isError, 'HTTP must reject host-local import');
|
|
85
|
+
const failedChunk = await call('upload_chunk', { uploadId: 'f'.repeat(64), offset: 0, data: 'SENSITIVE_PAYLOAD' });
|
|
86
|
+
assert.ok(failedChunk.isError);
|
|
87
|
+
const large = await fetch(endpoint, { method: 'POST', body: 'x'.repeat(9 * 1024 * 1024) });
|
|
88
|
+
assert.equal(large.status, 413);
|
|
89
|
+
assert.ok(!logs.includes(key), 'server logs must redact project key');
|
|
90
|
+
assert.ok(!logs.includes('SENSITIVE_PAYLOAD'), 'server logs must redact upload bytes');
|
|
91
|
+
console.log(`PASS: HTTP upload, ${imported.classCount} classes, source query, project isolation, host-path rejection, body limits and log redaction`);
|
|
92
|
+
passed = true;
|
|
93
|
+
} finally {
|
|
94
|
+
await client.close();
|
|
95
|
+
server.kill(); await stopped;
|
|
96
|
+
if (passed) await rm(root, { recursive: true, force: true });
|
|
97
|
+
else console.log(`HTTP fixture retained: ${root}`);
|
|
98
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
// npm ci generates the default PostgreSQL client. Generate SQLite before Vitest
|
|
8
|
+
// imports application modules, including when tests run before the build in CI.
|
|
9
|
+
export default function setup() {
|
|
10
|
+
execFileSync(process.execPath, [
|
|
11
|
+
require.resolve("prisma/build/index.js"), "generate",
|
|
12
|
+
"--schema", fileURLToPath(new URL("../prisma/backends/schema.sqlite.prisma", import.meta.url)),
|
|
13
|
+
], {
|
|
14
|
+
cwd: fileURLToPath(new URL("..", import.meta.url)),
|
|
15
|
+
env: { ...process.env, PRISMA_HIDE_UPDATE_MESSAGE: "1" },
|
|
16
|
+
stdio: "pipe",
|
|
17
|
+
});
|
|
18
|
+
}
|