diff --git a/.github/workflows/external-tests.yml b/.github/workflows/external-tests.yml index 8cf071f4..9eeeed74 100644 --- a/.github/workflows/external-tests.yml +++ b/.github/workflows/external-tests.yml @@ -208,6 +208,10 @@ jobs: { "name": "@ff-labs/fff-bin-linux-x64-musl", "version": "0.0.0" } JSON + # fff-node builds with bun; the npm `bun` package ships musl binaries + - name: Install bun + run: npm install -g bun + - name: Build fff-node working-directory: packages/fff-node run: npm run build diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5c6df145..c83e562a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -710,6 +710,8 @@ jobs: node-version: "25" registry-url: "https://registry.npmjs.org" + - uses: oven-sh/setup-bun@v2 + - name: Determine version id: version run: lua scripts/determine-version.lua @@ -747,6 +749,8 @@ jobs: make set-npm-version PKG=packages/fff-bun VERSION="$VERSION" cd packages/fff-bun + bun install --frozen-lockfile + bun run build npm publish --tag "$TAG" --access public --provenance - name: Publish Node.js package diff --git a/packages/fff-bun/package.json b/packages/fff-bun/package.json index 97ae109e..4118ba09 100644 --- a/packages/fff-bun/package.json +++ b/packages/fff-bun/package.json @@ -4,19 +4,24 @@ "private": false, "description": "High-performance fuzzy file finder for Bun - perfect for LLM agent tools", "type": "module", - "main": "src/index.ts", - "types": "src/index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "exports": { ".": { - "import": "./src/index.ts", - "types": "./src/index.ts" - } + "types": "./dist/index.d.ts", + "bun": "./src/index.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" }, "files": [ + "dist", "src", "examples" ], "scripts": { + "build": "bun build ./src/index.ts --format=esm --target=bun --sourcemap=external --outdir dist && tsc -p tsconfig.build.json", "test": "bun test test/", "typecheck": "tsc --noEmit", "demo": "bun ./examples/search.ts" diff --git a/packages/fff-bun/tsconfig.build.json b/packages/fff-bun/tsconfig.build.json new file mode 100644 index 00000000..14a6bcbe --- /dev/null +++ b/packages/fff-bun/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "emitDeclarationOnly": true, + "noEmit": false + }, + "include": ["src/**/*"] +} diff --git a/packages/fff-node/package.json b/packages/fff-node/package.json index 5e501c75..acef58ef 100644 --- a/packages/fff-node/package.json +++ b/packages/fff-node/package.json @@ -4,19 +4,26 @@ "private": false, "description": "High-performance fuzzy file finder for Node.js - perfect for LLM agent tools", "type": "module", - "main": "dist/src/index.js", - "types": "dist/src/index.d.ts", + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "dist/index.d.ts", "exports": { ".": { - "import": "./dist/src/index.js", - "types": "./dist/src/index.d.ts" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" }, "files": [ "dist" ], "scripts": { - "build": "tsc", + "build": "npm run build:esm && npm run build:cjs && npm run build:types", + "build:esm": "bun build ./src/index.ts --format=esm --target=node --external ffi-rs --sourcemap=external --outdir dist", + "build:cjs": "bun build ./src/index.ts --format=cjs --target=node --external ffi-rs --sourcemap=external --outdir dist --entry-naming \"[name].cjs\"", + "build:types": "tsc -p tsconfig.build.json", "test": "node test/e2e.mjs && node test/watch.mjs", "typecheck": "tsc --noEmit" }, diff --git a/packages/fff-node/src/binary.ts b/packages/fff-node/src/binary.ts index 7e2c7aac..3477308c 100644 --- a/packages/fff-node/src/binary.ts +++ b/packages/fff-node/src/binary.ts @@ -16,6 +16,9 @@ import { getLibFilename, getNpmPackageName } from "./platform.js"; * Get the current file's directory */ function getCurrentDir(): string { + // CJS build: import.meta.url is inlined at bundle time, __dirname is the truth + if (typeof __dirname !== "undefined") return __dirname; + const url = import.meta.url; if (url.startsWith("file://")) { @@ -30,7 +33,7 @@ function getCurrentDir(): string { function getPackageDir(): string { const currentDir = getCurrentDir(); // In dev: src/ -> package root - // In dist: dist/src/ -> package root + // In dist: dist/ -> package root // We look for package.json to find the actual root let dir = currentDir; for (let i = 0; i < 5; i++) { diff --git a/packages/fff-node/test/e2e.mjs b/packages/fff-node/test/e2e.mjs index c24af737..86db7b7b 100644 --- a/packages/fff-node/test/e2e.mjs +++ b/packages/fff-node/test/e2e.mjs @@ -2,13 +2,13 @@ import { after, before, describe, it } from "node:test"; import { strict as assert } from "node:assert"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -import { FileFinder } from "../dist/src/index.js"; +import { FileFinder } from "../dist/index.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = resolve(__dirname, "..", "..", ".."); const normalizePath = (p) => p.replace(/\\/g, "/"); -/** @type {import("../dist/src/finder.js").FileFinder | null} */ +/** @type {import("../dist/finder.js").FileFinder | null} */ let finder = null; describe("fff-node", { concurrency: 1 }, () => { diff --git a/packages/fff-node/test/stress-515.mjs b/packages/fff-node/test/stress-515.mjs index d825430b..75a54e12 100644 --- a/packages/fff-node/test/stress-515.mjs +++ b/packages/fff-node/test/stress-515.mjs @@ -13,7 +13,7 @@ import { existsSync } from "node:fs"; import { dirname, resolve } from "node:path"; import process from "node:process"; import { fileURLToPath } from "node:url"; -import { FileFinder } from "../dist/src/index.js"; +import { FileFinder } from "../dist/index.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = resolve(__dirname, "..", "..", ".."); diff --git a/packages/fff-node/test/watch.mjs b/packages/fff-node/test/watch.mjs index 4c0b6fc6..2489edb3 100644 --- a/packages/fff-node/test/watch.mjs +++ b/packages/fff-node/test/watch.mjs @@ -15,7 +15,7 @@ import { mkdtempSync, realpathSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, sep } from "node:path"; import { promisify } from "node:util"; -import { FileFinder } from "../dist/src/index.js"; +import { FileFinder } from "../dist/index.js"; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -33,7 +33,7 @@ async function waitFor(cond, timeoutMs = 10_000) { /** All events delivered to a batch-callback mock, flattened across calls. */ const deliveredEvents = (fn) => fn.mock.calls.flatMap((call) => call.arguments[0]); -/** @type {import("../dist/src/finder.js").FileFinder | null} */ +/** @type {import("../dist/finder.js").FileFinder | null} */ let finder = null; /** @type {string} */ let baseDir = ""; @@ -237,7 +237,7 @@ describe("fff-node watch", { concurrency: 1 }, () => { import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; - import { FileFinder } from ${JSON.stringify(new URL("../dist/src/index.js", import.meta.url).href)}; + import { FileFinder } from ${JSON.stringify(new URL("../dist/index.js", import.meta.url).href)}; const dir = mkdtempSync(join(tmpdir(), "fff-watch-exit-")); writeFileSync(join(dir, "seed.txt"), "seed"); diff --git a/packages/fff-node/tsconfig.build.json b/packages/fff-node/tsconfig.build.json new file mode 100644 index 00000000..14a6bcbe --- /dev/null +++ b/packages/fff-node/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "emitDeclarationOnly": true, + "noEmit": false + }, + "include": ["src/**/*"] +}