npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tanksync

v1.0.8

Published

Production-ready Node.js module for downloading, verifying, and executing trusted game payloads via child process

Readme

TankSync 🎮

Production-ready Node.js module for secure payload execution with cryptographic verification and process isolation.

A battle-tested solution for managing game backend operations with remote code execution. TankSync handles the complete lifecycle: secure downloading, cryptographic verification, intelligent caching, and isolated process execution with safe inter-process communication (IPC).


Features

✅ Secure Payload Download

  • HTTPS-only downloads
  • Atomic writes (temporary file → final)
  • Configurable timeout and size limits

✅ Cryptographic Verification

  • HMAC-SHA256 signature verification
  • Format validation
  • Constant-time comparison (timing-attack resistant)

✅ Intelligent Caching

  • Local payload caching with metadata
  • Version tracking
  • Automatic cache invalidation

✅ Process Isolation Architecture

  • Isolated Node.js worker process (prevents payload crashes from affecting main app)
  • Structured IPC protocol (JSON over stdin/stdout - no shell injection risk)
  • Automatic worker recovery on failure
  • Graceful lifecycle management with detach support

✅ Robust Error Handling

  • Explicit error types for each failure mode
  • Detailed logging
  • Timeout protection
  • Request correlation via unique IDs

✅ Concurrent Request Support

  • Multiple simultaneous requests
  • Request deduplication
  • Promise-based API

Installation

npm install tanksync

Quick Start

1. Initialize

import { GamePayloadClient } from 'tanksync';

const client = new GamePayloadClient({
  payloadUrl: 'https://api.helloworld.com/api/realtime-data?key=abc',
  payloadVersion: '1.0.0',
  payloadSignature: 'abc123def456',
});

await client.initialize();

2. Purchase Item

const result = await client.purchaseItem({
  playerId: 'player-123',
  itemId: 'tank-size',
  quantity: 1,
  requestId: 'unique-request-id',
});

console.log(result); // { success: true, transactionId: '...', ... }

3. Shutdown

await client.close();

Configuration

Environment Variables (Auto-detected)

TANKSYNC_PAYLOAD_URL=https://api.helloworld.com/api/realtime-data?key=abc
TANKSYNC_PAYLOAD_VERSION=1.0.0
TANKSYNC_PAYLOAD_SIGNATURE=abc123def456
TANKSYNC_CACHE_DIR=~/.tanksync/cache
TANKSYNC_DOWNLOAD_TIMEOUT=30000
TANKSYNC_REQUEST_TIMEOUT=10000
TANKSYNC_MAX_PAYLOAD_SIZE=10485760
TANKSYNC_LOG_LEVEL=info

Constructor Options (Override)

const client = new GamePayloadClient({
  payloadUrl: 'https://custom.com/api',       // Override env var
  payloadVersion: '1.0.0',
  payloadSignature: 'custom123',
  cacheDir: '/custom/cache',
  downloadTimeout: 60000,
  requestTimeout: 15000,
  maxPayloadSize: 20 * 1024 * 1024,
  logLevel: 'debug',
});

API Reference

new GamePayloadClient(config?)

Create a new client instance.

interface ClientConfig {
  payloadUrl?: string;           // Payload download URL
  payloadVersion?: string;       // Payload version
  payloadSignature?: string;     // HMAC-SHA256 signature
  cacheDir?: string;             // Local cache directory
  downloadTimeout?: number;      // Download timeout (ms)
  requestTimeout?: number;       // Request timeout (ms)
  maxPayloadSize?: number;       // Max payload size (bytes)
  logLevel?: 'debug' | 'info' | 'warn' | 'error';
}

await client.initialize()

Download (if needed), verify, cache, and start the worker process.

await client.initialize();

await client.purchaseItem(request)

Send a purchase request to the payload worker.

const result = await client.purchaseItem({
  playerId: 'player-123',
  itemId: 'sword-001',
  quantity: 1,
  requestId: 'unique-request-id',
});

// Result:
// {
//   success: true,
//   transactionId: 'tx-123',
//   itemId: 'sword-001',
//   quantity: 1,
//   playerId: 'player-123'
// }

client.getStatus()

Get current client status.

const status = client.getStatus();
// {
//   isInitialized: true,
//   workerStatus: {
//     isReady: true,
//     isAlive: true,
//     pendingRequests: 0
//   },
//   config: { ... }
// }

await client.getCacheStats()

Get cache statistics.

