Skip to content

NPM Deployment Guide โ€‹

Publishing OpenPets packages to the npm registry.

๐Ÿ“ฆ Packages โ€‹

Core Package โ€‹

Name: openpetsLocation: src/core/Version: 1.0.4

Published without @ scope for simplicity.

Pet Packages โ€‹

Scope: @openpets/Location: pets/*/

Published with scope for organization.

Examples:

  • @openpets/maps (v1.0.7)
  • @openpets/email (v1.0.1)
  • @openpets/jira
  • @openpets/github

๐Ÿ”’ Security Best Practices โ€‹

2-Factor Authentication (2FA) โ€‹

  • Maintainers: Must have 2FA enabled on their npm accounts.
  • Automation: Use Granular Access Tokens with "Publish" permissions restricted to the @openpets scope and specific IP ranges if possible. Avoid using legacy tokens.

Namespace Protection โ€‹

Using the @openpets scope prevents "typo-squatting" attacks where malicious actors publish packages with similar names (e.g., openpets-mps vs @openpets/maps). Ensure all new plugins are added to the organization scope.

Pre-Flight Checks โ€‹

The publishing scripts include automated security checks:

  • Secret Scanning: Scans src/ for potential API keys or .env files before publishing.
  • Dependency Pinning: Workspace dependencies are resolved to specific versions to prevent supply chain drift.
  • File Whitelist: Only explicitly listed files are included (index.ts, src/, commands.json, etc.).
  • npmignore Template: Auto-generated .npmignore excludes test files, backups, debug scripts, and sensitive files.

Environment Variable Handling โ€‹

Pets use the standardized loadEnv() function from the openpets core package:

typescript
import { loadEnv } from "openpets"

export const MyPlugin = async () => {
  const env = loadEnv("my-plugin")
  const API_KEY = env.MY_API_KEY
  // ...
}

How loadEnv works:

  1. Loads from .env file in the project's working directory (not the package cache)
  2. Loads from .pets/config.json if it exists (pet-specific config)
  3. Returns only project-relevant environment variables

This ensures pets never load .env from their installed cache location, and credentials are never bundled with published packages.


๐Ÿš€ Publishing โ€‹

Prerequisites โ€‹

  1. Login to npm:

    bash
    npm login
    npm whoami  # Should show: raggle_npm
  2. Verify organization access: Visit: https://www.npmjs.com/settings/openpets/packages

Publish Core Package โ€‹

bash
cd src/core
npm publish --access public

Result:

+ openpets@1.0.4

Publish Individual Pet โ€‹

Use the publish-pet.ts script which handles workspace dependencies, security checks, and version management:

bash
# From repository root
bun scripts/publish-pet.ts <pet-name>

# Examples
bun scripts/publish-pet.ts maps
bun scripts/publish-pet.ts jira
bun scripts/publish-pet.ts gitlab

# Preview mode (dry-run)
bun scripts/publish-pet.ts maps --preview

# Publish to specific channel
bun scripts/publish-pet.ts maps --channel beta

What the publish script does:

  1. Ensures .npmignore exists with secure defaults
  2. Runs security scan for secrets/credentials
  3. Replaces workspace:* dependencies with actual versions
  4. Auto-bumps version if already published
  5. Applies whitelist file filter (only includes core files)
  6. Verifies tarball contents before publishing
  7. Publishes to npm registry

Result:

+ @openpets/maps@1.0.8

Publish All Pets โ€‹

bash
# From repository root
npm run publish:pets

Or manually with the script:

bash
for pet in maps email jira gitlab slack; do
  bun scripts/publish-pet.ts "$pet"
done

๐Ÿงช Testing Before Publish โ€‹

Dry Run โ€‹

Test without actually publishing:

bash
# Core
cd src/core
npm publish --dry-run --access public

# Pets
cd pets/maps
npm publish --dry-run --access public

Pack and Inspect โ€‹

Create a tarball to inspect what will be published:

bash
npm pack
tar -tzf openpets-1.0.4.tgz

โš™๏ธ Configuration โ€‹

package.json Settings โ€‹

Core package (src/core/package.json):

json
{
  "name": "openpets",
  "version": "1.0.4",
  "publishConfig": {
    "access": "public"
  },
  "bin": {
    "pets": "./cli.ts",
    "pets-mcp": "./mcp-server.ts"
  },
  "files": [
    "*.ts",
    "*.js",
    "*.d.ts",
    "ai-client-base/**/*",
    "!**/*.test.ts"
  ]
}

Pet package (pets/maps/package.json):

json
{
  "name": "@openpets/maps",
  "version": "1.0.7",
  "publishConfig": {
    "access": "public"
  }
}

Note: The files array is preserved if already present, or dynamically added by publish-pet.ts during publishing to ensure a consistent whitelist approach:

json
{
  "files": [
    "index.ts",
    "index.js",
    "client.ts",
    "client.js",
    "*.d.ts",
    "lib/**/*",
    "src/**/*",
    "commands.json",
    "public/**/*",
    "prompts/**/*",
    "README.md"
  ]
}

This whitelist approach ensures only core plugin files are published, automatically excluding test files, backups, and debug scripts.


๐Ÿ“‹ Files Included โ€‹

Core Package โ€‹

openpets@1.0.4
โ”œโ”€โ”€ cli.ts (pets command)
โ”œโ”€โ”€ mcp-server.ts (pets-mcp command)
โ”œโ”€โ”€ index.ts
โ”œโ”€โ”€ build-pet.ts
โ”œโ”€โ”€ validate-pet.ts
โ”œโ”€โ”€ logger.ts
โ”œโ”€โ”€ ai-client-base/
โ””โ”€โ”€ ... (23 files total)

Pet Package โ€‹

@openpets/maps@1.0.7
โ”œโ”€โ”€ index.ts
โ”œโ”€โ”€ commands.json
โ”œโ”€โ”€ opencode.json
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ providers/
โ”‚       โ”œโ”€โ”€ google-maps.ts
โ”‚       โ”œโ”€โ”€ mapbox.ts
โ”‚       โ””โ”€โ”€ openstreetmap.ts
โ””โ”€โ”€ ... (8 files total)

๐Ÿ”„ Version Management โ€‹

Bump Version โ€‹

bash
# From package directory
npm version patch  # 1.0.4 -> 1.0.5
npm version minor  # 1.0.4 -> 1.1.0
npm version major  # 1.0.4 -> 2.0.0

Using Bump Script โ€‹

bash
# From repository root
npm run bump

๐Ÿ“Š After Publishing โ€‹

Verify Publication โ€‹

bash
# Check core package
npm view openpets

# Check pet package
npm view @openpets/maps

# Check all versions
npm view openpets versions
npm view @openpets/maps versions

Test Installation โ€‹

bash
# Global install
npm install -g openpets
pets --version

# Local install
npm install @openpets/maps

Update Distribution Files โ€‹

After publishing to npm, update other distribution methods:

bash
./scripts/update-openpets-checksums.sh

This updates:

  • Homebrew formula checksums
  • PKGBUILD checksums
  • Distribution templates

๐Ÿท๏ธ NPM Tags โ€‹

Latest (Default) โ€‹

bash
npm publish --access public
# Published with tag: latest

Beta Release โ€‹

bash
npm publish --access public --tag beta

Users install with:

bash
npm install openpets@beta
npm install @openpets/maps@beta

Alpha Release โ€‹

bash
npm publish --access public --tag alpha

๐Ÿ” Access Control โ€‹

All packages use:

json
{
  "publishConfig": {
    "access": "public"
  }
}

This ensures packages are publicly accessible despite being in an organization.


โš ๏ธ Common Issues โ€‹

"Package already exists" โ€‹

Problem: Version already published

Solution:

