
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
forge-npm-pkg
Advanced tools
A CLI tool to scaffold production-ready npm packages with modern best practices
A powerful CLI tool to scaffold production-ready npm packages with modern best practices.
@arethetypeswrong/clipackage.json exports configurationnpx forge-npm-pkg my-awesome-package
Or without specifying a name (you'll be prompted):
npx forge-npm-pkg
The CLI will ask you several questions and generate a complete project structure:
my-awesome-package/
├── src/
│ ├── index.ts (or .js)
│ └── index.test.ts (if testing enabled)
├── .github/
│ ├── workflows/
│ │ ├── ci.yml (if CI enabled)
│ │ ├── publish.yml (if CD enabled)
│ │ └── dependabot-auto-merge.yml (if Dependabot enabled)
│ └── dependabot.yml (if Dependabot enabled)
├── package.json
├── tsconfig.json (if TypeScript)
├── tsup.config.ts (if TypeScript)
├── vitest.config.ts (if Vitest selected)
├── jest.config.ts (if Jest selected)
├── eslint.config.js (if linting enabled)
├── .prettierrc (if linting enabled)
├── .gitignore
└── README.md
Your generated package will have:
npm run build - Build the package with tsupnpm test - Run testsnpm run lint - Lint your codenpm run format - Format code with Prettiernpm run check:exports - Validate package exportsnpm run typecheck - Type-check TypeScript (if applicable)package.json includes correctly configured exports field for maximum compatibilityModern ECMAScript modules with import/export syntax.
{
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
}
}
Legacy Node.js module format with require().
{
"type": "commonjs",
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js"
}
}
}
Exports both ESM and CommonJS for maximum compatibility.
{
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
}
}
This section walks you through the entire process of creating and publishing an npm package with automated CI/CD.
Create your package with automated publishing enabled:
npx forge-npm-pkg my-awesome-package
Select these options:
The tool will:
gh CLI is available)If you have the GitHub CLI installed and authenticated, the tool will prompt you to create a GitHub repository automatically:
◆ Create GitHub repository?
│ ○ Public repository
│ ○ Private repository
│ ● Skip - I'll create it manually
If you skip or don't have gh CLI:
cd my-awesome-package
# Create repository on GitHub (using GitHub CLI)
gh repo create my-awesome-package --public --source=. --remote=origin --push
# Or manually:
# 1. Go to https://github.com/new
# 2. Create repository named "my-awesome-package"
# 3. Add remote and push:
git remote add origin https://github.com/yourusername/my-awesome-package.git
git branch -M main
git push -u origin main
To enable automated publishing, you need to add your npm token to GitHub:
A. Create NPM Access Token:
npm_...)B. Add Token to GitHub:
# Using GitHub CLI (recommended)
gh secret set NPM_TOKEN
# Or manually:
# 1. Go to https://github.com/yourusername/my-awesome-package/settings/secrets/actions
# 2. Click "New repository secret"
# 3. Name: NPM_TOKEN
# 4. Value: [paste your npm token]
# 5. Click "Add secret"
💡 Tip: If you need to view your npm token locally, use:
npm run token
This displays your .npmrc file contents, making it easy to copy the token for CI/CD setup.
Write your code:
// src/index.ts
export function greet(name: string): string {
return `Hello, ${name}!`;
}
export function add(a: number, b: number): number {
return a + b;
}
Write tests:
// src/index.test.ts
import { describe, it, expect } from 'vitest';
import { greet, add } from './index.js';
describe('greet', () => {
it('should return a greeting message', () => {
expect(greet('World')).toBe('Hello, World!');
});
});
describe('add', () => {
it('should add two numbers correctly', () => {
expect(add(2, 3)).toBe(5);
});
});
Run tests locally:
npm test # Run tests
npm run build # Build package
npm run typecheck # Type checking
npm run lint # Lint code
git add .
git commit -m "feat: add greet function"
git push
What happens automatically:
When you're ready to publish to npm:
# Bump version based on change type
npm version patch # Bug fixes: 1.0.0 → 1.0.1
npm version minor # New features: 1.0.0 → 1.1.0
npm version major # Breaking changes: 1.0.0 → 2.0.0
# Push the tag
git push && git push --tags
What happens automatically when you push the tag:
# Check npm
npm view my-awesome-package
# Install in another project
npm install my-awesome-package
For every new feature or bug fix:
# 1. Make changes
vim src/index.ts
# 2. Write tests
vim src/index.test.ts
# 3. Run tests locally
npm test
# 4. Commit and push
git add .
git commit -m "fix: resolve edge case in greet()"
git push
# 5. Wait for CI to pass
# 6. When ready to release:
npm version patch # or minor/major
git push && git push --tags
# 7. Package auto-publishes to npm!
You can commit multiple changes before creating a release:
# Feature 1
git add .
git commit -m "feat: add multiply function"
git push
# Feature 2
git add .
git commit -m "feat: add divide function"
git push
# Bug fix
git add .
git commit -m "fix: handle negative numbers"
git push
# All CI checks pass, now release
npm version minor # Bump version for new features
git push && git push --tags # Auto-publishes to npm
All changes since the last release will be included.
# Fix critical bug
vim src/index.ts
npm test
# Push immediately
git add .
git commit -m "fix: critical bug in production"
git push
# Wait for CI to pass, then release
npm version patch
git push && git push --tags
# Package publishes automatically
If you need to publish manually (bypass CI/CD):
# Build and publish
npm run build
npm publish --access public
┌─────────────────────────────────────────────────────────┐
│ 1. Developer writes code + tests │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 2. git commit + git push │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 3. GitHub Actions CI runs (tests, lint, build) │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 4. Developer runs: npm version patch/minor/major │
│ - Bumps version in package.json │
│ - Creates git commit and tag │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 5. git push && git push --tags │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 6. GitHub Actions Publish workflow triggers │
│ - Installs dependencies │
│ - Runs tests │
│ - Builds package │
│ - Publishes to npm │
└─────────────────────────────────────────────────────────┘
CI fails on push:
npm run build and npm test locally firstNPM_TOKEN error during publish:
Publish workflow not triggering:
git push --tagsv* (e.g., v1.0.0).github/workflows/publish.yml existsPackage not publishing:
Save your author information once and reuse it for future projects:
# First time - you'll be prompted to save
npx forge-npm-pkg my-package
# Enter your name, email, GitHub username
# Choose "Yes" when asked to save for future projects
# Future runs - config loaded automatically
npx forge-npm-pkg another-package
# Your info is pre-filled!
Smart Git Integration:
Config Commands:
# View stored configuration
npx forge-npm-pkg --config
# Reset stored configuration
npx forge-npm-pkg --reset-config
# Skip saving config this time
npx forge-npm-pkg my-package --no-save
Storage Location:
C:\Users\{user}\AppData\Roaming\forge-npm-pkg\config.json~/.config/forge-npm-pkg/config.jsonThis tool uses dynamic version fetching to ensure your projects always start with the latest stable package versions.
When you run forge-npm-pkg, it:
Latest Package Versions:
{
"devDependencies": {
"typescript": "^5.7.2", // ✓ Latest fetched today
"vitest": "^2.1.5", // ✓ Latest fetched today
"eslint": "^9.15.0" // ✓ Latest fetched today
}
}
Current Node.js LTS:
{
"engines": {
"node": ">=20.0.0" // ✓ Current LTS requirement
}
}
Dynamic CI Matrix:
strategy:
matrix:
node-version: [20, 22] # ✓ Active LTS versions
Latest GitHub Actions:
steps:
- uses: actions/checkout@v5 # ✓ Latest major version
- uses: actions/setup-node@v6 # ✓ Latest major version
- uses: codecov/codecov-action@v5 # ✓ Latest major version
If a package was just released, you'll see:
⚠️ Package Version Warnings
⚠️ typescript@6.0.0 (3 days old)
New major version - may contain breaking changes.
If issues occur, downgrade: npm install typescript@5
You run the tool today (January 2025):
You run the tool in October 2025:
git clone https://github.com/yourusername/forge-npm-pkg
cd forge-npm-pkg
npm install
npm run build
This project uses a multi-layered testing approach to ensure quality:
Test individual generator functions and validators:
npm test # Run unit tests once
npm run test:watch # Run in watch mode
npm run test:coverage # Generate coverage report
npm run test:ui # Interactive UI mode
Automated end-to-end tests that verify the full CLI workflow:
npm run test:e2e # Creates project, runs build and tests
Quick scripts to manually test the CLI flow and UX:
npm run dev:test # Interactive mode - experience all prompts
npm run dev:test:quick # Quick mode with -y flag
These generate projects in .dev-test/ which is auto-cleaned and gitignored.
Why separate dev testing?
Automated testing on every push:
npm run test:all # Typecheck + Unit + E2E
npm link
forge-npm-pkg test-package
This project includes an interactive release automation tool:
npm run release
The script provides a beautiful interactive experience with @clack/prompts:
Features:
See scripts/README.md for detailed documentation.
Manual alternative:
npm run sync # Pull latest + install + test
npm run test:all # Verify everything passes
git add .
git commit -m "feat: your message"
npm version patch # or minor, or major
git push && git push --tags
Creating a properly configured npm package is complex:
package.json exportsThis tool eliminates the guesswork and gives you a production-ready setup in seconds.
MIT
This project uses Dependabot to automate dependency updates with a smart grouping strategy.
When you enable Dependabot, the tool generates an auto-merge workflow that:
Required GitHub Settings:
To enable auto-merge, configure these settings in your repository:
Enable auto-merge:
Allow GitHub Actions to approve PRs:
Once configured, Dependabot PRs for patch/minor updates will automatically merge after CI passes.
Dependencies are grouped for easier management:
This reduces PR volume while keeping production dependencies separate for safety.
When Dependabot creates PRs while you're working locally:
Push your local work first
git add .
git commit -m "your changes"
git push
Merge Dependabot PR on GitHub
Sync your local repository
npm run sync
This runs: git pull --rebase && npm install && npm test
Or use npm run sync:quick to skip tests (faster):
npm run sync:quick
If package-lock.json changed, commit and push
git add package-lock.json
git commit -m "chore: update package-lock.json after merge"
git push
Contributions are welcome! Please open an issue or PR.
FAQs
A CLI tool to scaffold production-ready npm packages with modern best practices
We found that forge-npm-pkg demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.