From 3f8af1f3592f5da13fd5b9eaace06378dceb622f Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Fri, 5 Jun 2026 17:23:10 +0200 Subject: [PATCH] fix: only run husky in a git checkout so npm consumers don't break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit postinstall ran husky unconditionally. npm executes a dependency's postinstall for every consumer, but husky is a devDependency and isn't installed in a consumer's tree, so `npm install stream-chat-react` failed with `code 127 · husky: command not found`. Yarn Berry runs the root workspace's postinstall on `yarn install` but not its prepare, so husky must stay in postinstall; the fix is to stop running it for consumers. postinstall now invokes a dev-only scripts/install-husky.mjs only when present, and that file is intentionally not in package.json#files, so consumers never receive it and the guard short-circuits to a no-op. The invocation runs via node (not a shell `|| true`) for Windows compatibility, and genuine husky setup errors surface instead of being swallowed. Ports GetStream/stream-chat-js#1764. --- package.json | 2 +- scripts/install-husky.mjs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 scripts/install-husky.mjs diff --git a/package.json b/package.json index 44b0b2d9c..e5d1c58f0 100644 --- a/package.json +++ b/package.json @@ -196,7 +196,7 @@ "start:css": "node scripts/watch-styling.mjs", "start:tutorial": "yarn workspace @stream-io/stream-chat-react-tutorial dev", "start:vite": "yarn workspace @stream-io/stream-chat-react-vite dev", - "postinstall": "husky", + "postinstall": "node -e \"require('fs').existsSync('scripts/install-husky.mjs') && import('./scripts/install-husky.mjs')\"", "test": "vitest run", "test:watch": "vitest", "types": "tsc --emitDeclarationOnly false --noEmit", diff --git a/scripts/install-husky.mjs b/scripts/install-husky.mjs new file mode 100644 index 000000000..a00e4212b --- /dev/null +++ b/scripts/install-husky.mjs @@ -0,0 +1,11 @@ +import { existsSync } from 'node:fs'; + +// husky installs this repo's local git hooks and is a dev-only dependency. It is +// invoked from a presence-guarded postinstall (see package.json) so it never runs +// for consumers — this file is intentionally not published. The .git check is a +// secondary guard for non-checkout environments; husky's own default() already +// no-ops gracefully on a missing .git or HUSKY=0, and any genuine setup error is +// left to surface rather than be swallowed. See GetStream/stream-chat-js#1763. +if (existsSync('.git')) { + (await import('husky')).default(); +}