bash
npm version patch
npm publish --access public

"403 Forbidden" โ€‹

Problem: Not logged in or wrong credentials

Solution:

bash
npm logout
npm login
npm whoami  # Verify: raggle_npm

"Invalid package name" โ€‹

Problem: Name has invalid characters (slashes without scope)

Solution: Use proper format:

  • โŒ openpets/maps
  • โœ… @openpets/maps

"ENEEDAUTH" โ€‹

Problem: Authentication token expired

Solution:

bash
npm login

๐Ÿ“ˆ NPM Stats โ€‹

View Package Info โ€‹

bash
npm info openpets
npm info @openpets/maps

Download Stats โ€‹

Visit:

Or use npm-stat:

bash
npx npm-stat openpets
npx npm-stat @openpets/maps

๐Ÿ”„ Deprecate a Version โ€‹

bash
npm deprecate openpets@1.0.3 "Please upgrade to 1.0.4"
npm deprecate @openpets/maps@1.0.6 "Use 1.0.7 instead"

๐Ÿ—‘๏ธ Unpublish (Use Carefully!) โ€‹

Warning: Can only unpublish within 72 hours, and it affects all users.

bash
# Unpublish specific version
npm unpublish openpets@1.0.4

# Unpublish entire package (dangerous!)
npm unpublish openpets --force

Better alternative: Use deprecate instead.


๐Ÿ” Security โ€‹

Pre-Publish Security Scan โ€‹

Always run security scan before publishing:

bash
# Run security check (fails on critical issues)
npm run security:check

# Or scan with verbose output
npm run security:scan:verbose

# Scan specific pet
bun scripts/security-scan.ts --dir pets/maps

The security scanner automatically detects:

  • Sensitive files (.env, private keys, credentials)
  • API keys (Google, OpenAI, GitHub, AWS, Stripe)
  • Hardcoded passwords
  • Database connection strings with credentials

Publishing will fail if critical issues are detected.

NPM Account Security โ€‹

Enable 2FA (Required):

bash
npm profile enable-2fa auth-and-writes

Create Granular Access Token:

bash
npm token create \
  --scope=@openpets \
  --description="GitHub Actions Publisher" \
  --expires=365d

See: Security Guide for comprehensive security documentation.


๐Ÿ“ Publishing Checklist โ€‹

Before publishing:

  • [ ] Preview mode passes: bun scripts/publish-pet.ts <pet> --preview
  • [ ] Tests pass: npm test
  • [ ] Pet uses loadEnv() from openpets (not local dotenv)
  • [ ] CHANGELOG.md updated
  • [ ] All changes committed
  • [ ] No .env files in package
  • [ ] No hardcoded API keys
  • [ ] No test files in tarball
  • [ ] 2FA enabled on npm account
  • [ ] Using granular access tokens (not classic)

After publishing:

  • [ ] Verify on npmjs.com
  • [ ] Test installation: npm install -g openpets
  • [ ] Update distribution checksums
  • [ ] Create git tag
  • [ ] Update documentation
  • [ ] Announce release

Note: Version bumping is handled automatically by publish-pet.ts if the version already exists.


๐Ÿ›ก๏ธ npmignore Management โ€‹

The ensure-npmignore.ts script maintains consistent .npmignore files across all pets:

bash
# Ensure all pets have .npmignore
bun scripts/ensure-npmignore.ts --all

# Overwrite existing .npmignore files
bun scripts/ensure-npmignore.ts --all --force

# Single pet
bun scripts/ensure-npmignore.ts pets/maps

Default npmignore template excludes:

  • Sensitive files: .env, *.pem, *.key, credentials*.json
  • Test files: test*.ts, *.test.ts, *.spec.ts
  • Debug files: debug-*.ts, diagnose-*.ts
  • Backup files: *-backup.ts, *.bak
  • Build artifacts: tsconfig.tsbuildinfo, *.log

๐Ÿ†˜ Support โ€‹