Skip to content

drakonkat/java-js-node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Java JS Node

npm version License: ISC Node.js Version

An advanced Node.js module for running Java JAR files from local paths or URLs with advanced JRE auto-download features, intelligent caching, and automatic validation.

🚀 Features

  • Flexible JAR execution: Supports local paths and remote URLs
  • Auto-download JRE: Automatically downloads the Java Runtime Environment if not present
  • Cross-platform: Windows, macOS and Linux
  • Multiple Java versions: Supports Java 8, 11, 17, 21 and other versions
  • Intelligent caching: Reuses downloaded JREs for subsequent executions
  • JAR validation: Automatic verification of JAR file integrity
  • Debug logging: Detailed monitoring of operations
  • Advanced error handling: Specific and informative errors
  • Flexible configuration: Environment variables and custom options

📦 Installation

npm install java-js-node

System Requirements

  • Node.js: >= 14.0.0
  • Operating System: Windows, macOS, or Linux
  • Architecture: x64, ARM64, or ARM
  • Disk Space: ~100MB for downloaded JRE

🎯 Quick Start

const { runJar } = require('java-js-node');

// Run a local JAR
const result = await runJar('./test/helloworld-1.0.0-SNAPSHOT.jar');
console.log('Exit code:', result.exitCode);
console.log('Output:', result.stdout);

💡 Practical Examples

1. Basic Examples

Hello World - The first step

const { runJar } = require('java-js-node');

// Basic execution with security validation
async function helloWorld() {
    // ✅ JAR validation mandatory for security
    const isValid = await runJar.validateJar('./test/helloworld-1.0.0-SNAPSHOT.jar');
    if (!isValid) {
        throw new Error('JAR unsafe or corrupted');
    }

    const result = await runJar('./test/helloworld-1.0-SNAPSHOT.jar');
    console.log('Exit code:', result.exitCode);
    console.log('Output:', result.stdout);
}

JAR with simple arguments

const { runJar } = require('java-js-node');

async function runWithArgs() {
    // Run JAR with configuration parameters
    const result = await runJar('./my-app.jar', ['--config', 'dev.json', '--debug']);
    console.log('Application executed with code:', result.exitCode);
}

2. Single JAR Execution

Spring Boot web application

const { runJar } = require('java-js-node');

async function startSpringApp() {
    console.log('🚀 Starting Spring Boot application...');

    // ✅ Mandatory validation before execution
    const isValid = await runJar.validateJar('./target/spring-app.jar');
    if (!isValid) {
        throw new Error('Invalid Spring Boot JAR');
    }

    // Run with production configuration
    const result = await runJar('./target/spring-app.jar', [
        '--spring.profiles.active=prod',
        '--server.port=8080'
    ]);

    if (result.exitCode === 0) {
        console.log('✅ Spring Boot started successfully');
    } else {
        console.error('❌ Startup error:', result.stderr);
    }
}

Batch processing with validation

const { runJar } = require('java-js-node');

async function processBatch() {
    // ✅ Always validate before execution
    const isValid = await runJar.validateJar('./batch-processor.jar');
    if (!isValid) {
        throw new Error('Invalid processor JAR');
    }

    // Process files with specific parameters
    const result = await runJar('./batch-processor.jar', [
        '--input', './data/input.csv',
        '--output', './data/output.csv',
        '--batch-size', '1000'
    ]);

    console.log('Batch completed with exit code:', result.exitCode);
}

3. Multiple JAR Execution

Sequential Pattern - One after another

const { create } = require('java-js-node');

async function sequentialExecution() {
    const runner = create({ debug: true });

    const jars = [
        { path: './init-database.jar', args: ['--setup'] },
        { path: './load-data.jar', args: ['--import'] },
        { path: './process-data.jar', args: ['--transform'] },
        { path: './cleanup.jar', args: ['--finalize'] }
    ];

    for (const jar of jars) {
        console.log(`Executing: ${jar.path}`);

        // ✅ Validation for each JAR
        const isValid = await runner.validateJar(jar.path);
        if (!isValid) {
            throw new Error(`Invalid JAR ${jar.path}`);
        }

        const result = await runner.runJar(jar.path, jar.args);
        if (result.exitCode !== 0) {
            throw new Error(`Error in ${jar.path}: ${result.stderr}`);
        }

        console.log(`✅ ${jar.path} completed`);
    }

    console.log('🎉 Sequential pipeline completed!');
}