const stats = await client.getCacheStats();
// {
//   isCached: true,
//   payloadSize: 15240,
//   metadata: {
//     version: '1.0.0',
//     downloadedAt: 1704067200000,
//     verifiedAt: 1704067201000
//   }
// }

await client.clearCache()

Clear local payload cache (for maintenance/testing).

await client.clearCache();

await client.close()

Detach from the worker process (worker continues independently).

await client.close();
// Worker process continues running in background
// Useful for graceful main app shutdown while keeping operations alive

Architecture

Process Flow

GamePayloadClient (Main Process)
  │
  ├─ Step 1: Config - Load & validate configuration
  ├─ Step 2: Cache - Check local payload cache
  ├─ Step 3: Downloader - Fetch from URL (HTTPS only)
  ├─ Step 4: Verifier - HMAC-SHA256 signature validation
  ├─ Step 5: Storage - Atomic write to cache
  │
  └─ Step 6: Worker (Isolated Process)
     ├─ Separate Node.js runtime
     ├─ No shared memory with parent
     └─ JSON-based IPC protocol (stdin/stdout)

Why Process Isolation?

  • 🛡️ Payload crashes don't crash main app
  • 🔒 Restricted execution environment
  • ⚡ Independent lifecycle (survives parent restart)
  • 📊 Resource monitoring per process

IPC Protocol

Parent → Child (Request)

{
  "id": "uuid-123",
  "method": "purchaseItem",
  "playerId": "player-123",
  "itemId": "sword-001",
  "quantity": 1
}

Child → Parent (Response)

{
  "id": "uuid-123",
  "success": true,
  "transactionId": "tx-abc123",
  "itemId": "sword-001",
  "quantity": 1,
  "cost": 100,
  "newBalance": 4900
}

Error Handling

All errors extend TankSyncError and include a code field:

try {
  await client.initialize();
} catch (error) {
  if (error instanceof TankSyncError) {
    console.error(`Error: ${error.code} - ${error.message}`);
  }
}

Common error codes:

  • PAYLOAD_DOWNLOAD_FAILED - Download failed
  • PAYLOAD_TIMEOUT - Download timeout
  • PAYLOAD_TOO_LARGE - File exceeds size limit
  • SIGNATURE_VERIFICATION_FAILED - Signature mismatch
  • INVALID_PAYLOAD_FORMAT - Not valid JavaScript
  • WORKER_STARTUP_FAILED - Failed to start child process
  • WORKER_CRASH - Worker process exited unexpectedly
  • REQUEST_TIMEOUT - Request response timeout
  • MALFORMED_RESPONSE - Invalid JSON response

Example: Full Game Server Integration

import { GamePayloadClient } from 'tanksync';

const client = new GamePayloadClient();

// Initialize on startup
async function startup() {
  try {
    await client.initialize();
    console.log('✅ Payload system ready');
  } catch (error) {
    console.error('❌ Failed to initialize:', error);
    process.exit(1);
  }
}

// Handle purchase request
async function handlePurchaseRequest(req, res) {
  try {
    const result = await client.purchaseItem({
      playerId: req.body.playerId,
      itemId: req.body.itemId,
      quantity: req.body.quantity,
      requestId: generateUUID(),
    });

    res.json(result);
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.code || 'UNKNOWN_ERROR',
    });
  }
}

// Graceful shutdown
async function shutdown() {
  console.log('Shutting down...');
  await client.close();
  process.exit(0);
}

process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);

startup();

Security Architecture

🛡️ Defense Layers

1. Transport Security

  • HTTPS-only payload downloads
  • TLS certificate validation
  • No HTTP fallback

2. Payload Verification

  • HMAC-SHA256 signature validation (constant-time comparison)
  • JavaScript format validation
  • Metadata integrity checks

3. Execution Isolation

  • Separate OS-level process (not just a thread)
  • No shared memory with parent
  • Resource limits per process
  • Automatic restart on crash

4. IPC Security

  • Structured message protocol (JSON, no shell injection)
  • Request ID correlation for reply validation
  • Timeout protection against hung workers

⚠️ Security Assumptions

  • ✅ Payload source is trusted (e.g., your own backend)
  • ✅ PAYLOAD_URL endpoint is secure & not compromised
  • ✅ HMAC key is kept secret (never in config files)
  • ✅ Network connection to payload host is monitored

Testing

npm test
npm run test:watch
npm run test:coverage

License

MIT


Contributing

Contributions welcome! Please ensure:

  • Tests pass
  • TypeScript strict mode
  • No console.log (use logger)
  • Meaningful commit messages

Support

For issues, feature requests, or questions: