
Security News
/Research
Popular node-ipc npm Package Infected with Credential Stealer
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.
@devgrid/netron
Advanced tools
A powerful TypeScript library for building distributed systems with event bus, streaming capabilities, and remote object invocation. Features WebSocket-based bidirectional communication between Node.js and browser environments, service discovery, and type
A powerful TypeScript library for building distributed systems with WebSocket-based communication, remote procedure calls (RPC), event bus capabilities, and service discovery. Designed for real-time bidirectional communication between Node.js services and browser clients.
npm install @devgrid/netron
# or
yarn add @devgrid/netron
# or
pnpm add @devgrid/netron
import { Netron, Service, Public } from '@devgrid/netron';
// Define a service with decorators
@Service('calculator@1.0.0')
class CalculatorService {
@Public()
add(a: number, b: number): number {
return a + b;
}
@Public()
async multiply(a: number, b: number): Promise<number> {
return a * b;
}
@Public({ readonly: true })
pi = 3.14159;
}
// Create server and expose service
const server = await Netron.create({
listenHost: 'localhost',
listenPort: 8080
});
await server.peer.exposeService(new CalculatorService());
console.log('Server running on ws://localhost:8080');
import { Netron } from '@devgrid/netron';
// Connect to server
const client = await Netron.create();
const peer = await client.connect('ws://localhost:8080');
// Query and use remote service
interface ICalculator {
add(a: number, b: number): Promise<number>;
multiply(a: number, b: number): Promise<number>;
pi: Promise<number>;
}
const calc = await peer.queryInterface<ICalculator>('calculator@1.0.0');
// Call remote methods
const sum = await calc.add(5, 3); // 8
const product = await calc.multiply(4, 2); // 8
const piValue = await calc.pi; // 3.14159
Enable automatic service discovery across your distributed system:
const netron = await Netron.create({
listenPort: 8080,
discoveryEnabled: true,
discoveryRedisUrl: 'redis://localhost:6379',
discoveryHeartbeatInterval: 5000,
discoveryCleanupInterval: 10000
});
// Services are automatically registered and discovered
// Query available nodes
const nodes = await netron.discovery.getActiveNodes();
// Find specific service
const serviceNode = await netron.discovery.findService('calculator@1.0.0');
if (serviceNode) {
const peer = await netron.connect(serviceNode.address);
const calc = await peer.queryInterface('calculator@1.0.0');
}
Netron provides multiple event emission patterns:
// Subscribe to events
peer.subscribe('user:login', async (data) => {
console.log('User logged in:', data.userId);
});
// Emit events with different patterns
// Parallel - all handlers execute simultaneously
await netron.emitParallel('user:login', { userId: 123 });
// Serial - handlers execute one after another
await netron.emitSerial('process:step', { step: 1 });
// Reduce - accumulate results left-to-right
const result = await netron.emitReduce('calculate:sum', [1, 2, 3, 4]);
// ReduceRight - accumulate results right-to-left
const reversed = await netron.emitReduceRight('process:reverse', 'hello');
Handle large file transfers or continuous data streams:
// Server-side streaming service
@Service('fileService@1.0.0')
class FileService {
@Public()
async downloadFile(filename: string): Promise<ReadableStream> {
const stream = fs.createReadStream(filename);
return stream;
}
@Public()
async uploadFile(filename: string, stream: WritableStream): Promise<void> {
const writeStream = fs.createWriteStream(filename);
await pipeline(stream, writeStream);
}
}
// Client-side usage
const fileService = await peer.queryInterface('fileService@1.0.0');
// Download
const readStream = await fileService.downloadFile('large-video.mp4');
for await (const chunk of readStream) {
// Process chunks
}
// Upload
const uploadStream = await fileService.uploadFile('upload.zip');
await pipeline(fs.createReadStream('local.zip'), uploadStream);
Define and execute tasks across peers:
// Register a task
netron.addTask(async function healthCheck(peer) {
return {
status: 'healthy',
uptime: process.uptime(),
memory: process.memoryUsage(),
timestamp: Date.now()
};
});
// Execute task on remote peer
const health = await remotePeer.runTask('healthCheck');
console.log('Remote peer health:', health);
// Task with arguments
netron.addTask(async function processData(peer, data: any, options: any) {
// Process data with options
return processedResult;
});
const result = await remotePeer.runTask('processData', rawData, { mode: 'fast' });
Monitor service lifecycle events:
// Enable service events
const netron = await Netron.create({
allowServiceEvents: true
});
// Listen for service events
netron.on('service:exposed', ({ service, peer }) => {
console.log(`Service ${service} exposed by ${peer.id}`);
});
netron.on('service:concealed', ({ service, peer }) => {
console.log(`Service ${service} concealed by ${peer.id}`);
});
netron.on('peer:connected', (peer) => {
console.log(`Peer connected: ${peer.id}`);
});
netron.on('peer:disconnected', (peer) => {
console.log(`Peer disconnected: ${peer.id}`);
});
@Service('advanced@2.0.0')
class AdvancedService {
// Readonly properties
@Public({ readonly: true })
version = '2.0.0';
@Public({ readonly: true })
startTime = Date.now();
// Async methods with complex types
@Public()
async processUser(user: User): Promise<ProcessedUser> {
// Complex processing
return processedUser;
}
// Methods with multiple parameters
@Public()
async batchProcess(
items: Item[],
options: ProcessOptions = {}
): Promise<BatchResult> {
// Batch processing logic
}
// Private methods are not exposed
private validateUser(user: User): boolean {
// Internal validation
}
}
interface NetronOptions {
// Identification
id?: string; // Unique instance ID
// Server options
listenHost?: string; // Host to listen on
listenPort?: number; // Port to listen on
// Timeouts (in milliseconds)
taskTimeout?: number; // Task execution timeout (default: 5000)
connectTimeout?: number; // Connection timeout (default: 5000)
requestTimeout?: number; // Request timeout (default: 5000)
streamTimeout?: number; // Stream timeout (default: 5000)
// Task handling
taskOverwriteStrategy?: 'replace' | 'skip' | 'throw';
// Features
allowServiceEvents?: boolean; // Enable service lifecycle events
// Reconnection
maxReconnectAttempts?: number; // Max reconnection attempts
reconnectDelay?: number; // Initial reconnect delay
// Service Discovery (Redis)
discoveryEnabled?: boolean; // Enable service discovery
discoveryRedisUrl?: string; // Redis connection URL
discoveryHeartbeatInterval?: number; // Heartbeat interval (ms)
discoveryCleanupInterval?: number; // Cleanup interval (ms)
// Logging
logger?: Logger; // Custom logger instance
}
Always version your services to ensure compatibility:
@Service('api@1.0.0') // Good - includes version
@Service('api') // Bad - no version
Implement proper error handling in services:
@Service('userService@1.0.0')
class UserService {
@Public()
async getUser(id: string): Promise<User> {
try {
const user = await db.findUser(id);
if (!user) {
throw new Error('User not found');
}
return user;
} catch (error) {
// Log error
logger.error('Failed to get user:', error);
throw error; // Re-throw for client handling
}
}
}
Always clean up resources properly:
const netron = await Netron.create({ listenPort: 8080 });
// Graceful shutdown
process.on('SIGINT', async () => {
await netron.stop();
process.exit(0);
});
Define interfaces for your services:
// Shared types
interface IUserService {
getUser(id: string): Promise<User>;
createUser(data: CreateUserDto): Promise<User>;
updateUser(id: string, data: UpdateUserDto): Promise<User>;
}
// Client usage with full type safety
const userService = await peer.queryInterface<IUserService>('userService@1.0.0');
const user = await userService.getUser('123'); // Fully typed!
// Enable debug logging
const netron = await Netron.create({
logger: {
debug: console.log,
info: console.log,
warn: console.warn,
error: console.error
}
});
// Handle connection errors
try {
const peer = await netron.connect('ws://localhost:8080');
} catch (error) {
console.error('Connection failed:', error);
}
// List available services
const services = peer.getServiceNames();
console.log('Available services:', services);
// Check service metadata
const metadata = await peer.getServiceMetadata('calculator@1.0.0');
console.log('Service metadata:', metadata);
Contributions are welcome! Please feel free to submit a Pull Request.
MIT © DevGrid
FAQs
A powerful TypeScript library for building distributed systems with event bus, streaming capabilities, and remote object invocation. Features WebSocket-based bidirectional communication between Node.js and browser environments, service discovery, and type
The npm package @devgrid/netron receives a total of 124 weekly downloads. As such, @devgrid/netron popularity was classified as not popular.
We found that @devgrid/netron 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
/Research
Socket detected malicious node-ipc versions with obfuscated stealer/backdoor behavior in a developing npm supply chain attack.

Security News
TeamPCP and BreachForums are promoting a Shai-Hulud supply chain attack contest with a $1,000 prize for the biggest package compromise.

Security News
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.