Parallel Pattern - Simultaneous execution

const { create } = require('java-js-node');

async function parallelExecution() {
    const runner = create({ debug: true });

    const services = [
        { name: 'auth-service', jar: './auth.jar', args: ['--port', '8081'] },
        { name: 'user-service', jar: './users.jar', args: ['--port', '8082'] },
        { name: 'notification-service', jar: './notifications.jar', args: ['--port', '8083'] }
    ];

    console.log('🚀 Starting services in parallel...');

    // Execute all services simultaneously
    const promises = services.map(async (service) => {
        console.log(`Starting ${service.name}...`);

        // ✅ Mandatory validation
        const isValid = await runner.validateJar(service.jar);
        if (!isValid) {
            throw new Error(`Invalid ${service.name} JAR`);
        }

        const result = await runner.runJar(service.jar, service.args);
        return { service: service.name, result };
    });

    try {
        const results = await Promise.all(promises);

        results.forEach(({ service, result }) => {
            if (result.exitCode === 0) {
                console.log(`✅ ${service} started successfully`);
            } else {
                console.error(`❌ Error in ${service}:`, result.stderr);
            }
        });
    } catch (error) {
        console.error('Error in parallel startup:', error.message);
    }
}

4. Enterprise Integration

CI/CD Pipeline with validation and testing

const { create, validateJar } = require('java-js-node');

async function cicdPipeline() {
    const runner = create({
        debug: true,
        jreMajor: 17,
        workdir: './build/runtime'
    });

    const jarPath = './target/application.jar';

    console.log('🔄 Starting CI/CD pipeline...\n');

    // 1. ✅ Validate built JAR
    console.log('1️⃣ JAR validation...');
    const isValid = await validateJar(jarPath);
    if (!isValid) {
        throw new Error('Invalid built JAR - build failed');
    }
    console.log('✅ JAR valid\n');

    // 2. Unit tests
    console.log('2️⃣ Running unit tests...');
    const testResult = await runner.runJar(jarPath, ['--test', '--unit']);
    if (testResult.exitCode !== 0) {
        throw new Error('Unit tests failed');
    }
    console.log('✅ Unit tests passed\n');

    // 3. Integration tests
    console.log('3️⃣ Running integration tests...');
    const integrationResult = await runner.runJar(jarPath, ['--test', '--integration']);
    if (integrationResult.exitCode !== 0) {
        throw new Error('Integration tests failed');
    }
    console.log('✅ Integration tests passed\n');

    // 4. Deploy to staging
    console.log('4️⃣ Deploy to staging environment...');
    await runner.runJar(jarPath, ['--deploy', '--env', 'staging']);
    console.log('✅ Staging deploy completed\n');

    // 5. End-to-end tests
    console.log('5️⃣ Running E2E tests...');
    const e2eResult = await runner.runJar(jarPath, ['--test', '--e2e']);
    if (e2eResult.exitCode !== 0) {
        throw new Error('E2E tests failed');
    }
    console.log('✅ E2E tests passed\n');

    console.log('🎉 CI/CD pipeline completed successfully!');
}

Microservices with advanced error handling

const { create, JavaRunnerError } = require('java-js-node');

class ServiceManager {
    constructor() {
        this.runner = create({
            debug: true,
            jreMajor: 17
        });
        this.services = new Map();
    }

    async startService(name, jarPath, args = []) {
        try {
            console.log(`🚀 Starting service ${name}...`);

            // ✅ Mandatory validation
            const isValid = await this.runner.validateJar(jarPath);
            if (!isValid) {
                throw new JavaRunnerError(`Invalid JAR ${name}`, 'INVALID_JAR');
            }

            const result = await this.runner.runJar(jarPath, args);
            this.services.set(name, { status: 'running', result });

            console.log(`✅ Service ${name} started`);
            return result;

        } catch (error) {
            this.services.set(name, { status: 'error', error: error.message });
            console.error(`❌ Error starting ${name}:`, error.message);
            throw error;
        }
    }

    async stopService(name) {
        if (this.services.has(name)) {
            this.services.delete(name);
            console.log(`🛑 Service ${name} stopped`);
        }
    }

    getStatus() {
        return Array.from(this.services.entries()).map(([name, service]) => ({
            name,
            status: service.status,
            exitCode: service.result?.exitCode
        }));
    }
}

async function manageMicroservices() {
    const manager = new ServiceManager();

    try {
        // Start core services
        await manager.startService('auth-service', './auth.jar', ['--port', '8081']);
        await manager.startService('user-service', './users.jar', ['--port', '8082']);
        await manager.startService('api-gateway', './gateway.jar', ['--port', '8080']);

        console.log('\n📊 Service status:');
        console.log(manager.getStatus());

    } catch (error) {
        console.error('\n❌ Error in microservice management:', error.message);

        // Cleanup services in case of error
        console.log('🧹 Service cleanup...');
        await manager.stopService('auth-service');
        await manager.stopService('user-service');
        await manager.stopService('api-gateway');
    }
}

These practical examples show how to use Node Java Runner in real scenarios, from simple JAR execution to complex enterprise pipeline management. Each example follows the project's security rules with mandatory JAR validation and appropriate error handling.

📖 Advanced Usage

Custom Configuration

const { create } = require('java-js-node');

// Create an instance with custom options
const runner = create({
    workdir: './custom-runtime',    // Custom working directory
    jreMajor: 17,                   // Specific Java version
    javaPath: '/custom/java/path',  // Custom Java path
    debug: true                     // Enable debug logging
});

Execution with Arguments

// Run JAR with arguments
const result = await runner.runJar('./my-app.jar', ['--port', '8080', '--env', 'production']);

JAR Validation

// Verify if a file is a valid JAR
const isValid = await runner.validateJar('./app.jar');
if (isValid) {
    console.log('✅ Valid JAR');
}

Java Version Check

// Check Java installation
const javaInfo = await runner.checkJavaVersion();
console.log(`Java ${javaInfo.version} found at: ${javaInfo.path}`);

🎯 Examples with Listeners for Real-Time Logging

Listeners allow you to capture JAR output in real-time during execution, useful for advanced logging, monitoring, and integration with external systems.

Basic Listener - Console Logging

const { create } = require('java-js-node');

async function esempioListenerBasico() {
   // Create the runner with custom configuration
   const runner = create({
       debug: true,
       jreMajor: 17
   });

   // Initialize with the correct pattern
   await runner.init({
       workdir: './runtime',
       minimumVersion: 17
   });

   console.log('🚀 Starting JAR with basic listener...\n');

   // Run JAR with listener for real-time logging
   const result = await runner.runJar('./test/helloworld-1.0.0-SNAPSHOT.jar', [], {
       onStdout: (data) => {
           console.log(`📤 STDOUT: ${data.trim()}`);
       },
       onStderr: (data) => {
           console.log(`⚠️ STDERR: ${data.trim()}`);
       }
   });

   console.log(`\n✅ Execution completed - Exit code: ${result.exitCode}`);
}

Advanced Listener - Logging with Timestamp and Categorization

const { create } = require('java-js-node');

async function esempioListenerAvanzato() {
   const runner = create({
       debug: true,
       jreMajor: 17
   });

   await runner.init({
       workdir: './runtime'
   });

   const logs = [];
   let startTime = Date.now();

   console.log('🔍 Starting JAR with advanced listener...\n');

   const result = await runner.runJar('./test/helloworld-1.0.0-SNAPSHOT.jar', [], {
       onStdout: (data) => {
           const timestamp = new Date().toISOString();
           const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
           logs.push({ type: 'INFO', timestamp, elapsed, data: data.trim() });
           console.log(`[${timestamp}] [${elapsed}s] 📤 ${data.trim()}`);
       },
       onStderr: (data) => {
           const timestamp = new Date().toISOString();
           const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
           logs.push({ type: 'ERROR', timestamp, elapsed, data: data.trim() });
           console.log(`[${timestamp}] [${elapsed}s] ❌ ${data.trim()}`);
       }
   });

   // Post-execution analysis
   const errors = logs.filter(log => log.type === 'ERROR');
   const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);

   console.log(`\n📊 Execution statistics:`);
   console.log(`   ⏱️ Total time: ${totalTime}s`);
   console.log(`   📝 Total logs: ${logs.length}`);
   console.log(`   ❌ Errors: ${errors.length}`);
   console.log(`   ✅ Exit code: ${result.exitCode}`);
}

Init Integration - Custom Logger

const { create } = require('java-js-node');
const fs = require('fs').promises;

class CustomLogger {
   constructor(logFile) {
       this.logFile = logFile;
       this.startTime = Date.now();
   }

   async log(level, message) {
       const timestamp = new Date().toISOString();
       const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(2);
       const logEntry = `[${timestamp}] [${elapsed}s] [${level}] ${message}\n`;

       console.log(logEntry.trim());

       // Save to file
       try {
           await fs.appendFile(this.logFile, logEntry);
       } catch (error) {
           console.error(`Error saving log: ${error.message}`);
       }
   }

   info(message) { return this.log('INFO', message); }
   error(message) { return this.log('ERROR', message); }
   warn(message) { return this.log('WARN', message); }
}

async function esempioIntegrazioneInit() {
   const runner = create({
       debug: true,
       jreMajor: 17
   });

   // Complete init() pattern with configuration
   await runner.init({
       workdir: './runtime',
       minimumVersion: 17,
       jreMajor: 17
   });

   const logger = new CustomLogger('./logs/app-runtime.log');

   console.log('🔧 Starting JAR with custom logger...\n');

   const result = await runner.runJar('./test/helloworld-1.0.0-SNAPSHOT.jar', [], {
       onStdout: async (data) => {
           await logger.info(`Application: ${data.trim()}`);
       },
       onStderr: async (data) => {
           await logger.error(`Application Error: ${data.trim()}`);
       }
   });

   await logger.info(`Execution completed with exit code: ${result.exitCode}`);

   console.log(`\n✅ Logs saved in: ./logs/app-runtime.log`);
   console.log(`📊 Final exit code: ${result.exitCode}`);
}

Practical Use Case - Performance Monitoring with Metrics

const { create } = require('java-js-node');

class PerformanceMonitor {
   constructor() {
       this.metrics = {
           startTime: null,
           endTime: null,
           memoryUsage: [],
           cpuUsage: [],
           logCount: 0,
           errorCount: 0
       };
   }

   start() {
       this.metrics.startTime = Date.now();
       console.log('📊 Performance monitoring started');
   }

   recordMemory() {
       const usage = process.memoryUsage();
       this.metrics.memoryUsage.push({
           timestamp: Date.now(),
           rss: Math.round(usage.rss / 1024 / 1024), // MB
           heapUsed: Math.round(usage.heapUsed / 1024 / 1024) // MB
       });
   }

   log(type, data) {
       this.metrics.logCount++;
       if (type === 'ERROR') {
           this.metrics.errorCount++;
       }

       const elapsed = this.metrics.startTime ?
           ((Date.now() - this.metrics.startTime) / 1000).toFixed(2) : '0.00';

       console.log(`[${elapsed}s] ${type === 'ERROR' ? '❌' : '📤'} ${data.trim()}`);
   }

   end() {
       this.metrics.endTime = Date.now();
       this.printReport();
   }

   printReport() {
       const totalTime = ((this.metrics.endTime - this.metrics.startTime) / 1000).toFixed(2);
       const avgMemory = this.metrics.memoryUsage.length > 0 ?
           Math.round(this.metrics.memoryUsage.reduce((sum, m) => sum + m.heapUsed, 0) / this.metrics.memoryUsage.length) : 0;

       console.log('\n📊 PERFORMANCE REPORT');
       console.log('='.repeat(50));
       console.log(`⏱️ Execution time: ${totalTime}s`);
       console.log(`📝 Total logs: ${this.metrics.logCount}`);
       console.log(`❌ Errors: ${this.metrics.errorCount}`);
       console.log(`🧠 Average memory: ${avgMemory} MB`);
       console.log(`📊 Memory samples: ${this.metrics.memoryUsage.length}`);
       console.log('='.repeat(50));
   }
}

async function esempioMonitoraggioPerformance() {
   const runner = create({
       debug: true,
       jreMajor: 17
   });

   // Optimized init() pattern with configuration
   await runner.init({
       workdir: './runtime',
       minimumVersion: 17
   });

   const monitor = new PerformanceMonitor();
   monitor.start();

   // Interval for memory sampling every 500ms
   const memoryInterval = setInterval(() => {
       monitor.recordMemory();
   }, 500);

   console.log('⚡ Starting JAR with performance monitoring...\n');

   const result = await runner.runJar('./test/helloworld-1.0.0-SNAPSHOT.jar', [], {
       onStdout: (data) => monitor.log('INFO', data),
       onStderr: (data) => monitor.log('ERROR', data)
   });

   clearInterval(memoryInterval);
   monitor.end();

   console.log(`\n🎯 Exit code: ${result.exitCode}`);
   console.log(`📈 Detailed metrics available in monitor.metrics`);
}

These examples show how to use listeners for:

  • Real-time logging during JAR execution
  • Advanced categorization and formatting of logs
  • Integration with custom logging systems
  • Performance monitoring during execution
  • init() pattern for optimal Java runtime configuration

Listeners are particularly useful for applications that require continuous monitoring, advanced debugging, or integration with enterprise logging systems.

🔧 API Reference

Static Methods (for quick usage)

runJar(jarPath, args = [])

Executes a JAR file with the specified arguments.

Parameters:

  • jarPath (string): Path to the JAR file (local or URL)
  • args (string[]): Array of arguments to pass to the JAR

Returns: Promise<Object>

{
    stdout: string,    // Standard output
    stderr: string,    // Standard errors
    exitCode: number   // Process exit code
}

Example:

const result = await runJar('./my-app.jar', ['--config', 'prod.json']);

validateJar(jarPath)

Validates if a file is a valid JAR.

Parameters:

  • jarPath (string): Path to the JAR file

Returns: Promise<boolean>

Example:

const isValid = await validateJar('./application.jar');

findJavaPath()

Finds the path to the Java executable in the system.

Returns: Promise<string|null>

Example:

const javaPath = await findJavaPath();
if (javaPath) {
    console.log('Java found at:', javaPath);
}

checkJavaVersion()

Checks the installed Java version.

Returns: Promise<Object>

{
    path: string,      // Path to Java executable
    version: string,   // Java version
    available: boolean // Availability
}

Example:

const info = await checkJavaVersion();
console.log(`Java ${info.version} at ${info.path}`);

NodeJavaRunner Class

constructor(options = {})

Creates a new NodeJavaRunner instance.

Options:

  • workdir (string): Working directory for downloads and cache (default: ./runtime)
  • jreMajor (number): Major Java version to use (default: 17)
  • javaPath (string): Custom path to Java executable
  • debug (boolean): Enable debug logging (default: false)

runJar(jarPath, args = [])

Executes a JAR file with the specified arguments.

validateJar(jarPath)

Validates a JAR file.

findJavaPath()

Finds the Java path in the system.

checkJavaVersion()

Checks the Java version.

⚙️ Configuration

Environment Variables

The module supports the following environment variables for configuration:

Variable Description Default
JAVA_JS_NODE_WORKDIR Custom working directory ./runtime
JAVA_JS_NODE_JRE_MAJOR Major Java version 17
JAVA_JS_NODE_DEBUG Enable debug logging false
JAVA_HOME Custom Java installation directory -

Environment Configuration Example

# Configuration via environment variables
export JAVA_JS_NODE_DEBUG=true
export JAVA_JS_NODE_WORKDIR=/tmp/java-js-node
export JAVA_JS_NODE_JRE_MAJOR=11
export JAVA_HOME=/opt/jdk-17

node my-app.js

🔍 Troubleshooting

Java Not Found

Problem: The system cannot find Java.

Solutions:

  1. Install Java manually:

    # Ubuntu/Debian
    sudo apt-get install openjdk-17-jre
    
    # CentOS/RHEL
    sudo yum install java-17-openjdk
    
    # macOS
    brew install openjdk@17
    
    # Windows (using Chocolatey)
    choco install openjdk17
  2. Set JAVA_HOME:

    export JAVA_HOME=/path/to/java
  3. Use custom configuration:

    const runner = create({
        javaPath: '/custom/java/path'
    });

Invalid JAR

Problem: The specified file is not a valid JAR.

Solutions:

  1. Verify that the file has .jar extension
  2. Check that the file is not corrupted
  3. Use validation before execution:
    const isValid = await validateJar('./app.jar');
    if (!isValid) {
        throw new Error('Invalid JAR');
    }

Insufficient Space

Problem: JRE download failed due to lack of space.

Solutions:

  1. Free up disk space
  2. Use a custom working directory with more space:
    const runner = create({
        workdir: '/path/with/more/space'
    });

Insufficient Permissions

Problem: Unable to download or extract JRE.

Solutions:

  1. Check the permissions of the working directory
  2. Use a writable directory:
    const runner = create({
        workdir: process.env.HOME + '/java-runner'
    });

🚀 Advanced Examples

Use Case: Web server with remote JAR

const { runJar } = require('java-js-node');

async function startRemoteServer() {
    try {
        // Download and run JAR from URL
        const result = await runJar('https://example.com/app.jar', ['--server', '--port', '3000']);

        if (result.exitCode === 0) {
            console.log('Server started successfully');
            console.log(result.stdout);
        } else {
            console.error('Server startup error:', result.stderr);
        }
    } catch (error) {
        console.error('Error:', error.message);
    }
}

Use Case: CI/CD Pipeline

const { create, validateJar } = require('java-js-node');

async function deployApplication() {
    const runner = create({
        debug: true,
        jreMajor: 17,
        workdir: './build/runtime'
    });

    // 1. Validate the built JAR
    const jarPath = './target/app-1.0.0.jar';
    const isValid = await validateJar(jarPath);

    if (!isValid) {
        throw new Error('Invalid built JAR');
    }

    // 2. Run integration tests
    console.log('Running integration tests...');
    const testResult = await runner.runJar(jarPath, ['--test', '--integration']);

    if (testResult.exitCode !== 0) {
        throw new Error('Integration tests failed');
    }

    // 3. Deploy to production
    console.log('Deploying to production...');
    await runner.runJar(jarPath, ['--deploy', '--env', 'prod']);

    console.log('Deploy completed successfully!');
}

Use Case: Advanced error handling

const { runJar, JavaRunnerError } = require('java-js-node');

async function safeJarExecution() {
    try {
        const result = await runJar('./app.jar');

        if (result.exitCode === 0) {
            console.log('Execution completed');
        } else {
            console.warn(`JAR terminated with code ${result.exitCode}`);
        }

    } catch (error) {
        if (error instanceof JavaRunnerError) {
            switch (error.code) {
                case 'JAVA_NOT_FOUND':
                    console.error('Java not installed. Install Java or check JAVA_HOME');
                    break;
                case 'JAR_NOT_FOUND':
                    console.error('JAR file not found:', error.message);
                    break;
                case 'INVALID_JAR_FORMAT':
                    console.error('The specified file is not a valid JAR');
                    break;
                default:
                    console.error('Unknown error:', error.message);
            }
        } else {
            console.error('Unexpected error:', error.message);
        }
    }
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

How to Contribute

  1. Fork the project
  2. Create a branch for your feature (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Development Guidelines

  • Maintain compatibility with Node.js >= 14.0.0
  • Add tests for new features
  • Update documentation for API changes
  • Follow existing code conventions
  • Ensure all tests pass

📝 License

This project is distributed under the ISC license.

ISC License

Copyright (c) TND Team

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

📞 Support

If you encounter problems or have questions:

  1. Check the Troubleshooting section
  2. Review the examples in test.js
  3. Open an issue on GitHub with problem details

Made with ❤️ by TND Team

About

A package to run jar file, or java basically in a node enviroment

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published