@serve.zone/nupst
v5.1.5
Published
Network UPS Shutdown Tool - Monitor SNMP-enabled UPS devices and orchestrate graceful system shutdowns during power emergencies
Maintainers
Readme
NUPST Migration Plan: Node.js → Deno v4.0.0
Migration Goal: Convert NUPST from Node.js to Deno with single-executable distribution Version: 3.1.2 → 4.0.0 (breaking changes) Platforms: Linux x64/ARM64, macOS x64/ARM64, Windows x64
Phase 0: Planning & Preparation
- [x] Research Deno compilation targets and npm: specifier support
- [x] Analyze current codebase structure and dependencies
- [x] Define CLI command structure simplification
- [x] Create detailed migration task list
- [ ] Create feature branch:
migration/deno-v4 - [ ] Backup current working state with git tag:
v3.1.2-pre-deno-migration
Phase 1: Dependency Migration (4-6 hours)
1.1 Analyze Current Dependencies
- [ ] List all production dependencies from
package.json- Current:
[email protected]
- Current:
- [ ] List all dev dependencies to be removed
@git.zone/tsbuild,@git.zone/tsrun,@git.zone/tstest,@push.rocks/qenv,@push.rocks/tapbundle,@types/node
- [ ] Identify Node.js built-in module usage
child_process(execSync)https(for version checking)fs(readFileSync, writeFileSync, existsSync, mkdirSync)path(join, dirname, resolve)
1.2 Create Deno Configuration
- [ ] Create
deno.jsonwith project configuration{ "name": "@serve.zone/nupst", "version": "4.0.0", "exports": "./mod.ts", "tasks": { "dev": "deno run --allow-all mod.ts", "compile": "deno task compile:all", "compile:all": "bash scripts/compile-all.sh", "test": "deno test --allow-all tests/", "check": "deno check mod.ts" }, "lint": { "rules": { "tags": ["recommended"] } }, "fmt": { "useTabs": false, "lineWidth": 100, "indentWidth": 2, "semiColons": true }, "compilerOptions": { "lib": ["deno.window"], "strict": true }, "imports": { "@std/cli": "jsr:@std/cli@^1.0.0", "@std/fmt": "jsr:@std/fmt@^1.0.0", "@std/path": "jsr:@std/path@^1.0.0" } }
1.3 Update Import Statements
- [ ]
ts/snmp/manager.ts: Changeimport * as snmp from 'net-snmp'toimport * as snmp from "npm:[email protected]" - [ ]
ts/cli.ts: Changeimport { execSync } from 'child_process'toimport { execSync } from "node:child_process" - [ ]
ts/nupst.ts: Changeimport * as https from 'https'toimport * as https from "node:https" - [ ] Search for all
fsimports and update tonode:fs - [ ] Search for all
pathimports and update tonode:path - [ ] Update all relative imports to use
.tsextension instead of.js- Example:
'./nupst.js'→'./nupst.ts'
- Example:
1.4 Test npm: Specifier Compatibility
- [ ] Create test file:
tests/snmp_compatibility_test.ts - [ ] Test SNMP v1 connection with npm:net-snmp
- [ ] Test SNMP v2c connection with npm:net-snmp
- [ ] Test SNMP v3 connection with npm:net-snmp
- [ ] Verify native addon loading works in compiled binary
Phase 2: Code Structure Refactoring (3-4 hours)
2.1 Create Main Entry Point
- [ ] Create
mod.tsas main Deno entry point:#!/usr/bin/env -S deno run --allow-all /** * NUPST - UPS Shutdown Tool for Deno * * Required Permissions: * --allow-net: SNMP communication with UPS devices * --allow-read: Configuration file access (/etc/nupst/config.json) * --allow-write: Configuration file updates * --allow-run: System commands (systemctl, shutdown) * --allow-sys: System information (hostname, OS info) * --allow-env: Environment variables */ import { NupstCli } from './ts/cli.ts'; const cli = new NupstCli(); await cli.parseAndExecute(Deno.args);
2.2 Update All Import Extensions
Files to update (change .js → .ts in imports):
- [ ]
ts/index.ts - [ ]
ts/cli.ts(imports from ./nupst.js, ./logger.js) - [ ]
ts/nupst.ts(imports from ./snmp/manager.js, ./daemon.js, etc.) - [ ]
ts/daemon.ts(imports from ./snmp/manager.js, ./logger.js, ./helpers/) - [ ]
ts/systemd.ts(imports from ./daemon.js, ./logger.js) - [ ]
ts/cli/service-handler.ts - [ ]
ts/cli/group-handler.ts - [ ]
ts/cli/ups-handler.ts - [ ]
ts/snmp/index.ts - [ ]
ts/snmp/manager.ts(imports from ./types.js, ./oid-sets.js) - [ ]
ts/snmp/oid-sets.ts(imports from ./types.js) - [ ]
ts/helpers/index.ts - [ ]
ts/logger.ts
2.3 Update process.argv References
- [ ]
ts/cli.ts: Replaceprocess.argvwithDeno.args(adjust indexing: process.argv[2] → Deno.args[0]) - [ ] Update parseAndExecute method to work with Deno.args (0-indexed vs 2-indexed)
2.4 Update File System Operations
- [ ] Search for
fs.readFileSync()→ Consider usingDeno.readTextFile()or keep node:fs - [ ] Search for
fs.writeFileSync()→ Consider usingDeno.writeTextFile()or keep node:fs - [ ] Search for
fs.existsSync()→ Keep node:fs or use Deno.stat - [ ] Search for
fs.mkdirSync()→ Keep node:fs or use Deno.mkdir - [ ] Decision: Keep node:fs for consistency or migrate to Deno APIs?
2.5 Update Path Operations
- [ ] Verify all
path.join(),path.resolve(),path.dirname()work with node:path - [ ] Consider using
@std/pathfrom JSR for better Deno integration
2.6 Handle __dirname and __filename
- [ ] Find all
__dirnameusage - [ ] Replace with
import.meta.dirname(Deno) ordirname(fromFileUrl(import.meta.url)) - [ ] Find all
__filenameusage - [ ] Replace with
import.meta.filenameorfromFileUrl(import.meta.url)
Phase 3: CLI Command Simplification (3-4 hours)
3.1 Design New Command Structure
Current → New mapping:
OLD NEW
=== ===
nupst enable → nupst service enable
nupst disable → nupst service disable
nupst daemon-start → nupst service start-daemon
nupst logs → nupst service logs
nupst stop → nupst service stop
nupst start → nupst service start
nupst status → nupst service status
nupst add → nupst ups add
nupst edit [id] → nupst ups edit [id]
nupst delete <id> → nupst ups remove <id>
nupst list → nupst ups list
nupst setup → nupst ups edit (removed alias)
nupst test → nupst ups test
nupst group list → nupst group list
nupst group add → nupst group add
nupst group edit <id> → nupst group edit <id>
nupst group delete <id> → nupst group remove <id>
nupst config → nupst config show
nupst update → nupst update
nupst uninstall → nupst uninstall
nupst help → nupst help / nupst --help
(new) → nupst --version3.2 Update CLI Parser (ts/cli.ts)
- [ ] Refactor
parseAndExecute()to handle new command structure - [ ] Add
servicesubcommand handler - [ ] Add
upssubcommand handler - [ ] Keep
groupsubcommand handler (already exists, just update delete→remove) - [ ] Add
configsubcommand handler withshowdefault - [ ] Add
--versionflag handler - [ ] Update
helpcommand to show new structure - [ ] Add command aliases:
rm→remove,ls→list - [ ] Add
--jsonflag for machine-readable output (future enhancement)
3.3 Update Command Handlers
- [ ]
ts/cli/service-handler.ts: Update method names if needed - [ ]
ts/cli/ups-handler.ts: Renamedelete()→remove(), removesetupmethod - [ ]
ts/cli/group-handler.ts: Renamedelete()→remove()
3.4 Improve Help Messages
- [ ] Update
showHelp()in ts/cli.ts with new command structure - [ ] Update
showGroupHelp()in ts/cli.ts - [ ] Add
showServiceHelp()method - [ ] Add
showUpsHelp()method - [ ] Add
showConfigHelp()method - [ ] Include usage examples in help text
3.5 Add Version Command
- [ ] Read version from deno.json
- [ ] Create
--versionhandler in CLI - [ ] Display version with build info
Phase 4: Compilation & Distribution (2-3 hours)
4.1 Create Compilation Script
- [ ] Create directory:
scripts/ - [ ] Create
scripts/compile-all.sh:#!/bin/bash set -e VERSION=$(cat deno.json | jq -r '.version') BINARY_DIR="dist/binaries" echo "Compiling NUPST v${VERSION} for all platforms..." mkdir -p "$BINARY_DIR" # Linux x86_64 echo "→ Linux x86_64..." deno compile --allow-all --output "$BINARY_DIR/nupst-linux-x64" \ --target x86_64-unknown-linux-gnu mod.ts # Linux ARM64 echo "→ Linux ARM64..." deno compile --allow-all --output "$BINARY_DIR/nupst-linux-arm64" \ --target aarch64-unknown-linux-gnu mod.ts # macOS x86_64 echo "→ macOS x86_64..." deno compile --allow-all --output "$BINARY_DIR/nupst-macos-x64" \ --target x86_64-apple-darwin mod.ts # macOS ARM64 echo "→ macOS ARM64..." deno compile --allow-all --output "$BINARY_DIR/nupst-macos-arm64" \ --target aarch64-apple-darwin mod.ts # Windows x86_64 echo "→ Windows x86_64..." deno compile --allow-all --output "$BINARY_DIR/nupst-windows-x64.exe" \ --target x86_64-pc-windows-msvc mod.ts echo "" echo "✓ Compilation complete!" ls -lh "$BINARY_DIR/" - [ ] Make script executable:
chmod +x scripts/compile-all.sh
4.2 Test Local Compilation
- [ ] Run
deno task compileto compile for all platforms - [ ] Verify all 5 binaries are created
- [ ] Check binary sizes (should be reasonable, < 100MB each)
- [ ] Test local binary on current platform:
./dist/binaries/nupst-linux-x64 --version
4.3 Update Installation Scripts
- [ ] Update
install.sh:- Remove Node.js download logic (lines dealing with vendor/node-*)
- Add detection for binary download from GitHub releases
- Simplify to download appropriate binary based on OS/arch
- Place binary in
/opt/nupst/bin/nupst - Create symlink:
/usr/local/bin/nupst → /opt/nupst/bin/nupst - Update to v4.0.0 in script
- [ ] Simplify or remove
setup.sh(no longer needed without Node.js) - [ ] Update
bin/nupstlauncher:- Option A: Keep as simple wrapper
- Option B: Remove and symlink directly to binary
- [ ] Update
uninstall.sh:- Remove vendor directory cleanup
- Update paths to new binary location
4.4 Update Systemd Service
- [ ] Update systemd service file path in
ts/systemd.ts - [ ] Verify ExecStart points to correct binary location:
/opt/nupst/bin/nupst daemon-start - [ ] Remove Node.js environment variables if any
- [ ] Test service installation and startup
Phase 5: Testing & Validation (4-6 hours)
5.1 Create Deno Test Suite
- [ ] Create
tests/directory (or migrate from existingtest/) - [ ] Create
tests/snmp_test.ts: Test SNMP manager functionality - [ ] Create
tests/config_test.ts: Test configuration loading/saving - [ ] Create
tests/cli_test.ts: Test CLI parsing and command routing - [ ] Create
tests/daemon_test.ts: Test daemon logic - [ ] Remove dependency on @git.zone/tstest and @push.rocks/tapbundle
- [ ] Use Deno's built-in test runner (
Deno.test())
5.2 Unit Tests
- [ ] Test SNMP connection with mock responses
- [ ] Test configuration validation
- [ ] Test UPS status parsing for different models
- [ ] Test group logic (redundant/non-redundant modes)
- [ ] Test threshold checking
- [ ] Test version comparison logic
5.3 Integration Tests
- [ ] Test CLI command parsing for all commands
- [ ] Test config file creation and updates
- [ ] Test UPS add/edit/remove operations
- [ ] Test group add/edit/remove operations
- [ ] Mock systemd operations for testing
5.4 Binary Testing
- [ ] Test compiled binary on Linux x64
- [ ] Test compiled binary on Linux ARM64 (if available)
- [ ] Test compiled binary on macOS x64 (if available)
- [ ] Test compiled binary on macOS ARM64 (if available)
- [ ] Test compiled binary on Windows x64 (if available)
- [ ] Verify SNMP functionality works in compiled binary
- [ ] Verify config file operations work in compiled binary
- [ ] Test systemd integration with compiled binary
5.5 Performance Testing
- [ ] Measure binary size for each platform
- [ ] Measure startup time:
time ./nupst-linux-x64 --version - [ ] Measure memory footprint during daemon operation
- [ ] Compare with Node.js version performance
- [ ] Document performance metrics
5.6 Upgrade Path Testing
- [ ] Create test with v3.x config
- [ ] Verify v4.x can read existing config
- [ ] Test migration from old commands to new commands
- [ ] Verify systemd service upgrade path
Phase 6: Distribution Strategy (2-3 hours)
6.1 GitHub Actions Workflow
- [ ] Create
.github/workflows/release.yml:name: Release on: push: tags: - 'v*' jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: denoland/setup-deno@v1 with: deno-version: v1.x - name: Compile binaries run: deno task compile - name: Generate checksums run: | cd dist/binaries sha256sum * > SHA256SUMS - name: Create Release uses: softprops/action-gh-release@v1 with: files: dist/binaries/* generate_release_notes: true
6.2 Update package.json for npm
- [ ] Update version to 4.0.0
- [ ] Update description to mention Deno
- [ ] Add postinstall script to symlink appropriate binary:
{ "name": "@serve.zone/nupst", "version": "4.0.0", "description": "UPS Shutdown Tool - Deno-based single executable", "bin": { "nupst": "bin/nupst-npm-wrapper.js" }, "type": "module", "scripts": { "postinstall": "node bin/setup-npm-binary.js" }, "files": [ "dist/binaries/*", "bin/*" ] } - [ ] Create
bin/setup-npm-binary.jsto symlink correct binary - [ ] Create
bin/nupst-npm-wrapper.jsas entry point
6.3 Verify Distribution Methods
- [ ] Test GitHub release download and installation
- [ ] Test npm install from tarball
- [ ] Test direct install.sh script
- [ ] Verify all methods create working installation
Phase 7: Documentation Updates (2-3 hours)
7.1 Update README.md
- [ ] Remove Node.js requirements section
- [ ] Update features list (mention Deno, single executable)
- [ ] Update installation methods:
- Method 1: Quick install script (updated)
- Method 2: GitHub releases (new)
- Method 3: npm (updated with notes)
- [ ] Update usage section with new command structure
- [ ] Add command mapping table (v3 → v4)
- [ ] Update platform support matrix (note: no Windows ARM)
- [ ] Update "System Changes" section (no vendor directory)
- [ ] Update security section (remove Node.js mentions)
- [ ] Update uninstallation instructions
7.2 Create MIGRATION.md
- [ ] Create detailed migration guide from v3.x to v4.x
- [ ] List all breaking changes:
- CLI command structure reorganization
- No Node.js requirement
- Windows ARM not supported
- Installation path changes
- [ ] Provide command mapping table
- [ ] Explain config compatibility
- [ ] Document upgrade procedure
- [ ] Add rollback instructions
7.3 Update CHANGELOG.md
- [ ] Add v4.0.0 section with all breaking changes
- [ ] List new features (Deno, single executable)
- [ ] List improvements (startup time, binary size)
- [ ] List removed features (Windows ARM, setup command alias)
- [ ] Migration guide reference
7.4 Update Help Text
- [ ] Ensure all help commands show new structure
- [ ] Add examples for common operations
- [ ] Include migration notes in help output
Phase 8: Cleanup & Finalization (1 hour)
8.1 Remove Obsolete Files
- [ ] Delete
vendor/directory (Node.js binaries) - [ ] Delete
dist/directory (old compiled JS) - [ ] Delete
dist_ts/directory (old compiled TS) - [ ] Delete
node_modules/directory - [ ] Remove or update
tsconfig.json(decide if needed for npm compatibility) - [ ] Remove
setup.shif no longer needed - [ ] Remove old test files in
test/if migrated totests/ - [ ] Delete
pnpm-lock.yaml
8.2 Update Git Configuration
- [ ] Update
.gitignore:# Deno .deno/ deno.lock # Compiled binaries dist/binaries/ # Old Node.js artifacts (to be removed) node_modules/ vendor/ dist/ dist_ts/ pnpm-lock.yaml - [ ] Add
deno.lockto version control - [ ] Create
.denoignoreif needed
8.3 Final Validation
- [ ] Run
deno check mod.ts- verify no type errors - [ ] Run
deno lint- verify code quality - [ ] Run
deno fmt --check- verify formatting - [ ] Run
deno task test- verify all tests pass - [ ] Run
deno task compile- verify all binaries compile - [ ] Test each binary manually
8.4 Prepare for Release
- [ ] Create git tag:
v4.0.0 - [ ] Push to main branch
- [ ] Push tags to trigger release workflow
- [ ] Verify GitHub Actions workflow succeeds
- [ ] Verify binaries are attached to release
- [ ] Test installation from GitHub release
- [ ] Publish to npm:
npm publish - [ ] Test npm installation
Rollback Strategy
If critical issues are discovered:
- [ ] Keep
v3.1.2tag available for rollback - [ ] Create
v3-stablebranch for continued v3 maintenance - [ ] Update install.sh to offer v3/v4 choice
- [ ] Document known issues in GitHub Issues
- [ ] Provide downgrade instructions in docs
Success Criteria Checklist
- [ ] ✅ All 5 platform binaries compile successfully
- [ ] ✅ Binary sizes are reasonable (< 100MB per platform)
- [ ] ✅ Startup time < 2 seconds
- [ ] ✅ SNMP v1/v2c/v3 functionality verified on real UPS device
- [ ] ✅ All CLI commands work with new structure
- [ ] ✅ Config file compatibility maintained
- [ ] ✅ Systemd integration works on Linux
- [ ] ✅ Installation scripts work on fresh systems
- [ ] ✅ npm package still installable and functional
- [ ] ✅ All tests pass
- [ ] ✅ Documentation is complete and accurate
- [ ] ✅ GitHub release created with binaries
- [ ] ✅ Migration guide tested by following it step-by-step
Timeline
- Phase 0: 1 hour ✓ (in progress)
- Phase 1: 4-6 hours
- Phase 2: 3-4 hours
- Phase 3: 3-4 hours
- Phase 4: 2-3 hours
- Phase 5: 4-6 hours
- Phase 6: 2-3 hours
- Phase 7: 2-3 hours
- Phase 8: 1 hour
Total Estimate: 22-31 hours
Notes & Decisions
Key Decisions Made:
- ✅ Use npm:net-snmp (no pure Deno SNMP library available)
- ✅ Major version bump to 4.0.0 (breaking changes)
- ✅ CLI reorganization with subcommands
- ✅ Keep npm publishing alongside binary distribution
- ✅ 5 platform targets (Windows ARM not supported by Deno yet)
Open Questions:
- [ ] Should we keep tsconfig.json for npm package compatibility?
- [ ] Should we fully migrate to Deno APIs (Deno.readFile) or keep node:fs?
- [ ] Should we remove the
bin/nupstwrapper or keep it? - [ ] Should setup.sh be completely removed or kept for dependencies?
Risk Areas:
- ⚠️ SNMP native addon compatibility in compiled binaries (HIGH PRIORITY TO TEST)
- ⚠️ Systemd integration with new binary structure
- ⚠️ Config migration from v3 to v4
- ⚠️ npm package installation with embedded binaries
