Last active
December 27, 2025 05:32
-
-
Save danthegoodman1/021678f0aac498d7d644a70609109655 to your computer and use it in GitHub Desktop.
NPM Vendor in a package to a `vendor/` subdir. Helps against supply chain attacks, and makes it easier for LLMs to learn how packages work. Opus 4.5 did most of the work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Downloads an npm package and extracts it to the vendor directory | |
| # Does NOT install to node_modules - this is an alternative to npm install | |
| # | |
| # Usage: ./scripts/vendor-package.sh <package-name>[@version] | |
| # | |
| # Examples: | |
| # ./scripts/vendor-package.sh lodash | |
| # ./scripts/vendor-package.sh lodash@4.17.20 | |
| # ./scripts/vendor-package.sh @tanstack/react-query@5.0.0 | |
| set -e | |
| if [ -z "$1" ]; then | |
| echo "Usage: $0 <package-name>[@version]" | |
| echo "Examples:" | |
| echo " $0 lodash" | |
| echo " $0 lodash@4.17.20" | |
| echo " $0 @tanstack/react-query@5.0.0" | |
| exit 1 | |
| fi | |
| FULL_SPEC="$1" | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" | |
| VENDOR_DIR="$PROJECT_ROOT/vendor" | |
| # Parse package name from spec like "lodash@4.17.20" or "@tanstack/react-query@5.0.0" | |
| if [[ "$FULL_SPEC" =~ ^@ ]]; then | |
| # Scoped package: @scope/name or @scope/name@version | |
| SCOPE_AND_NAME="${FULL_SPEC#@}" # Remove leading @ | |
| if [[ "$SCOPE_AND_NAME" =~ ^([^/]+/[^@]+)(@.+)?$ ]]; then | |
| PACKAGE_NAME="@${BASH_REMATCH[1]}" | |
| else | |
| PACKAGE_NAME="$FULL_SPEC" | |
| fi | |
| else | |
| # Regular package: name or name@version | |
| if [[ "$FULL_SPEC" =~ ^([^@]+)(@.+)?$ ]]; then | |
| PACKAGE_NAME="${BASH_REMATCH[1]}" | |
| else | |
| PACKAGE_NAME="$FULL_SPEC" | |
| fi | |
| fi | |
| # Handle scoped packages: @tanstack/react-query -> tanstack/react-query | |
| VENDOR_SUBDIR="$VENDOR_DIR/${PACKAGE_NAME#@}" | |
| # Create a temp directory for downloading | |
| TEMP_DIR=$(mktemp -d) | |
| trap "rm -rf $TEMP_DIR" EXIT | |
| echo "Downloading $FULL_SPEC..." | |
| # Use npm pack to download the tarball (works without installing) | |
| cd "$TEMP_DIR" | |
| TARBALL=$(npm pack "$FULL_SPEC" 2>/dev/null) | |
| if [ ! -f "$TARBALL" ]; then | |
| echo "Error: Failed to download package '$FULL_SPEC'" | |
| exit 1 | |
| fi | |
| # Extract the tarball (npm pack creates a 'package' directory inside) | |
| tar -xzf "$TARBALL" | |
| if [ ! -d "package" ]; then | |
| echo "Error: Failed to extract package" | |
| exit 1 | |
| fi | |
| # Get the version from the extracted package.json | |
| INSTALLED_VERSION=$(node -p "require('./package/package.json').version" 2>/dev/null || echo "unknown") | |
| # Create vendor directory if it doesn't exist | |
| mkdir -p "$VENDOR_DIR" | |
| # Remove existing vendored copy if present | |
| if [ -d "$VENDOR_SUBDIR" ]; then | |
| echo "Removing existing vendored copy at $VENDOR_SUBDIR" | |
| rm -rf "$VENDOR_SUBDIR" | |
| fi | |
| # Create parent directory for scoped packages | |
| mkdir -p "$(dirname "$VENDOR_SUBDIR")" | |
| # Move the extracted package to vendor | |
| echo "Installing $PACKAGE_NAME@$INSTALLED_VERSION to $VENDOR_SUBDIR" | |
| mv "$TEMP_DIR/package" "$VENDOR_SUBDIR" | |
| echo "" | |
| echo "Done! Vendored $PACKAGE_NAME@$INSTALLED_VERSION to: $VENDOR_SUBDIR" | |
| echo "" | |
| echo "You can now import it with:" | |
| echo " import something from \"vendor/${PACKAGE_NAME#@}\"" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment