diff --git a/mcp-server/package.json b/mcp-server/package.json index d306b59..f0f90fa 100644 --- a/mcp-server/package.json +++ b/mcp-server/package.json @@ -18,10 +18,10 @@ "description": "Currents MCP server", "main": "./dist/api.cjs", "module": "./dist/api.mjs", - "types": "./dist/api.d.ts", + "types": "./dist/api.d.mts", "exports": { ".": { - "types": "./dist/api.d.ts", + "types": "./dist/api.d.mts", "import": "./dist/api.mjs", "require": "./dist/api.cjs" } diff --git a/mcp-server/src/cli-bin.integration.test.ts b/mcp-server/src/cli-bin.integration.test.ts index e9e214e..3cfaac8 100644 --- a/mcp-server/src/cli-bin.integration.test.ts +++ b/mcp-server/src/cli-bin.integration.test.ts @@ -12,19 +12,19 @@ * (same artifact shape as registry install, minus release-only publish.cjs * mutations). */ -import { execFileSync, spawnSync } from "node:child_process"; import { existsSync, mkdtempSync, readdirSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; +import { execNpm, spawnNpx } from "../test/npm-exec.js"; const root = fileURLToPath(new URL("..", import.meta.url)); const buildIndex = path.join(root, "dist", "index.mjs"); function packTarball(packDest: string): string { // Respect `files` and standard pack rules; do not mutate package.json (unlike release `publish.cjs`). - execFileSync("npm", ["pack", "--ignore-scripts", "--pack-destination", packDest], { + execNpm(["pack", "--ignore-scripts", "--pack-destination", packDest], { cwd: root, stdio: ["ignore", "pipe", "pipe"], }); @@ -50,7 +50,7 @@ describe.skipIf(!existsSync(buildIndex))( it("starts via npx --package tarball mcp", () => { const packDir = mkdtempSync(path.join(tmpdir(), "mcp-pack-")); const tarball = packTarball(packDir); - const r = spawnSync("npx", ["-y", "--package", tarball, "mcp"], { + const r = spawnNpx(["-y", "--package", tarball, "mcp"], { cwd: packDir, timeout: 45_000, encoding: "utf-8", @@ -80,11 +80,11 @@ describe.skipIf(!existsSync(buildIndex))( const packDir = mkdtempSync(path.join(tmpdir(), "mcp-pack-")); const installDir = mkdtempSync(path.join(tmpdir(), "mcp-install-")); const tarball = packTarball(packDir); - execFileSync("npm", ["init", "-y"], { + execNpm(["init", "-y"], { cwd: installDir, stdio: "ignore", }); - execFileSync("npm", ["install", tarball], { + execNpm(["install", tarball], { cwd: installDir, stdio: "ignore", }); diff --git a/mcp-server/src/package-published-esm.integration.test.ts b/mcp-server/src/package-published-esm.integration.test.ts index d2dcf2f..065392a 100644 --- a/mcp-server/src/package-published-esm.integration.test.ts +++ b/mcp-server/src/package-published-esm.integration.test.ts @@ -29,11 +29,18 @@ * layout. * */ import { execFileSync } from "node:child_process"; -import { copyFileSync, existsSync, mkdtempSync, readdirSync } from "node:fs"; +import { + copyFileSync, + existsSync, + mkdtempSync, + readFileSync, + readdirSync, +} from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; +import { execNpm } from "../test/npm-exec.js"; const root = fileURLToPath(new URL("..", import.meta.url)); const buildIndex = path.join(root, "dist", "index.mjs"); @@ -41,7 +48,7 @@ const buildIndex = path.join(root, "dist", "index.mjs"); /** Run `npm pack` from the package root and return the path to the single `.tgz` in `packDest`. */ function packTarball(packDest: string): string { // Respect `files` and standard pack rules; do not mutate package.json (unlike release `publish.cjs`). - execFileSync("npm", ["pack", "--ignore-scripts", "--pack-destination", packDest], { + execNpm(["pack", "--ignore-scripts", "--pack-destination", packDest], { cwd: root, stdio: ["ignore", "pipe", "pipe"], }); @@ -62,11 +69,11 @@ describe.skipIf(!existsSync(buildIndex))( path.join(tmpdir(), "mcp-install-published-") ); const tarball = packTarball(packDir); - execFileSync("npm", ["init", "-y"], { + execNpm(["init", "-y"], { cwd: installDir, stdio: "ignore", }); - execFileSync("npm", ["install", tarball], { + execNpm(["install", tarball], { cwd: installDir, stdio: "ignore", }); @@ -84,5 +91,32 @@ describe.skipIf(!existsSync(buildIndex))( }); expect(out.trim()).toBe("published-esm-ok"); }); + + it("ships package metadata that points at existing declaration files", () => { + const packDir = mkdtempSync(path.join(tmpdir(), "mcp-pack-types-")); + const installDir = mkdtempSync(path.join(tmpdir(), "mcp-install-types-")); + const tarball = packTarball(packDir); + execNpm(["init", "-y"], { + cwd: installDir, + stdio: "ignore", + }); + execNpm(["install", tarball], { + cwd: installDir, + stdio: "ignore", + }); + const installedRoot = path.join( + installDir, + "node_modules", + "@currents", + "mcp" + ); + const pkg = JSON.parse( + readFileSync(path.join(installedRoot, "package.json"), "utf-8") + ); + expect(existsSync(path.join(installedRoot, pkg.types))).toBe(true); + expect(existsSync(path.join(installedRoot, pkg.exports["."].types))).toBe( + true + ); + }); } ); diff --git a/mcp-server/test/npm-exec.ts b/mcp-server/test/npm-exec.ts new file mode 100644 index 0000000..56b3e1b --- /dev/null +++ b/mcp-server/test/npm-exec.ts @@ -0,0 +1,26 @@ +import { execFileSync, spawnSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import path from "node:path"; + +const npmCli = process.env.npm_execpath; +const npxCli = npmCli ? path.join(path.dirname(npmCli), "npx-cli.js") : undefined; + +export function execNpm( + args: string[], + options: Parameters[2] +) { + if (npmCli) { + return execFileSync(process.execPath, [npmCli, ...args], options); + } + return execFileSync("npm", args, options); +} + +export function spawnNpx( + args: string[], + options: Parameters[2] +) { + if (npxCli && existsSync(npxCli)) { + return spawnSync(process.execPath, [npxCli, ...args], options); + } + return spawnSync("npx", args, options); +}