New:Socket for Asana Is Now Available.Learn more
Get Started

node-ipc

Package Overview
Dependencies
Maintainers
1
Versions
83
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-ipc - npm Package Compare versions

Comparing version
12.0.0
to
14.0.0
+13
entities/MessageParser.js
import Message from 'js-message';
import Parser from './EventParser.js';
class MessageParser extends Parser{
decode(frame){
return new Message(frame);
}
}
export {
MessageParser as default,
MessageParser
};
import fs from 'node:fs';
function createClientTLSOptions(config,connectionOptions,assured=false){
const options=loadTLSOptions(config);
Object.assign(options,connectionOptions);
if(options.rejectUnauthorized === undefined){
options.rejectUnauthorized=true;
}
if(assured && (
options.rejectUnauthorized !== true
|| !options.ca
|| !options.key
|| !options.cert
)){
throw tlsConfigurationError(
'Assured network clients require a key, certificate, trusted CA, and rejectUnauthorized=true.',
'ERR_IPC_ASSURED_TLS'
);
}
return options;
}
function createServerTLSOptions(config,assured=false){
const options=loadTLSOptions(config);
if(!options.key || !options.cert){
throw tlsConfigurationError(
'TLS servers require an explicit key and certificate. Supply tls.key/tls.cert values or tls.private/tls.public file paths.'
);
}
if(options.ca && options.requestCert === undefined){
options.requestCert=true;
}
if(options.requestCert && options.rejectUnauthorized === undefined){
options.rejectUnauthorized=true;
}
if(assured && (
options.requestCert !== true
|| options.rejectUnauthorized !== true
|| !options.ca
)){
throw tlsConfigurationError(
'Assured network servers require a trusted client CA, requestCert=true, and rejectUnauthorized=true.',
'ERR_IPC_ASSURED_TLS'
);
}
return options;
}
function loadTLSOptions(config){
if(!config || typeof config !== 'object' || Array.isArray(config)){
throw tlsConfigurationError('ipc.config.tls must be an options object');
}
const options={...config};
if(options.private){
options.key=fs.readFileSync(options.private);
}
if(options.public){
options.cert=fs.readFileSync(options.public);
}
if(typeof options.dhparam === 'string' && !options.dhparam.includes('BEGIN DH PARAMETERS')){
options.dhparam=fs.readFileSync(options.dhparam);
}
if(options.trustedConnections){
const paths=Array.isArray(options.trustedConnections)
? options.trustedConnections
: [options.trustedConnections];
const trusted=paths.map((trustedPath) => fs.readFileSync(trustedPath));
const existing=options.ca === undefined
? []
: (Array.isArray(options.ca) ? options.ca : [options.ca]);
options.ca=[...existing,...trusted];
}
delete options.private;
delete options.public;
delete options.trustedConnections;
return options;
}
function tlsConfigurationError(message,code='ERR_IPC_TLS_CONFIGURATION'){
const error=new Error(message);
error.code=code;
return error;
}
export {
createClientTLSOptions,
createServerTLSOptions
};
# Migrating from 12.0.0 to 14.0.0
Version `13.0.0` was an internal modernization candidate and was never
published. Upgrade directly from `12.0.0` to `14.0.0`.
Node-ipc 14 is native ESM and requires Node.js 22.13 or newer. CommonJS on
supported Node releases can continue to use:
```js
const ipc = require('node-ipc').default;
```
The generated `node-ipc.cjs` bundle and its esbuild step are gone. Both
`import` and `require()` now load the same source.
The `node-ipc` JavaScript package is **Node.js-only**. It directly uses Node's
raw TCP, TLS, UDP, Unix-domain socket, Windows named-pipe, filesystem, OS,
process, and `Buffer` APIs. It is not supported in browsers, with or without a
bundler. “Native ESM” describes the one implementation loaded by Node without a
transpiler; it is not a native-browser entry.
## Paired Rust implementation
Version 14 introduces the dependency-free Rust crate under the same
`node-ipc` name and major version:
```toml
[dependencies]
node-ipc = "=14.0.0"
```
The Rust crate implements the same event envelope, delimiter framing, runtime
profiles, TCP, UDP, Unix sockets, and Windows named pipes. It has no runtime or
build dependencies. TLS remains application supplied so the crate does not
choose a cryptography stack or weaken certificate verification.
Node and Rust normal framed messages interoperate. Review the documented
language boundaries for malformed JSON, number precision, duplicate object
members, UTF-16 surrogate escapes, custom delimiters, and incomplete frames
before treating arbitrary language-specific values as portable.
## Aligned C# implementation
Version 14 also introduces the zero-NuGet-dependency .NET 8 package under the
same `node-ipc` name and major version:
```console
dotnet add package node-ipc --version 14.0.0
```
Unlike the lower-level blocking Rust crate, the C# port mirrors the JavaScript
facade: isolated `IPCModule` instances, lowercase config and service methods,
client registries, synchronous event subscriptions, reconnects, sync queues,
targeted replies, broadcasts, TCP/TLS/UDP, and cross-platform local service.
Valid Fast messages use the same compact `{type,data}` UTF-8 envelope and form-
feed delimiter and pass the repository's two-direction Node/C# gate.
C# endpoints capture parser, TLS trust/identity, logging, identification, sync,
and local-permission choices when constructed. Configure them before calling
`connect*()` or `serve*()`. Fast malformed input without a string event type
fails closed before C# event dispatch; normal framed messages are unaffected.
For Unix Assured clients, the built-in connector does not authenticate socket
ownership: verify the root and endpoint ownership in the application before
connecting.
The repository's shared behavioral gate runs one versioned Fast TCP transcript
through all nine JavaScript, Rust, and C# client/server pairings. It covers
falsey scalar values, Unicode and control characters, arrays, nested objects,
pipelined ordering, an exact canonical Fast frame, a separate finish barrier,
and a clean half-close/end-of-stream boundary in both directions. Run it with
`npm run test:behavioral`; language-specific malformed-input and security
boundaries remain in the native suites. The command also runs 12 raw negative
checks so every client and server language rejects complete and incomplete
frames after the finish boundary.
## Event subscriptions
Node-ipc 14 uses `event-pubsub` 6.1.1. Dispatch remains synchronous and live:
wildcard listeners run before typed listeners, and listeners appended during a
dispatch can run in that same dispatch. A `once` registration is removed before
its handler is invoked, so nested emission cannot invoke it twice. `list`
returns isolated handler-array snapshots on a null-prototype object; the real
all-events entry is exposed under `Symbol.for('event-pubsub-all')`, while the
public registration spelling remains the literal `'*'`.
Invalid public arguments still throw `TypeError`, but applications must not
depend on exact error text. Event-pubsub's sole runtime dependency remains
exact `strong-type` 2.0.0 and loads through the bare `strong-type` package name,
preserving that dependency's own Node, bundler, and native-browser import-map
resolution boundary. That browser contract belongs to `event-pubsub`; it does
not make the Node.js-only `node-ipc` runtime browser-compatible. The old runtime
`copyfiles` dependency is gone.
## Select a parser
`ipc.config.parser` is selected once when a client or server is created:
- `raw` — caller-owned bytes, with no node-ipc framing or parsing.
- `fast` — the default JSON event frame and malformed-JSON containment.
- `guarded` — Fast plus size, name, reserved-event, timeout, and pending-write limits.
- `assured` — Guarded plus an explicit `allowedEvents` list and mutually authenticated TLS on network transports.
- a parser class or object — implements `encode(type, data)` and
`read(remainder, chunk, receive)`.
`rawBuffer=true` remains an alias for Raw.
Fast now preserves payloads directly. Empty strings, `null`, and objects with
an `_maxListeners` field are no longer rewritten to `{}`.
Built-in framed parsers use UTF-8 in both directions. `ipc.config.encoding`
now applies to non-Buffer Raw writes. A custom parser that owns another wire
encoding should return Buffers.
Servers no longer inspect every payload for `data.id` by default. Set
`ipc.config.identifyPeer=true` only when legacy payload-based socket IDs are
required. The option is selected once when the server is created.
The official js-message adapter is available separately:
```js
import {MessageParser} from 'node-ipc/parsers/message';
ipc.config.parser = MessageParser;
```
This compatibility parser follows js-message error-envelope behavior. Use
Guarded or Assured for untrusted peers.
## TLS and local sockets
TLS servers no longer fall back to repository fixtures. Configure
`tls.key`/`tls.cert` values or `tls.private`/`tls.public` file paths.
Clients publish `connect` only after the TLS handshake succeeds.
On Unix, the default local-socket directory is user-specific. Secure root
ownership and mode checks happen once when a local server starts. Assured local
server endpoints must be direct children of that root; clients must verify the
endpoint they connect to.
Assured local service is limited to Unix sockets because node-ipc cannot prove
a Windows named-pipe ACL. Use Assured mutual TLS or an application-owned pipe
and policy on Windows.
The example certificates remain public, expired development fixtures and are
excluded from the npm package.
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 14.x | :white_check_mark: |
| 12.x | :white_check_mark: |
| 10.1.x | :white_check_mark: |
| Other versions | :x: |
Version 14.x aligns the native-ESM Node.js implementation (Node.js 22.13+), the
dependency-free Rust implementation (Rust 1.85+), and the zero-NuGet-dependency
C# implementation (.NET 8+). Version 13 was never published.
The `node-ipc` JavaScript package is **Node.js-only**. It does not run in web
browsers, whether bundled or unbundled, because browsers and browser-targeted
bundles cannot supply its raw TCP, TLS, UDP, Unix-domain socket, Windows
named-pipe, filesystem, OS, process, or `Buffer` contracts. The documentation
website's browser code is separate from the npm runtime.
## 14.x Node.js security profiles
Security and performance are selected once when a client or server is created. Changing `ipc.config.parser` or a related limit after `connect*()` or `serve*()` does not reconfigure an existing endpoint.
| Profile | Built-in protocol controls | Appropriate use |
|---------|----------------------------|-----------------|
| Raw | None. Buffers pass through unchanged. | Fully trusted peers with a caller-owned protocol and validation. |
| Fast | Delimiter framing and JSON event envelopes. Malformed JSON closes a stream connection or resets UDP peer frame state. | Trusted local peers. It does not enforce Guarded limits or event-name rules. |
| Guarded | Frame and stream pending-write limits, object-envelope checks, event-name length, reserved and prototype-name rejection, and incomplete-frame timeout. | Mixed-trust local services or authenticated network services. |
| Assured | Guarded plus a required event allow-list; network clients require a key, certificate, trusted CA, and verification; servers require verified client certificates; each Unix local server endpoint must be a direct child of the secure socket root. Clients must verify local endpoint ownership. Built-in Assured local service rejects Windows because node-ipc cannot prove a named-pipe ACL. | A building block for hostile networks when combined with authorization, payload validation, rate limits, key operations, and deployment controls. |
These rows describe the Node.js runtime. They are not government, military, industry, or compliance certifications. No parser authenticates a user, authorizes a command, validates application payload schemas, prevents replay, manages certificates, or establishes a complete security program.
`ipc.config.identifyPeer=true` restores the legacy server lookup of `data.id`, selected once at server construction. That payload field is untrusted application data and must never be treated as authenticated identity.
The `node-ipc/parsers/message` compatibility parser is an explicit ecosystem option. It maps malformed envelopes to an `error` message and is not a hardened decoder. Use Guarded or Assured for the built-in protocol controls, or supply a custom parser with the policy your application requires.
## 14.x Rust security profiles
Rust exposes the same Raw, Fast, Guarded, and Assured profile names and framed
wire contract. Guarded and Assured enforce a per-frame write ceiling because
Rust writes synchronously; they do not measure Node.js-style queued socket
writes. Rust Assured adds the event allow-list, but it cannot authenticate an
arbitrary `Read + Write` transport. The application must supply and verify
mutual TLS for hostile networks, enforce an owner-only Unix socket boundary,
or create and verify an appropriate Windows named-pipe ACL. UDP is rejected by
Rust Assured. See the [Rust security boundary](https://riaevangelist.github.io/node-ipc/rust/#security-boundary) for the exact contract.
## 14.x C# security profiles
C# mirrors the JavaScript Raw, Fast, Guarded, and Assured names and high-level
service API. Parser choice, TLS material and trust, payload logging, peer
identification, sync behavior, and local permission flags are captured when an
endpoint is constructed. Fast has framing but no inbound size or timeout limit;
use Guarded or Assured for untrusted peers.
C# Assured network service requires mutually authenticated TLS, verified custom
roots, identities with private keys, hostname and enhanced-key-usage checks,
and an event allowlist. Certificate AIA downloads and revocation networking are
disabled. UDP, plain network streams, accept-all validation callbacks, and
built-in Windows local Assured service fail closed.
On Unix, an Assured server requires a current-user-owned `0700` socket root and
an endpoint directly inside it. The built-in C# client does not verify root or
endpoint ownership; Assured local clients must verify ownership themselves
before connecting. `unlink=true` type- and identity-checks the path but cannot
prove that another same-user listener is dead, so supervised or multi-instance
deployments should manage liveness and use `unlink=false`.
As in JavaScript, event and logger callbacks are synchronous application code.
Do not install handlers that throw on untrusted input; validate payload schemas,
authorize operations, rate-limit peers, and contain application failures.
See the [profile guide](https://riaevangelist.github.io/node-ipc/profiles/), [parser contract](https://riaevangelist.github.io/node-ipc/parsers/), and [deployment security guide](https://riaevangelist.github.io/node-ipc/security/).
## Reporting a Vulnerability
Report vulnerabilities through GitHub's private [Report a vulnerability](https://github.com/RIAEvangelist/node-ipc/security/advisories/new) form. Do not open a public issue or discussion containing exploit details.
Include the affected version, impact, reproduction steps or a proof of concept, and any suggested mitigation. Avoid including real credentials, private keys, or data from systems you do not own.
The report and status updates will remain in the private security advisory until a fix and coordinated disclosure are ready. If the private reporting form is unavailable, open a public issue that contains no vulnerability details and asks the maintainer to provide a private contact channel.
Reporters who want public credit should say so in the private report; otherwise the disclosure will omit identifying information.
+226
-190

@@ -1,10 +0,9 @@

import net from 'net';
import tls from 'tls';
import EventParser from '../entities/EventParser.js';
import Message from 'js-message';
import fs from 'fs';
import Queue from 'js-queue';
import net from 'node:net';
import tls from 'node:tls';
import {createRequire} from 'node:module';
import Events from 'event-pubsub';
import {createParser,IPCProtocolError} from '../entities/EventParser.js';
import {createClientTLSOptions} from '../entities/TLS.js';
let eventParser = new EventParser();
const require=createRequire(import.meta.url);

@@ -14,241 +13,278 @@ class Client extends Events{

super();
this.Client=Client;
this.config=config;
this.log=log;
this.publish=super.emit;
(config.maxRetries)? this.retriesRemaining=config.maxRetries:0;
eventParser=new EventParser(this.config);
this.retriesRemaining=config.maxRetries || 0;
this.parser=createParser(config);
this.raw=this.parser.raw;
this.encoding=this.parser.encoding || 'utf8';
this.encode=this.parser.encode.bind(this.parser);
const maxPendingBytes=this.parser.maxPendingBytes;
this.writeSocket=Number.isFinite(maxPendingBytes) &&
maxPendingBytes>0
? this.writeGuarded
: this.writeDirect;
this.send=config.sync ? this.sendQueued : this.writeSocket;
this.queue=config.sync ? new (require('js-queue')) : null;
this.receive=this.raw
? (config.sync ? this.receiveRawSync : this.receiveRaw)
: (this.parser.messageTimeout ? this.receiveGuarded : this.receiveFramed);
this.dispatch=config.sync ? this.dispatchSync : this.dispatchDirect;
this.emit=config.logPayloads ? this.emitLogged : this.emitDirect;
if(config.logPayloads){
this.dispatch=config.sync ? this.dispatchLoggedSync : this.dispatchLogged;
}
this.receiveMessage=this.dispatch.bind(this);
}
Client=Client;
queue =new Queue;
socket=false;
connect=connect;
emit=emit;
retriesRemaining=0;
retryTimer=false;
explicitlyDisconnected=false;
}
protocolViolation=false;
function emit(type,data){
this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data);
emitDirect(type,data){
return this.send(this.encode(type,data));
}
let message=new Message;
message.type=type;
message.data=data;
emitLogged(type,data){
this.log('dispatching event to',this.id,this.path,':',this.raw ? '<raw-buffer>' : type,data);
return this.send(this.encode(type,data));
}
if(this.config.rawBuffer){
message=Buffer.from(type,this.config.encoding);
}else{
message=eventParser.format(message);
sendQueued(message){
this.queue.add(() => this.writeSocket(message));
return true;
}
//volitile emit
if(!this.config.sync){
this.socket.write(message);
return;
writeDirect(message){
return this.socket.write(message);
}
//sync, non-volitile, ack emit
this.queue.add(
syncEmit.bind(this,message)
);
}
writeGuarded(message){
const bytes=Buffer.isBuffer(message)
? message.length
: Buffer.byteLength(message,this.encoding);
if(this.socket.writableLength+bytes > this.parser.maxPendingBytes){
const error=new IPCProtocolError(
'ERR_IPC_BACKPRESSURE',
'pending socket writes exceed maxPendingBytes'
);
this.protocolFailure(this.socket,error);
return false;
}
return this.socket.write(message);
}
function syncEmit(message){
this.log('dispatching event to ', this.id, this.path, ' : ', message);
this.socket.write(message);
}
dispatchDirect(message){
this.publish(message.type,message.data);
}
function connect(){
//init client object for scope persistance especially inside of socket events.
let client=this;
dispatchSync(message){
this.publish(message.type,message.data);
this.queue.next();
}
client.log('requested connection to ', client.id, client.path);
if(!this.path){
client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.');
return;
dispatchLogged(message){
this.log('received event',message.type,message.data);
this.publish(message.type,message.data);
}
const options={};
dispatchLoggedSync(message){
this.log('received event',message.type,message.data);
this.publish(message.type,message.data);
this.queue.next();
}
if(!client.port){
client.log('Connecting client on Unix Socket :', client.path);
options.path=client.path;
if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){
options.path = options.path.replace(/^\//, '');
options.path = options.path.replace(/\//g, '-');
options.path= `\\\\.\\pipe\\${options.path}`;
connect(){
if(!this.path){
this.log('client has no socket path');
return;
}
client.socket = net.connect(options);
}else{
options.host=client.path;
options.port=client.port;
if(client.config.interface.localAddress){
options.localAddress=client.config.interface.localAddress;
if(this.socket && !this.socket.destroyed){
return this.socket;
}
if(client.config.interface.localPort){
options.localPort=client.config.interface.localPort;
if(this.retryTimer){
clearTimeout(this.retryTimer);
this.retryTimer=false;
}
if(client.config.interface.family){
options.family=client.config.interface.family;
const options=this.connectionOptions();
const secure=Boolean(this.port && this.config.tls);
if(this.port && this.parser.profile === 'assured' && !secure){
throw new IPCProtocolError(
'ERR_IPC_ASSURED_TRANSPORT',
'The assured parser requires TLS for network connections.'
);
}
if(client.config.interface.hints){
options.hints=client.config.interface.hints;
let socket;
if(!this.port){
this.log('connecting client on local socket',options.path);
socket=net.connect(options);
}else if(secure){
this.log('connecting client via TLS',this.path,this.port);
socket=tls.connect(createClientTLSOptions(
this.config.tls,
options,
this.parser.profile === 'assured'
));
}else{
this.log('connecting client via TCP',options);
socket=net.connect(options);
}
this.socket=socket;
if(client.config.interface.lookup){
options.lookup=client.config.interface.lookup;
socket.setNoDelay?.(true);
if(!this.raw){
socket.setEncoding(this.encoding);
}
if(!client.config.tls){
client.log('Connecting client via TCP to', options);
client.socket = net.connect(options);
}else{
client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls);
if(client.config.tls.private){
client.config.tls.key=fs.readFileSync(client.config.tls.private);
socket.on('error',(error) => {
if(socket !== this.socket){
return;
}
if(client.config.tls.public){
client.config.tls.cert=fs.readFileSync(client.config.tls.public);
this.log('client socket error',error);
this.publish('error',error);
});
socket.on(secure ? 'secureConnect' : 'connect',() => this.connected(socket));
socket.on('close',() => this.closed(socket));
socket.on('data',(data) => {
if(socket === this.socket){
this.receive(socket,data);
}
if(client.config.tls.trustedConnections){
if(typeof client.config.tls.trustedConnections === 'string'){
client.config.tls.trustedConnections=[client.config.tls.trustedConnections];
}
client.config.tls.ca=[];
for(let i=0; i<client.config.tls.trustedConnections.length; i++){
client.config.tls.ca.push(
fs.readFileSync(client.config.tls.trustedConnections[i])
);
}
});
return socket;
}
connectionOptions(){
if(!this.port){
let socketPath=this.path;
if(process.platform === 'win32' && !socketPath.startsWith('\\\\.\\pipe\\')){
socketPath=`\\\\.\\pipe\\${socketPath.replace(/^\//,'').replace(/\//g,'-')}`;
}
return {path:socketPath};
}
Object.assign(client.config.tls,options);
const options={host:this.path,port:this.port};
const source=this.config.interface;
for(const name of ['localAddress','localPort','family','hints','lookup']){
if(source[name]){
options[name]=source[name];
}
}
return options;
}
client.socket = tls.connect(
client.config.tls
);
connected(socket=this.socket){
if(socket !== this.socket){
return;
}
this.retriesRemaining=this.config.maxRetries;
this.publish('connect');
}
client.socket.setEncoding(this.config.encoding);
client.socket.on(
'error',
function(err){
client.log('\n\n######\nerror: ', err);
client.publish('error', err);
closed(socket=this.socket){
this.clearMessageTimer(socket);
if(socket !== this.socket){
return;
}
);
this.log('connection closed',this.id,this.path);
client.socket.on(
'connect',
function connectionMade(){
client.publish('connect');
client.retriesRemaining=client.config.maxRetries;
client.log('retrying reset');
if(
this.config.stopRetrying ||
this.retriesRemaining < 1 ||
this.explicitlyDisconnected ||
this.protocolViolation
){
this.publish('disconnect');
socket.destroy();
this.publish('destroy');
return;
}
);
client.socket.on(
'close',
function connectionClosed(){
client.log('connection closed' ,client.id , client.path,
client.retriesRemaining, 'tries remaining of', client.config.maxRetries
);
if(
client.config.stopRetrying ||
client.retriesRemaining<1 ||
client.explicitlyDisconnected
){
client.publish('disconnect');
client.log(
(client.config.id),
'exceeded connection rety amount of',
' or stopRetrying flag set.'
);
client.socket.destroy();
client.publish('destroy');
client=undefined;
this.retryTimer=setTimeout(() => {
this.retryTimer=false;
if(this.explicitlyDisconnected){
return;
}
setTimeout(
function retryTimeout(){
if (client.explicitlyDisconnected) {
return;
}
client.retriesRemaining--;
client.connect();
}.bind(null,client),
client.config.retry
);
client.publish('disconnect');
}
);
client.socket.on(
'data',
function(data) {
client.log('## received events ##');
if(client.config.rawBuffer){
client.publish(
'data',
Buffer.from(data,client.config.encoding)
);
if(!client.config.sync){
return;
}
client.queue.next();
if(this.config.stopRetrying){
socket.destroy();
this.publish('destroy');
return;
}
this.retriesRemaining--;
this.connect();
},this.config.retry);
this.publish('disconnect');
}
if(!this.ipcBuffer){
this.ipcBuffer='';
}
receiveRaw(socket,data){
this.publish('data',data);
}
data=(this.ipcBuffer+=data);
receiveRawSync(socket,data){
this.publish('data',data);
this.queue.next();
}
if(data.slice(-1)!=eventParser.delimiter || data.indexOf(eventParser.delimiter) == -1){
client.log('Messages are large, You may want to consider smaller messages.');
return;
}
receiveFramed(socket,data){
try{
socket.ipcBuffer=this.parser.read(socket.ipcBuffer || '',data,this.receiveMessage);
}catch(error){
this.handleReadError(socket,error);
}
}
this.ipcBuffer='';
receiveGuarded(socket,data){
this.receiveFramed(socket,data);
if(socket.destroyed){
return;
}
if(socket.ipcBuffer){
this.startMessageTimer(socket);
}else{
this.clearMessageTimer(socket);
}
}
const events = eventParser.parse(data);
const eCount = events.length;
for(let i=0; i<eCount; i++){
let message=new Message;
message.load(events[i]);
handleReadError(socket,error){
if(error instanceof IPCProtocolError){
this.protocolFailure(socket,error);
return;
}
throw error;
}
client.log('detected event', message.type, message.data);
client.publish(
message.type,
message.data
);
}
startMessageTimer(socket){
if(socket.ipcMessageTimer){
return;
}
socket.ipcMessageTimer=setTimeout(() => {
this.protocolFailure(
socket,
new IPCProtocolError('ERR_IPC_MESSAGE_TIMEOUT','incomplete message exceeded messageTimeout')
);
},this.parser.messageTimeout);
socket.ipcMessageTimer.unref?.();
}
if(!client.config.sync){
return;
}
clearMessageTimer(socket){
if(!socket?.ipcMessageTimer){
return;
}
clearTimeout(socket.ipcMessageTimer);
socket.ipcMessageTimer=undefined;
}
client.queue.next();
}
);
protocolFailure(socket,error){
this.clearMessageTimer(socket);
socket.ipcBuffer='';
this.protocolViolation=true;
this.log('IPC protocol error',error.code || 'ERR_IPC_PROTOCOL',error.message);
socket.destroy();
this.publish('error',error);
}
}

@@ -255,0 +291,0 @@

@@ -1,394 +0,493 @@

import net from 'net';
import tls from 'tls';
import fs from 'fs';
import dgram from 'dgram';
import EventParser from '../entities/EventParser.js';
import Message from 'js-message';
import dgram from 'node:dgram';
import fs from 'node:fs';
import net from 'node:net';
import path from 'node:path';
import tls from 'node:tls';
import Events from 'event-pubsub';
import {createParser,IPCProtocolError} from '../entities/EventParser.js';
import {createServerTLSOptions} from '../entities/TLS.js';
let eventParser = new EventParser();
class Server extends Events{
constructor(path,config,log,port){
constructor(socketPath,config,log,port){
super();
this.config = config;
this.path = path;
this.port = port;
this.log = log;
this.config=config;
this.path=socketPath;
this.port=port;
this.log=log;
this.publish=super.emit;
eventParser=new EventParser(this.config);
this.on(
'close',
serverClosed.bind(this)
);
this.parser=createParser(config);
this.raw=this.parser.raw;
this.encoding=this.parser.encoding || 'utf8';
this.encode=this.parser.encode.bind(this.parser);
const maxPendingBytes=this.parser.maxPendingBytes;
const boundedWrites=Number.isFinite(maxPendingBytes) &&
maxPendingBytes>0;
this.writeStream=boundedWrites
? this.writeStreamGuarded
: this.writeStreamDirect;
this.sendDatagram=boundedWrites
? this.sendDatagramGuarded
: this.sendDatagramDirect;
this.datagramCallback=boundedWrites
? this.handleDatagramError.bind(this)
: null;
this.writeDatagram=this.raw || this.encoding === 'utf8'
? this.writeDatagramDirect
: this.writeDatagramEncoded;
this.receive=this.raw
? this.receiveRaw
: (this.parser.messageTimeout ? this.receiveGuarded : this.receiveFramed);
if(config.logPayloads){
this.dispatch=config.identifyPeer
? this.dispatchIdentifiedLogged
: this.dispatchLogged;
}else{
this.dispatch=config.identifyPeer
? this.dispatchIdentified
: this.dispatchDirect;
}
this.emit=config.logPayloads ? this.emitLogged : this.emitDirect;
this.broadcast=config.logPayloads ? this.broadcastLogged : this.broadcastDirect;
this.selectTransport();
}
udp4=false;
udp6=false;
_udp4=false;
_udp6=false;
server=false;
sockets=[];
emit=emit;
broadcast=broadcast;
lastPeer=false;
onStart(socket){
this.publish(
'start',
socket
);
get udp4(){
return this._udp4;
}
stop(){
this.server.close();
set udp4(value){
this._udp4=value;
this.selectTransport();
}
get udp6(){
return this._udp6;
}
set udp6(value){
this._udp6=value;
this.selectTransport();
}
selectTransport(){
if(this._udp4 || this._udp6){
this.write=this.writeDatagram;
this.writeAll=this.writeAllDatagrams;
return;
}
this.write=this.writeStream;
this.writeAll=this.writeAllStreams;
}
onStart(socket){
this.publish('start',socket);
}
start(){
if(!this.path){
this.log('Socket Server Path not specified, refusing to start');
this.log('socket server path not specified');
return;
}
if(this.config.unlink){
fs.unlink(
this.path,
startServer.bind(this)
if(!this.port && this.parser.profile === 'assured' && process.platform === 'win32'){
throw new IPCProtocolError(
'ERR_IPC_ASSURED_TRANSPORT',
'Assured local transport requires Unix socket ownership checks; use mutual TLS or an application-owned Windows ACL.'
);
}else{
startServer.bind(this)();
}
}
}
if(!this.port && this.parser.profile === 'assured' && !this.config.secureSocketRoot){
throw new IPCProtocolError(
'ERR_IPC_ASSURED_TRANSPORT',
'The assured parser requires secureSocketRoot for local sockets.'
);
}
if(!this.port && this.parser.profile === 'assured' && !socketPathInRoot(this)){
throw new IPCProtocolError(
'ERR_IPC_ASSURED_TRANSPORT',
'The assured parser requires a local endpoint directly inside socketRoot.'
);
}
function emit(socket, type, data){
this.log('dispatching event to socket', ' : ', type, data);
if(!this.port && process.platform !== 'win32'){
prepareSocketRoot(this);
if(this.config.unlink){
unlinkSocket(this.path);
}
}
let message=new Message;
message.type=type;
message.data=data;
if(this.config.rawBuffer){
this.log(this.config.encoding)
message=Buffer.from(type,this.config.encoding);
}else{
message=eventParser.format(message);
this.startServer();
}
if(this.udp4 || this.udp6){
if(!socket.address || !socket.port){
this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets');
this.broadcast(type,data);
return;
stop(){
for(const socket of this.sockets){
this.clearMessageTimer(socket);
socket.destroy?.();
}
this.sockets.length=0;
this.lastPeer=false;
if(this.server && typeof this.server.close === 'function'){
this.server.close();
}
}
this.server.write(
message,
socket
);
return;
emitDirect(socket,type,data){
return this.write(socket,this.encode(type,data));
}
socket.write(message);
}
function broadcast(type,data){
this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data);
let message=new Message;
message.type=type;
message.data=data;
emitLogged(socket,type,data){
this.log('dispatching event to socket',type,data);
return this.write(socket,this.encode(type,data));
}
if(this.config.rawBuffer){
message=Buffer.from(type,this.config.encoding);
}else{
message=eventParser.format(message);
broadcastDirect(type,data){
return this.writeAll(this.encode(type,data));
}
if(this.udp4 || this.udp6){
for(let i=1, count=this.sockets.length; i<count; i++){
this.server.write(message,this.sockets[i]);
}
}else{
for(let i=0, count=this.sockets.length; i<count; i++){
this.sockets[i].write(message);
}
broadcastLogged(type,data){
this.log('broadcasting event',type,data);
return this.writeAll(this.encode(type,data));
}
}
function serverClosed(){
for(let i=0, count=this.sockets.length; i<count; i++){
let socket=this.sockets[i];
let destroyedSocketId=false;
if(socket){
if(socket.readable){
continue;
writeAllStreams(message){
let writable=true;
for(const socket of this.sockets){
const result=this.writeStream(socket,message);
if(result === false){
writable=false;
}
}
return writable;
}
if(socket.id){
destroyedSocketId=socket.id;
writeAllDatagrams(message){
for(const socket of this.sockets){
this.writeDatagram(socket,message);
}
return true;
}
this.log('socket disconnected',destroyedSocketId.toString());
writeStreamDirect(socket,message){
return socket.write(message);
}
if(socket && socket.destroy){
socket.destroy();
writeStreamGuarded(socket,message){
const bytes=Buffer.isBuffer(message)
? message.length
: Buffer.byteLength(message,this.encoding);
if(socket.writableLength+bytes > this.parser.maxPendingBytes){
this.protocolFailure(
socket,
new IPCProtocolError(
'ERR_IPC_BACKPRESSURE',
'pending socket writes exceed maxPendingBytes'
)
);
return false;
}
return socket.write(message);
}
this.sockets.splice(i,1);
this.publish('socket.disconnected', socket, destroyedSocketId);
return;
writeDatagramDirect(socket,message){
if(!socket?.address || !socket?.port){
return this.writeAllDatagrams(message);
}
return this.sendDatagram(message,socket.port,socket.address);
}
}
function gotData(socket,data,UDPSocket){
let sock=((this.udp4 || this.udp6)? UDPSocket : socket);
if(this.config.rawBuffer){
data=Buffer.from(data,this.config.encoding);
this.publish(
'data',
data,
sock
writeDatagramEncoded(socket,message){
if(!socket?.address || !socket?.port){
return this.writeAllDatagrams(message);
}
return this.sendDatagram(
Buffer.from(message,this.encoding),
socket.port,
socket.address
);
return;
}
if(!sock.ipcBuffer){
sock.ipcBuffer='';
sendDatagramDirect(data,port,address){
this.server.send(data,port,address);
return true;
}
data=(sock.ipcBuffer+=data);
sendDatagramGuarded(data,port,address){
this.server.send(data,port,address,this.datagramCallback);
return true;
}
if(data.slice(-1)!=eventParser.delimiter || data.indexOf(eventParser.delimiter) == -1){
this.log('Messages are large, You may want to consider smaller messages.');
return;
handleDatagramError(error){
if(!error){
return;
}
this.log('error writing datagram',error);
this.publish('error',error);
}
sock.ipcBuffer='';
startServer(){
this.log('starting server on',this.path,this.port ? `:${this.port}` : '');
if(this.parser.profile === 'assured' && (this.udp4 || this.udp6 || (this.port && !this.config.tls))){
throw new IPCProtocolError(
'ERR_IPC_ASSURED_TRANSPORT',
'The assured parser requires TLS for network servers.'
);
}
if(this.udp4 || this.udp6){
this.startDatagramServer();
return;
}
data=eventParser.parse(data);
this.server=this.config.tls
? tls.createServer(
createServerTLSOptions(
this.config.tls,
this.parser.profile === 'assured'
),
(socket) => this.addSocket(socket)
)
: net.createServer((socket) => this.addSocket(socket));
this.server.maxConnections=this.config.maxConnections;
this.server.on('error',(error) => this.serverError(error));
while(data.length>0){
let message=new Message;
message.load(data.shift());
// Only set the sock id if it is specified.
if (message.data && message.data.id){
sock.id=message.data.id;
if(!this.port){
if(process.platform === 'win32'){
this.path=`\\\\.\\pipe\\${this.path.replace(/^\//,'').replace(/\//g,'-')}`;
}
this.server.listen({
path:this.path,
readableAll:this.config.readableAll,
writableAll:this.config.writableAll
},() => this.onStart(this.server));
return;
}
this.log('received event of : ',message.type,message.data);
this.server.listen(this.port,this.path,() => this.onStart(this.server));
}
this.publish(
message.type,
message.data,
sock
);
startDatagramServer(){
this.server=dgram.createSocket(this.udp4 ? 'udp4' : 'udp6');
this.server.on('error',(error) => this.serverError(error));
this.server.on('message',(message,rinfo) => this.receiveDatagram(message,rinfo));
this.server.bind(this.port,this.path,() => {
this.publish('connect',this.server);
this.onStart(this.server);
});
}
}
function socketClosed(socket){
this.publish(
'close',
socket
);
}
addSocket(socket){
this.sockets.push(socket);
socket.setNoDelay?.(true);
socket.ipcBuffer='';
socket.ipcDispatch=(message) => this.dispatch(message,socket);
if(!this.raw){
socket.setEncoding(this.encoding);
}
socket.on('close',() => {
this.removeSocket(socket);
this.publish('close',socket);
});
socket.on('error',(error) => {
this.log('server socket error',error);
this.publish('error',error);
});
socket.on('data',(data) => this.receive(socket,data));
this.publish('connect',socket);
}
function serverCreated(socket) {
this.sockets.push(socket);
if(socket.setEncoding){
socket.setEncoding(this.config.encoding);
receiveDatagram(message,rinfo){
const peer=this.peer(rinfo);
const data=this.raw ? message : message.toString(this.encoding);
this.receive(peer,data);
}
this.log('## socket connection to server detected ##');
socket.on(
'close',
socketClosed.bind(this)
);
peer(rinfo){
let peer=this.lastPeer;
if(peer?.address === rinfo.address && peer.port === rinfo.port){
return peer;
}
for(let index=0;index<this.sockets.length;index++){
peer=this.sockets[index];
if(peer.address === rinfo.address && peer.port === rinfo.port){
this.lastPeer=peer;
return peer;
}
}
socket.on(
'error',
function(err){
this.log('server socket error',err);
peer={...rinfo,ipcBuffer:''};
peer.ipcDispatch=(message) => this.dispatch(message,peer);
this.sockets.push(peer);
this.lastPeer=peer;
return peer;
}
this.publish('error',err);
}.bind(this)
);
receiveRaw(socket,data){
this.publish('data',data,socket);
}
socket.on(
'data',
gotData.bind(this,socket)
);
receiveFramed(socket,data){
try{
socket.ipcBuffer=this.parser.read(socket.ipcBuffer || '',data,socket.ipcDispatch);
}catch(error){
this.handleReadError(socket,error);
}
}
socket.on(
'message',
function(msg,rinfo) {
if (!rinfo){
return;
}
receiveGuarded(socket,data){
this.receiveFramed(socket,data);
if(socket.destroyed){
return;
}
if(socket.ipcBuffer){
this.startMessageTimer(socket);
}else{
this.clearMessageTimer(socket);
}
}
this.log('Received UDP message from ', rinfo.address, rinfo.port);
let data;
dispatchDirect(message,socket){
this.publish(message.type,message.data,socket);
}
if(this.config.rawSocket){
data=Buffer.from(msg,this.config.encoding);
}else{
data=msg.toString();
}
socket.emit('data',data,rinfo);
}.bind(this)
);
dispatchIdentified(message,socket){
if(message.data?.id){
socket.id=message.data.id;
}
this.publish(message.type,message.data,socket);
}
this.publish(
'connect',
socket
);
dispatchLogged(message,socket){
this.log('received event',message.type,message.data);
this.publish(message.type,message.data,socket);
}
if(this.config.rawBuffer){
return;
dispatchIdentifiedLogged(message,socket){
this.log('received event',message.type,message.data);
this.dispatchIdentified(message,socket);
}
}
function startServer() {
this.log(
'starting server on ',this.path,
((this.port)?`:${this.port}`:'')
);
handleReadError(socket,error){
if(error instanceof IPCProtocolError){
this.protocolFailure(socket,error);
return;
}
throw error;
}
if(!this.udp4 && !this.udp6){
this.log('starting TLS server',this.config.tls);
if(!this.config.tls){
this.server=net.createServer(
serverCreated.bind(this)
startMessageTimer(socket){
if(socket.ipcMessageTimer){
return;
}
socket.ipcMessageTimer=setTimeout(() => {
this.protocolFailure(
socket,
new IPCProtocolError('ERR_IPC_MESSAGE_TIMEOUT','incomplete message exceeded messageTimeout')
);
}else{
startTLSServer.bind(this)();
},this.parser.messageTimeout);
socket.ipcMessageTimer.unref?.();
}
clearMessageTimer(socket){
if(!socket?.ipcMessageTimer){
return;
}
}else{
this.server=dgram.createSocket(
((this.udp4)? 'udp4':'udp6')
);
this.server.write=UDPWrite.bind(this);
this.server.on(
'listening',
function UDPServerStarted() {
serverCreated.bind(this)(this.server);
}.bind(this)
);
clearTimeout(socket.ipcMessageTimer);
socket.ipcMessageTimer=undefined;
}
this.server.on(
'error',
function(err){
this.log('server error',err);
protocolFailure(socket,error){
this.clearMessageTimer(socket);
socket.ipcBuffer='';
this.log('IPC protocol error',error.code || 'ERR_IPC_PROTOCOL',error.message);
socket.destroy?.();
this.publish('error',error);
}
this.publish(
'error',
err
);
}.bind(this)
);
this.server.maxConnections=this.config.maxConnections;
if(!this.port){
this.log('starting server as', 'Unix || Windows Socket');
if (process.platform ==='win32'){
this.path = this.path.replace(/^\//, '');
this.path = this.path.replace(/\//g, '-');
this.path= `\\\\.\\pipe\\${this.path}`;
removeSocket(socket){
const index=this.sockets.indexOf(socket);
if(index === -1 || socket.readable){
return;
}
this.sockets.splice(index,1);
if(this.lastPeer === socket){
this.lastPeer=false;
}
const id=socket.id || false;
if(!socket.destroyed){
socket.destroy?.();
}
this.clearMessageTimer(socket);
this.publish('socket.disconnected',socket,id);
}
this.server.listen({
path: this.path,
readableAll: this.config.readableAll,
writableAll: this.config.writableAll
}, this.onStart.bind(this));
serverError(error){
this.log('server error',error);
this.publish('error',error);
}
}
function prepareSocketRoot(server){
const root=path.resolve(server.config.socketRoot);
const relative=path.relative(root,path.resolve(server.path));
if(pathOutsideRoot(relative)){
return;
}
if(!this.udp4 && !this.udp6){
this.log('starting server as', (this.config.tls?'TLS':'TCP'));
this.server.listen(
this.port,
this.path,
this.onStart.bind(this)
);
fs.mkdirSync(root,{recursive:true,mode:0o700});
if(!server.config.secureSocketRoot){
return;
}
this.log('starting server as',((this.udp4)? 'udp4':'udp6'));
const stat=fs.lstatSync(root);
if(!stat.isDirectory() || stat.isSymbolicLink()){
throw socketRootError('socketRoot must be a real directory');
}
if(typeof process.getuid === 'function' && stat.uid !== process.getuid()){
throw socketRootError('socketRoot must be owned by the current user');
}
if((stat.mode & 0o077) !== 0){
fs.chmodSync(root,0o700);
}
}
this.server.bind(
this.port,
this.path
);
function socketPathInRoot(server){
const root=path.resolve(server.config.socketRoot);
const relative=path.relative(root,path.resolve(server.path));
return Boolean(relative) &&
!pathOutsideRoot(relative) &&
path.dirname(relative) === '.';
}
this.onStart(
{
address : this.path,
port : this.port
}
);
function pathOutsideRoot(relative){
return relative === '..' ||
relative.startsWith(`..${path.sep}`) ||
path.isAbsolute(relative);
}
function startTLSServer(){
this.log('starting TLS server',this.config.tls);
if(this.config.tls.private){
this.config.tls.key=fs.readFileSync(this.config.tls.private);
}else{
this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`);
function unlinkSocket(socketPath){
let stat;
try{
stat=fs.lstatSync(socketPath);
}catch(error){
if(error.code === 'ENOENT'){
return;
}
throw error;
}
if(this.config.tls.public){
this.config.tls.cert=fs.readFileSync(this.config.tls.public);
}else{
this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`);
if(!stat.isSocket()){
const error=new Error('refusing to unlink a non-socket path');
error.code='ERR_IPC_UNLINK_NOT_SOCKET';
throw error;
}
if(this.config.tls.dhparam){
this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam);
}
if(this.config.tls.trustedConnections){
if(typeof this.config.tls.trustedConnections === 'string'){
this.config.tls.trustedConnections=[this.config.tls.trustedConnections];
}
this.config.tls.ca=[];
for(let i=0; i<this.config.tls.trustedConnections.length; i++){
this.config.tls.ca.push(
fs.readFileSync(this.config.tls.trustedConnections[i])
);
}
}
this.server=tls.createServer(
this.config.tls,
serverCreated.bind(this)
);
fs.unlinkSync(socketPath);
}
function UDPWrite(message,socket){
let data=Buffer.from(message, this.config.encoding);
this.server.send(
data,
0,
data.length,
socket.port,
socket.address,
function(err, bytes) {
if(err){
this.log('error writing data to socket',err);
this.publish(
'error',
function(err){
this.publish('error',err);
}
);
}
}
);
function socketRootError(message){
const error=new Error(message);
error.code='ERR_IPC_SOCKET_ROOT';
return error;
}

@@ -395,0 +494,0 @@

@@ -1,12 +0,7 @@

import os from 'os';
import os from 'node:os';
import path from 'node:path';
class Defaults{
constructor(){
}
appspace='app.';
socketRoot='/tmp/';
socketRoot=getSocketRoot();
id=os.hostname();

@@ -16,8 +11,17 @@

rawBuffer=false;
parser='fast';
sync=false;
unlink=true;
identifyPeer=false;
delimiter='\f';
maxMessageSize=1024*1024;
maxPendingBytes=8*1024*1024;
maxEventNameLength=256;
messageTimeout=30000;
allowReservedEvents=false;
allowedEvents=false;
silent=false;
logPayloads=false;
logDepth=5;

@@ -39,2 +43,3 @@ logInColor=true;

writableAll = false;
secureSocketRoot = true;

@@ -51,14 +56,37 @@ interface={

function getSocketRoot(){
const userName=safePathSegment(getUserName());
if(process.platform === 'win32'){
return `/node-ipc-${userName}/`;
}
const runtimeRoot=process.env.XDG_RUNTIME_DIR;
if(runtimeRoot){
return path.join(runtimeRoot,'node-ipc')+path.sep;
}
const userId=typeof process.getuid === 'function' ? process.getuid() : userName;
return path.join(os.tmpdir(),`node-ipc-${userId}`)+path.sep;
}
function getUserName(){
try{
return os.userInfo().username;
}catch{
return 'user';
}
}
function safePathSegment(value){
return String(value).replace(/[^a-zA-Z0-9_.-]/g,'_');
}
function getIPType() {
const networkInterfaces = os.networkInterfaces();
let IPType = '';
if (networkInterfaces
&& Array.isArray(networkInterfaces)
&& networkInterfaces.length > 0) {
// getting the family of first network interface available
IPType = networkInterfaces [
Object.keys( networkInterfaces )[0]
][0].family;
const interfaces=os.networkInterfaces();
for(const addresses of Object.values(interfaces || {})){
if(addresses?.length){
return addresses[0].family;
}
}
return IPType;
return '';
}

@@ -65,0 +93,0 @@

@@ -1,34 +0,287 @@

import Defaults from './Defaults.js';
const reservedEventTypes=new Set([
'start',
'connect',
'disconnect',
'destroy',
'close',
'socket.disconnected',
'error',
'data'
]);
const unsafeEventTypes=new Set(Object.getOwnPropertyNames(Object.prototype));
const emptyPayload={};
class IPCProtocolError extends Error{
constructor(code,message){
super(message);
this.name='IPCProtocolError';
this.code=code;
}
}
class RawParser{
constructor(config=new Defaults){
this.encoding=config.encoding;
}
profile='raw';
raw=true;
encode(value){
return Buffer.isBuffer(value) ? value : Buffer.from(value,this.encoding);
}
format(value){
return this.encode(value);
}
read(buffer,data,receive){
receive(data);
return buffer;
}
parse(data){
return [data];
}
decode(data){
return data;
}
}
class Parser{
constructor(config){
if(!config){
config=new Defaults;
constructor(config=new Defaults){
this.delimiter=config.delimiter;
if(typeof this.delimiter !== 'string' || this.delimiter.length === 0){
throw new TypeError('ipc.config.delimiter must be a non-empty string');
}
}
this.delimiter=config.delimiter;
}
format(message){
if(!message.data && message.data!==false && message.data!==0){
message.data={};
profile='fast';
raw=false;
encoding='utf8';
encode(type,data=emptyPayload){
return JSON.stringify({type,data})+this.delimiter;
}
if(message.data['_maxListeners']){
message.data={};
format(message){
return this.encode(message.type,message.data);
}
message=message.JSON+this.delimiter;
return message;
}
read(buffer,data,receive){
const combined=buffer ? buffer+data : data;
const delimiter=this.delimiter;
const length=delimiter.length;
let start=0;
let end=combined.indexOf(delimiter);
parse(data){
let events=data.split(this.delimiter);
events.pop();
return events;
}
while(end !== -1){
receive(this.decode(combined.slice(start,end)));
start=end+length;
end=combined.indexOf(delimiter,start);
}
return start === 0 ? combined : combined.slice(start);
}
push(buffer='',data=''){
const combined=buffer ? buffer+data : data;
const events=[];
const delimiter=this.delimiter;
const length=delimiter.length;
let start=0;
let end=combined.indexOf(delimiter);
while(end !== -1){
events.push(combined.slice(start,end));
start=end+length;
end=combined.indexOf(delimiter,start);
}
return {
events,
remainder:start === 0 ? combined : combined.slice(start)
};
}
parse(data){
return this.push('',data).events;
}
decode(frame){
try{
return JSON.parse(frame);
}catch{
throw new IPCProtocolError('ERR_IPC_INVALID_JSON','received message is not valid JSON');
}
}
}
class GuardedParser extends Parser{
constructor(config=new Defaults){
super(config);
this.maxMessageSize=config.maxMessageSize;
this.maxPendingBytes=config.maxPendingBytes;
this.maxEventNameLength=config.maxEventNameLength;
this.messageTimeout=config.messageTimeout;
this.allowReservedEvents=config.allowReservedEvents;
this.delimiterBytes=Buffer.byteLength(this.delimiter);
validateLimit(this.maxMessageSize,'maxMessageSize');
validateLimit(this.maxPendingBytes,'maxPendingBytes');
validateLimit(this.maxEventNameLength,'maxEventNameLength');
if(this.messageTimeout !== 0){
validateLimit(this.messageTimeout,'messageTimeout');
}
}
profile='guarded';
encode(type,data){
this.validateType(type);
const frame=super.encode(type,data);
this.assertFrameSize(
frame.length-this.delimiter.length,
Buffer.byteLength(frame)-this.delimiterBytes
);
return frame;
}
read(buffer,data,receive){
const combined=buffer ? buffer+data : data;
const delimiter=this.delimiter;
const length=delimiter.length;
let start=0;
let end=combined.indexOf(delimiter);
while(end !== -1){
const frame=combined.slice(start,end);
this.assertFrameSize(frame.length,Buffer.byteLength(frame));
receive(this.decodeMessage(frame));
start=end+length;
end=combined.indexOf(delimiter,start);
}
const remainder=start === 0 ? combined : combined.slice(start);
this.assertFrameSize(remainder.length,Buffer.byteLength(remainder));
return remainder;
}
push(buffer='',data=''){
const parsed=super.push(buffer,data);
for(const frame of parsed.events){
this.assertFrameSize(frame.length,Buffer.byteLength(frame));
}
this.assertFrameSize(
parsed.remainder.length,
Buffer.byteLength(parsed.remainder)
);
return parsed;
}
decode(frame){
this.assertFrameSize(frame.length,Buffer.byteLength(frame));
return this.decodeMessage(frame);
}
decodeMessage(frame){
const message=super.decode(frame);
if(!message || typeof message !== 'object' || Array.isArray(message)){
throw new IPCProtocolError('ERR_IPC_INVALID_MESSAGE','received message must be a JSON object');
}
this.validateType(message.type);
return message;
}
validateType(type){
if(typeof type !== 'string' || type.length === 0){
throw new IPCProtocolError('ERR_IPC_INVALID_EVENT','event type must be a non-empty string');
}
if(type.length > this.maxEventNameLength){
throw new IPCProtocolError('ERR_IPC_EVENT_TOO_LARGE','event type exceeds maxEventNameLength');
}
if(unsafeEventTypes.has(type)){
throw new IPCProtocolError('ERR_IPC_INVALID_EVENT',`event type "${type}" is not safe for the active event dispatcher`);
}
if(!this.allowReservedEvents && reservedEventTypes.has(type)){
throw new IPCProtocolError('ERR_IPC_RESERVED_EVENT',`event type "${type}" is reserved for local lifecycle events`);
}
}
assertFrameSize(characters,bytes){
if(bytes <= this.maxMessageSize){
return;
}
throw new IPCProtocolError('ERR_IPC_FRAME_TOO_LARGE','message exceeds maxMessageSize');
}
}
class AssuredParser extends GuardedParser{
constructor(config=new Defaults){
super(config);
const allowed=config.allowedEvents;
if(!(Array.isArray(allowed) || allowed instanceof Set) || allowed.size === 0 || allowed.length === 0){
throw new TypeError('ipc.config.allowedEvents must be a non-empty Array or Set for the assured parser');
}
this.allowedEvents=new Set(allowed);
this.allowReservedEvents=false;
}
profile='assured';
validateType(type){
super.validateType(type);
if(!this.allowedEvents.has(type)){
throw new IPCProtocolError('ERR_IPC_EVENT_NOT_ALLOWED','event type is not in allowedEvents');
}
}
}
function createParser(config){
const selected=config.rawBuffer ? 'raw' : config.parser;
let parser;
if(selected === 'raw'){
parser=new RawParser(config);
}else if(!selected || selected === 'fast'){
parser=new Parser(config);
}else if(selected === 'guarded'){
parser=new GuardedParser(config);
}else if(selected === 'assured'){
parser=new AssuredParser(config);
}else if(typeof selected === 'function'){
parser=new selected(config);
}else{
parser=selected;
}
if(!parser || typeof parser.encode !== 'function' || typeof parser.read !== 'function'){
throw new TypeError('ipc.config.parser must be "raw", "fast", "guarded", "assured", or an object with encode() and read() methods');
}
return parser;
}
function validateLimit(value,name){
if(value === Infinity){
return;
}
if(!Number.isInteger(value) || value < 1){
throw new TypeError(`ipc.config.${name} must be a positive integer or Infinity`);
}
}
export {
Parser as default,
Parser
AssuredParser,
Parser as FastParser,
GuardedParser,
IPCProtocolError,
Parser,
Parser as default,
RawParser,
createParser,
reservedEventTypes
};
import IPC from './services/IPC.js';
import {
AssuredParser,
FastParser,
GuardedParser,
IPCProtocolError,
Parser,
RawParser
} from './entities/EventParser.js';
class IPCModule extends IPC{
constructor(){
super();
}
IPC=IPC;

@@ -15,4 +18,10 @@ }

export {
AssuredParser,
FastParser,
GuardedParser,
IPCProtocolError,
singleton as default,
IPCModule
IPCModule,
Parser,
RawParser
}
{
"name": "node-ipc",
"version": "12.0.0",
"description": "A nodejs module for local and remote Inter Process Communication (IPC), Neural Networking, and able to facilitate machine learning.",
"version": "14.0.0",
"description": "Fast local and network IPC with Node.js-only JavaScript and aligned dependency-free Rust and C# implementations.",
"type": "module",
"main": "node-ipc.cjs",
"module": "node-ipc.js",
"main": "./node-ipc.js",
"exports": {
"import": "./node-ipc.js",
"require": "./node-ipc.cjs"
".": "./node-ipc.js",
"./parsers": "./entities/EventParser.js",
"./parsers/message": "./entities/MessageParser.js"
},
"directories": {
"example": "example"
},
"files": [
"node-ipc.js",
"dao/",
"entities/",
"services/",
"README.md",
"MIGRATION.md",
"SECURITY.md",
"licence"
],
"sideEffects": false,
"engines": {
"node": ">=14"
"node": ">=22.13.0"
},
"dependencies": {
"event-pubsub": "5.0.3",
"js-message": "1.0.7",
"js-queue": "2.0.2",
"strong-type": "^1.0.1"
"event-pubsub": "6.1.1",
"js-message": "3.1.0",
"js-queue": "3.1.0"
},
"devDependencies": {
"c8": "^7.7.3",
"esbuild": "^0.12.28",
"lcov2badge": "^0.1.2",
"node-cmd": "^4.0.0",
"node-http-server": "^8.1.4",
"vanilla-test": "^1.4.8"
"node-http-server": "9.1.0",
"vanilla-test": "2.1.3"
},
"scripts": {
"prepare": "esbuild node-ipc.js --bundle --format=cjs --target=es2018 --platform=node --outfile=node-ipc.cjs",
"test": "npm i && c8 -r lcov -r html node test/CI.js && c8 report && node ./lcov.js",
"coverage": "echo 'See your coverage report at http://localhost:8080' && node-http-server port=8080 root=./coverage/"
"benchmark": "node ./benchmark/run.js",
"benchmark:c-smoke": "node ./benchmark/c-oracle-smoke.js",
"benchmark:chart": "node ./benchmark/render-chart.js",
"benchmark:chart:check": "node ./benchmark/render-chart.js --check",
"benchmark:dashboard": "node ./benchmark/dashboard.js",
"benchmark:quick": "node ./benchmark/run.js --quick",
"benchmark:record": "node ./benchmark/record-result.js --full --oracle=c --footprint",
"benchmark:rust": "node ./benchmark/rust/run.js --full",
"benchmark:rust:chart": "node ./benchmark/rust/chart.js",
"benchmark:rust:chart:check": "node ./benchmark/rust/chart.js --check",
"benchmark:rust:merge": "node ./benchmark/rust/merge.js",
"benchmark:rust:quick": "node ./benchmark/rust/run.js --quick",
"benchmark:rust:record": "node ./benchmark/rust/record.js --full",
"benchmark:rust:test": "node ./benchmark/rust/test.js",
"benchmark:rust:validate": "node ./benchmark/rust/validate.js",
"benchmark:rust:validate:tracked": "node ./benchmark/rust/validate.js --tracked ./benchmark/rust-results",
"benchmark:test": "node ./benchmark/test.js",
"benchmark:transport": "node ./benchmark/transport/run.js",
"benchmark:transport:chart": "node ./benchmark/render-transport-chart.js",
"benchmark:transport:chart:check": "node ./benchmark/render-transport-chart.js --check",
"benchmark:transport:c-oracle:test": "node ./benchmark/transport/c-oracle.test.js",
"benchmark:transport:dashboard": "node ./benchmark/transport-dashboard.js",
"benchmark:transport:evidence:test": "node ./benchmark/transport-evidence.test.js",
"benchmark:transport:merge": "node ./benchmark/merge-transport-results.js",
"benchmark:transport:prepare": "node ./benchmark/transport/prepare-v12.js",
"benchmark:transport:record": "node ./benchmark/record-transport-result.js --full",
"benchmark:transport:test": "node ./benchmark/transport/test.js",
"benchmark:transport:validate": "node ./benchmark/validate-transport-results.js",
"benchmark:validate": "node ./benchmark/validate-results.js",
"coverage": "echo 'See your coverage report at http://127.0.0.1:8080' && node-http-server host=127.0.0.1 domain=127.0.0.1 port=8080 root=./coverage/node/",
"test": "npm run test:correctness && npm run test:smoke && npm run benchmark:test && npm run benchmark:rust:test && npm run benchmark:rust:validate:tracked && npm run benchmark:rust:chart:check && npm run benchmark:validate && npm run benchmark:chart:check && npm run benchmark:transport:test && npm run benchmark:transport:evidence:test && npm run benchmark:transport:validate && npm run benchmark:transport:chart:check",
"test:behavioral": "node ./test/behavioral/portable-json.test.js && node ./test/behavioral/vanilla-test.js",
"test:correctness": "npm run test:inventory && vanilla-test coverage node",
"test:inventory": "node ./test/inventory.js",
"test:csharp": "dotnet run --project ./csharp/node-ipc/tests/NodeIpc.Tests/NodeIpc.Tests.csproj -c Release",
"test:csharp:interop": "node ./csharp/node-ipc/interop/vanilla-test.js",
"test:csharp:package": "pwsh -NoProfile -File ./csharp/node-ipc/package-smoke.ps1",
"test:smoke": "npm run test:smoke:runtime && npm run test:smoke:transport && npm run test:smoke:package",
"test:smoke:package": "node ./test/package-smoke.js",
"test:smoke:runtime": "node ./test/runtime-smoke.js",
"test:smoke:transport": "node ./test/transport-smoke.js"
},

@@ -63,3 +104,3 @@ "keywords": [

"type": "git",
"url": "https://github.com/RIAEvangelist/node-ipc.git"
"url": "git+https://github.com/RIAEvangelist/node-ipc.git"
},

@@ -69,3 +110,3 @@ "bugs": {

},
"homepage": "http://riaevangelist.github.io/node-ipc/"
}
"homepage": "https://riaevangelist.github.io/node-ipc/"
}
+219
-57

@@ -1,28 +0,110 @@

node-ipc
================
[![node-ipc - local and remote inter-process communication for Node.js](https://raw.githubusercontent.com/RIAEvangelist/node-ipc/main/assets/node-ipc-header.png)](https://riaevangelist.github.io/node-ipc/)
# node-ipc
[![Sponsor RIAEvangelist to help development of node-ipc](https://img.shields.io/static/v1?label=Sponsor%20Me%20On%20Github&message=%E2%9D%A4&logo=GitHub&link=https://github.com/sponsors/RIAEvangelist)](https://github.com/sponsors/RIAEvangelist)
*a nodejs module for local and remote Inter Process Communication* with full support for Linux, Mac and Windows. It also supports all forms of socket communication from low level unix and windows sockets to UDP and secure TLS and TCP sockets.
**node-ipc 14.0.0 source for the aligned [npm](https://www.npmjs.com/package/node-ipc), [NuGet](https://www.nuget.org/packages/node-ipc), and [crates.io](https://crates.io/crates/node-ipc) release**
Fast local and remote process communication for Node.js, C#, and Rust on Linux,
macOS, and Windows. The aligned implementations share the normal node-ipc event
envelope and delimiter framing across local sockets, TCP, and UDP.
A great solution for complex multiprocess **Neural Networking** in Node.JS
`npm install node-ipc`
`npm install --save-exact node-ipc@14.0.0`
#### for node <v14
Rust: `cargo add node-ipc@14.0.0 --exact`
`npm install node-ipc@^9.0.0`
C#: `dotnet add package node-ipc --version 14.0.0`
#### including v10 or greater into your code
Use an exact, reviewed version. Do not use a mutable tag or version range for security-sensitive deployments.
```js
#### Runtime
//es6
import ipc from 'node-ipc'
Version 14 requires Node.js 22.13.0 or newer. The native ports require Rust
1.85 or newer and .NET 8 or newer. Version 12 remains the legacy Node release
line; version 13 was never published.
//commonjs
const ipc = require('node-ipc').default;
`node-ipc` ships native ES modules only. Node.js loads the same entry point through `import` or synchronous `require()`; no transpiled CommonJS bundle is generated.
The `node-ipc` JavaScript package is **Node.js-only**. It uses Node's raw TCP,
TLS, UDP, Unix-domain socket, Windows named-pipe, filesystem, OS, process, and
`Buffer` APIs. It is not supported in browsers, with or without a bundler.
“Native ESM” means that Node loads the one JavaScript implementation without a
transpiler; it does not mean native-browser ESM. The documentation website's
browser code is separate and is not part of the npm package runtime.
#### Node.js runtime profiles
The Node.js implementation selects its parser and hot-path handlers once, when each client or server is created. It does not poll a security flag for every message. Set the profile before calling `connect*()` or `serve*()`.
| Profile | Work on every message | Intended boundary |
|---------|-----------------------|-------------------|
| `raw` | No node-ipc framing, JSON parsing, or message checks. Buffers pass through the `data` event. | Trusted peers using a caller-owned binary or text protocol. |
| `fast` | JSON event-envelope encoding/decoding and delimiter framing. Malformed JSON becomes a protocol error; stream connections close. | Default for trusted local peers where the application owns payload validity. |
| `guarded` | Fast framing plus frame-size, stream pending-write, event-name, reserved/prototype-name, envelope, and incomplete-message-time controls. | Mixed-trust local services and authenticated network applications. |
| `assured` | Guarded controls plus a required event allow-list. Network use requires mutually authenticated TLS; each Unix local server endpoint must be a direct child of the secure socket root. Built-in Windows local service is rejected because node-ipc cannot prove its named-pipe ACL. | Hostile-network building block with verified peer certificates and application authorization; not a certification. |
```javascript
ipc.config.parser = 'guarded';
ipc.config.maxMessageSize = 1024 * 1024;
ipc.config.maxPendingBytes = 8 * 1024 * 1024;
```
These transport guarantees are Node.js-specific. Rust shares the four codec
profiles but requires the caller to establish and verify the transport boundary.
See [Profiles](https://riaevangelist.github.io/node-ipc/profiles/), [Parsers](https://riaevangelist.github.io/node-ipc/parsers/), and [Security](https://riaevangelist.github.io/node-ipc/security/) before choosing a network-facing configuration.
#### Rust
The paired Rust crate requires Rust 1.85 or newer and has no runtime or build
dependencies. Its sole development dependency is exact `vanilla-test 2.1.0`.
```rust
use node_ipc::{tcp, CodecConfig, Connection, Event};
fn main() -> node_ipc::Result<()> {
let stream = tcp::connect(("127.0.0.1", 9763))?;
let mut connection = Connection::new(stream, CodecConfig::fast())?;
connection.send(&Event::new("app.message", "hello"))?;
Ok(())
}
```
Rust supplies TCP, UDP, Unix-domain sockets, Windows named pipes, raw bytes,
and the Fast, Guarded, and Assured codecs. Applications supply their own
verified TLS stream; the crate does not choose or reimplement cryptography.
See the [Rust engineer guide](https://riaevangelist.github.io/node-ipc/rust/)
and [native examples](https://github.com/RIAEvangelist/node-ipc/tree/main/rust/node-ipc/examples).
#### C#
The aligned C# package targets .NET 8, has no NuGet dependencies, and mirrors
the JavaScript facade: `IPCModule`, `config`, `of`, `server`, `serve*`,
`connect*`, event subscriptions, targeted `emit`, and `broadcast`. It supplies
async TCP, TLS, UDP4/UDP6, Unix-domain sockets, Windows named pipes, Raw, Fast,
Guarded, Assured, reconnect, and sync request queues.
```csharp
using NodeIpc;
await using var ipc = new IPCModule();
ipc.config.silent = true;
var client = ipc.connectToNet("service", "127.0.0.1", 9763)!;
await client.waitForConnectAsync();
await client.emitAsync("app.message", new { text = "hello" });
```
See the [C# package guide](https://github.com/RIAEvangelist/node-ipc/tree/main/csharp/node-ipc)
and [native examples](https://github.com/RIAEvangelist/node-ipc/tree/main/csharp/node-ipc/examples).
#### Use
ESM: `import ipc from 'node-ipc';`
CommonJS: `const ipc = require('node-ipc').default;`
CommonJS loading uses Node.js 22.13+'s native [`require(esm)` support](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require).
#### NPM Stats

@@ -39,10 +121,9 @@

Code Coverage Info :
![lcov node-ipc](/coverage/lcov.svg)
Run `npm run coverage` to host a local version of the coverage report on [localhost:8080](http://localhost:8080) This is the same format as Istanbul and NYC. It should be very familiar.
Run `npm run coverage` to host a local version of the coverage report on [127.0.0.1:8080](http://127.0.0.1:8080).
Testing done with [vanilla-test](https://github.com/RIAEvangelist/vanilla-test)
`vanilla-test` integrates with [c8](https://github.com/bcoe/c8) for native ESM coverage without the need to transpile your code. At the time of writing, this is the only way to natively test ESM, and it is amazing!
`vanilla-test` provides native V8 coverage for the ESM test suite without transpilation or bundling.
Package details websites :
* [GitHub.io site](http://riaevangelist.github.io/node-ipc/ "node-ipc documentation"). A prettier version of this site.
* [GitHub.io site](https://riaevangelist.github.io/node-ipc/ "node-ipc documentation"). Engineer documentation and tracked evidence.
* [NPM Module](https://www.npmjs.org/package/node-ipc "node-ipc npm module"). The npm page for the node-ipc module.

@@ -52,12 +133,58 @@

#### Older versions of node
#### Testing
the latest versions of `node-ipc` may work with the --harmony flag. Officially though, we support node v4 and newer with es5 and es6
`npm test` runs 195 Node correctness cases, native V8 coverage, both module
loaders, installed-package smoke, and benchmark validation. Reports are written
to `coverage/node/`.
#### Testing
`cargo test --manifest-path rust/node-ipc/Cargo.toml --all-targets` runs the 38
Rust-native VanillaTest cases. `node rust/node-ipc/interop/vanilla-test.js` runs
the separate two-direction Node/Rust interoperability gate.
` npm test ` will run the jasmine tests with istanbul for node-ipc and generate a coverage report in the spec folder.
`dotnet run --project csharp/node-ipc/tests/NodeIpc.Tests -c Release` runs the
exact C# native case inventory. `node csharp/node-ipc/interop/vanilla-test.js`
runs the separate two-direction Node/C# interoperability gate, and
`pwsh -File csharp/node-ipc/package-smoke.ps1` validates the NuGet boundary.
You may want to install jasmine and istanbul globally with ` sudo npm install -g jasmine istanbul `
`npm run test:behavioral` runs the shared black-box Fast TCP transcript across
all nine JavaScript, Rust, and C# server/client pairings. Seven pipelined
payload-shape and ordering cases must pass before a separate finish handshake
and two-sided clean stream boundary in every pair, including both Rust/C#
directions. Each native encoder also has to match one canonical Fast frame byte
for byte. This gate makes no performance assertions; the deeper
language-specific profile and transport checks remain in their native suites.
The same command adds 12 raw fault-injection cases: each language, in both
client and server roles, must reject complete and incomplete frames after the
finish boundary. Together with the nine positive pairings, the behavioral gate
contains 21 cases.
#### Performance evidence
![Tracked node-ipc profile benchmark chart](https://riaevangelist.github.io/node-ipc/assets/node-ipc-benchmark.svg)
The chart is generated from tracked, clean profile runs. Results stay separated by operating system, architecture, Node version, compiler, and commit; Assured remains pending until comparable mTLS evidence passes the same gates. See the [benchmark overview](https://riaevangelist.github.io/node-ipc/benchmarks/), [profile results](https://riaevangelist.github.io/node-ipc/benchmarks/profiles/), [resource results](https://riaevangelist.github.io/node-ipc/benchmarks/resources/), [methodology](https://riaevangelist.github.io/node-ipc/benchmarks/methodology/), and [run records](https://riaevangelist.github.io/node-ipc/benchmarks/runs/).
##### Version 12 versus tracked transport cohorts
![Paired node-ipc v12.0.0 and v14.0.0 million-message transport timings on Linux, macOS, and Windows](https://riaevangelist.github.io/node-ipc/assets/node-ipc-transport-comparison.svg)
The accepted `2692d32` CI cohort reports median time for 1,000,000 completed messages through native local IPC, TCP, TLS, UDP4, and UDP6 on Windows, macOS, and Linux with Node.js 22.13.0 and 24.18.1. v14.0.0 was faster than v12.0.0 in all 30 exact environment/transport pairs, with paired median speedups from 1.14× to 4.96×. Local IPC, TCP, and TLS use the Node byte reflector; UDP4 and UDP6 use the standard-C exact-count reflector. Both versions use the same oracle within every pair, and C-oracle source, binary, compiler, flags, target provenance, exact counts, and cleanup are retained. TLS is an encryption-only throughput lane with peer verification disabled and its handshake outside timing. Hosted results remain grouped by operating system, Node version, and transport; they are directional snapshots, not a universal ranking. See the [transport comparison](https://riaevangelist.github.io/node-ipc/benchmarks/transports/), [raw manifest](https://riaevangelist.github.io/node-ipc/data/transport-benchmarks/index.json), and [accepted workflow run](https://github.com/RIAEvangelist/node-ipc/actions/runs/32623449214).
##### Node.js and Rust TCP
![Node.js and Rust median milliseconds per one million validated TCP round trips on Linux, macOS, and Windows](https://riaevangelist.github.io/node-ipc/assets/node-ipc-rust-benchmark.svg)
The accepted `2692d32` hosted-runner batch used Node.js 24.18.1 and Rust 1.85.0.
Fixed lane order is Node→Node / Node→Rust / Rust→Node / Rust→Rust: Linux measured
10,312 / 9,317 / 16,816 / 12,478 ms, macOS 7,817 / 7,368 / 8,165 / 5,596 ms,
and Windows 12,609 / 15,231 / 23,186 / 13,070 ms per 1,000,000 validated round
trips. One round trip is two application frames. Each full sample also uses
100,000 warm-up round trips, a 64-byte payload, 64 maximum requests in flight,
release-built Rust, fresh peers, a fresh loopback port, and exact cleanup.
Hosted platforms have different hardware; this is fixed-order evidence, not a
cross-platform ranking. See the [engineer benchmark page](https://riaevangelist.github.io/node-ipc/benchmarks/rust/),
[raw manifest](https://riaevangelist.github.io/node-ipc/data/rust-benchmarks/index.json),
or run `npm run benchmark:rust:quick` for a non-publishable four-lane smoke.
----

@@ -83,4 +210,4 @@ #### Contents

5. [Raw Buffers, Real Time and / or Binary Sockets](#raw-buffer-or-binary-sockets)
7. [Working with TLS/SSL Socket Servers & Clients](https://github.com/RIAEvangelist/node-ipc/tree/master/example/TLSSocket)
8. [Node Code Examples](https://github.com/RIAEvangelist/node-ipc/tree/master/example)
7. [Working with TLS/SSL Socket Servers & Clients](https://github.com/RIAEvangelist/node-ipc/tree/main/example/TLSSocket)
8. [Node Code Examples](https://github.com/RIAEvangelist/node-ipc/tree/main/example)

@@ -93,6 +220,6 @@

|-----------|-----------|-----------|
|Unix Socket or Windows Socket| Stable | Gives Linux, Mac, and Windows lightning fast communication and avoids the network card to reduce overhead and latency. [Local Unix and Windows Socket examples ](https://github.com/RIAEvangelist/node-ipc/tree/master/example/unixWindowsSocket/ "Unix and Windows Socket Node IPC examples") |
|TCP Socket | Stable | Gives the most reliable communication across the network. Can be used for local IPC as well, but is slower than #1's Unix Socket Implementation because TCP sockets go through the network card while Unix Sockets and Windows Sockets do not. [Local or remote network TCP Socket examples ](https://github.com/RIAEvangelist/node-ipc/tree/master/example/TCPSocket/ "TCP Socket Node IPC examples") |
|TLS Socket | Stable | Configurable and secure network socket over SSL. Equivalent to https. [TLS/SSL documentation](https://github.com/RIAEvangelist/node-ipc/tree/master/example/TLSSocket) |
|UDP Sockets| Stable | Gives the **fastest network communication**. UDP is less reliable but much faster than TCP. It is best used for streaming non critical data like sound, video, or multiplayer game data as it can drop packets depending on network connectivity and other factors. UDP can be used for local IPC as well, but is slower than #1's Unix Socket or Windows Socket Implementation because UDP sockets go through the network card while Unix and Windows Sockets do not. [Local or remote network UDP Socket examples ](https://github.com/RIAEvangelist/node-ipc/tree/master/example/UDPSocket/ "UDP Socket Node IPC examples") |
|Unix socket or Windows named pipe| Stable | Local IPC without the TCP/IP stack. Measure it against TCP on the target system rather than assuming a fixed latency difference. [Local Unix socket and Windows named-pipe examples](https://github.com/RIAEvangelist/node-ipc/tree/main/example/unixWindowsSocket/ "Unix socket and Windows named-pipe examples") |
|TCP Socket | Stable | Reliable ordered byte streams for local loopback or remote networks. [Local or remote TCP examples](https://github.com/RIAEvangelist/node-ipc/tree/main/example/TCPSocket/ "TCP examples") |
|TLS Socket | Stable | Encrypted network socket. It is secure only when certificate identities are verified; use mTLS or application authentication when clients must be identified. [TLS documentation](https://github.com/RIAEvangelist/node-ipc/tree/main/example/TLSSocket) |
|UDP Sockets| Stable | Unordered datagrams for workloads that can own loss, duplication, reordering, and authentication. Compare measured latency and throughput on the target network before choosing it over TCP or local IPC. [Local or remote UDP examples](https://github.com/RIAEvangelist/node-ipc/tree/main/example/UDPSocket/ "UDP examples") |

@@ -117,10 +244,15 @@ | OS | Supported Sockets |

appspace : 'app.',
socketRoot : '/tmp/',
socketRoot : '<secure per-user runtime directory>/',
id : os.hostname(),
networkHost : 'localhost', //should resolve to 127.0.0.1 or ::1 see the table below related to this
networkHost : '127.0.0.1', //or ::1 when IPv6 is selected
networkPort : 8000,
IPType : '<detected IPv4 or IPv6>',
tls : false,
readableAll : false,
writableAll : false,
secureSocketRoot: true,
encoding : 'utf8',
rawBuffer : false,
parser : 'fast',
identifyPeer : false,
delimiter : '\f',

@@ -132,8 +264,15 @@ sync : false,

logger : console.log,
logPayloads : false,
maxConnections : 100,
maxMessageSize : 1024 * 1024,
maxPendingBytes : 8 * 1024 * 1024,
maxEventNameLength: 256,
messageTimeout : 30000,
allowReservedEvents: false,
allowedEvents : false,
retry : 500,
maxRetries : false,
maxRetries : Infinity,
stopRetrying : false,
unlink : true,
interfaces : {
interface : {
localAddress: false,

@@ -152,3 +291,3 @@ localPort : false,

| appspace | used for Unix Socket (Unix Domain Socket) namespacing. If not set specifically, the Unix Domain Socket will combine the socketRoot, appspace, and id to form the Unix Socket Path for creation or binding. This is available in case you have many apps running on your system, you may have several sockets with the same id, but if you change the appspace, you will still have app specic unique sockets.|
| socketRoot| the directory in which to create or bind to a Unix Socket |
| socketRoot| owner-only directory in which to create or bind a Unix Socket. On Unix the default is `$XDG_RUNTIME_DIR/node-ipc` when available, otherwise an owner-only `node-ipc-<uid>` directory below the OS temporary directory. Windows uses a per-user logical pipe prefix. The configured root is created and verified as owner-only by default. |
| id | the id of this socket or service |

@@ -159,5 +298,8 @@ | networkHost| the local or remote host on which TCP, TLS or UDP Sockets should connect |

| writableAll| makes the pipe writable for all users including windows services |
| encoding | the default encoding for data sent on sockets. Mostly used if rawBuffer is set to true. Valid values are : ` ascii` ` utf8 ` ` utf16le` ` ucs2` ` base64` ` hex ` . |
| rawBuffer| if true, data will be sent and received as a raw node ` Buffer ` __NOT__ an ` Object ` as JSON. This is great for Binary or hex IPC, and communicating with other processes in languages like C and C++ |
| delimiter| the delimiter at the end of each data packet. |
| secureSocketRoot | create and verify an owner-only Unix socket root. Defaults to `true` and is required by Assured. For other profiles, disabling it transfers directory ownership and permission checks to the application. An Assured local server must bind directly inside that root and is Unix-only; clients must verify endpoint ownership. On Windows use Assured mutual TLS or an application-owned named-pipe ACL outside the built-in profile. |
| encoding | encoding for non-Buffer Raw writes. Built-in framed profiles use UTF-8 so both wire directions remain symmetric. Custom parsers should return a `Buffer` when they own another wire encoding. |
| rawBuffer| compatibility switch for the `raw` profile. When `true`, node-ipc performs no framing, JSON parsing, or message validation; incoming `Buffer` values are delivered through `data`. The caller owns the complete wire protocol and its security. |
| parser | parser profile or custom parser. Defaults to `fast`; accepts `raw`, `fast`, `guarded`, `assured`, a parser class, or a parser object. Selection happens once for each new client or server. |
| identifyPeer | legacy server behavior that copies a received payload's `data.id` onto the socket. Defaults to `false` so Fast does not inspect every payload. Selected once when the server is created; never treat this caller-supplied value as authenticated identity. |
| delimiter| frame terminator used by the `fast`, `guarded`, and `assured` profiles. |
| sync | synchronous requests. Clients will not send new requests until the server answers. |

@@ -168,9 +310,31 @@ | silent | turn on/off logging default is false which means logging is on |

| logger | the function which receives the output from ipc.log; should take a single string argument |
| maxConnections| this is the max number of connections allowed to a socket. It is currently only being set on Unix Sockets. Other Socket types are using the system defaults. |
| logPayloads | include application payloads in automatic transport logs. Defaults to `false`. Do not pass keys, passphrases, tokens, or other secrets to `ipc.log`; application-supplied log values are not redacted. |
| maxConnections| maximum number of concurrent connections accepted by a stream socket. Defaults to 100. |
| maxMessageSize | `guarded` and `assured` maximum framed-message size in bytes. Defaults to 1 MiB. Fast and Raw do not read this option. |
| maxPendingBytes | `guarded` and `assured` maximum bytes queued for a stream socket write. Defaults to 8 MiB; exceeding it closes that connection. Fast and Raw write directly. |
| maxEventNameLength | `guarded` and `assured` maximum accepted wire event-name length. Defaults to 256 characters. |
| messageTimeout | `guarded` and `assured` time allowed for an incomplete stream frame. Defaults to 30000 ms; set to `0` to disable the timer. |
| allowReservedEvents | `guarded` compatibility escape hatch for lifecycle names. Defaults to `false`. Assured always rejects reserved names. |
| allowedEvents | required non-empty `Array` or `Set` of event names for `assured`. The allow-list applies to sent and received events. Defaults to `false` for the other profiles. |
| retry | this is the time in milliseconds a client will wait before trying to reconnect to a server if the connection is lost. This does not effect UDP sockets since they do not have a client server relationship like Unix Sockets and TCP Sockets. |
| maxRetries | if set, it represents the maximum number of retries after each disconnect before giving up and completely killing a specific connection |
| stopRetrying| Defaults to false meaning clients will continue to retry to connect to servers indefinitely at the retry interval. If set to any number the client will stop retrying when that number is exceeded after each disconnect. If set to true in real time it will immediately stop trying to connect regardless of maxRetries. If set to 0, the client will ***NOT*** try to reconnect. |
| stopRetrying| Boolean switch. `true` stops scheduled and future reconnect attempts; `false` permits retries up to `maxRetries`. Set `maxRetries` to `0` to disable reconnects. |
| unlink| Defaults to true meaning that the module will take care of deleting the IPC socket prior to startup. If you use `node-ipc` in a clustered environment where there will be multiple listeners on the same socket, you must set this to `false` and then take care of deleting the socket in your own code. |
| interfaces| primarily used when specifying which interface a client should connect through. see the [socket.connect documentation in the node.js api](https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener) |
| interface| primarily used when specifying which interface a client should connect through. see the [socket.connect documentation in the node.js api](https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener) |
| IPType | detected IP family used to choose the initial loopback host. |
| tls | TLS options object or `false`. Assured network clients require a key, certificate, trusted CA, and `rejectUnauthorized:true`; servers also require a trusted client CA, `requestCert:true`, and `rejectUnauthorized:true`. |
Security boundaries:
- `fast` is the default because the trusted hot path stays direct. It contains malformed JSON, but it does not enforce message size, event-name, reserved-name, timeout, allow-list, or pending-write limits. Use `guarded` or `assured` when peers are not fully trusted.
- Parser controls validate the event envelope, not the application payload. Validate payload type, shape, identity, authorization, and replay rules in the application.
- TCP and UDP provide neither authentication nor confidentiality. Any service bound beyond loopback must authenticate and authorize messages at the application layer, or use mutually authenticated TLS. Server-authenticated TLS alone does not identify clients.
- TLS servers must supply an explicit `key` and `cert`, or the existing `private` and `public` file-path aliases. There is no bundled certificate fallback. Keep private keys outside the package and source tree.
- `rejectUnauthorized: false` disables certificate identity verification and is vulnerable to man-in-the-middle attacks. Use it only for isolated local development, never on an external or untrusted network.
- Unix socket permissions are a boundary, not message authentication. Keep the default owner-only socket root or provide an equally restricted directory; do not place privileged sockets directly in a shared temporary directory.
The official `node-ipc/parsers/message` export keeps `js-message` ecosystem compatibility as an explicit opt-in parser. It maps malformed envelopes to an `error` message and is not a hardened decoder. Use Guarded or Assured for node-ipc protocol controls, or provide a custom parser that implements your required policy.
For the complete upgrade contract, see [MIGRATION.md](./MIGRATION.md).
----

@@ -203,3 +367,3 @@

Used for connecting as a client to local Unix Sockets and Windows Sockets. ***This is the fastest way for processes on the same machine to communicate*** because it bypasses the network card which TCP and UDP must both use.
Used for connecting as a client to local Unix sockets and Windows named pipes. This avoids IP framing and routing, but the fastest same-machine transport depends on the operating system, workload, and message shape, so compare it with loopback TCP on the target system.

@@ -269,5 +433,5 @@ | variable | required | definition |

Used to connect as a client to a TCP or [TLS socket](https://github.com/RIAEvangelist/node-ipc/tree/master/example/TLSSocket) via the network card. This can be local or remote, if local, it is recommended that you use the Unix and Windows Socket Implementaion of `connectTo` instead as it is much faster since it avoids the network card altogether.
Used to connect as a client to a TCP or [TLS socket](https://github.com/RIAEvangelist/node-ipc/tree/main/example/TLSSocket) over loopback or a remote IP network. For same-machine peers, compare this path with `connectTo`; the better choice depends on the target system and workload.
For TLS and SSL Sockets see the [node-ipc TLS and SSL docs](https://github.com/RIAEvangelist/node-ipc/tree/master/example/TLSSocket). They have a few additional requirements, and things to know about and so have their own doc.
For TLS and SSL Sockets see the [node-ipc TLS and SSL docs](https://github.com/RIAEvangelist/node-ipc/tree/main/example/TLSSocket). They have a few additional requirements, and things to know about and so have their own doc.

@@ -382,3 +546,3 @@ | variable | required | definition |

ipc.serve(
'/tmp/myapp.myservice'
ipc.config.socketRoot+'myapp.myservice'
);

@@ -393,3 +557,3 @@

ipc.serve(
'/tmp/myapp.myservice',
ipc.config.socketRoot+'myapp.myservice',
function(){...}

@@ -407,6 +571,8 @@ );

Binding to a non-loopback interface exposes the service to the network. Use application authentication and authorization for TCP/UDP, or mutually authenticated TLS when both peers must have cryptographic identities.
| variable | required | definition |
|----------|----------|------------|
| host | optional | If not specified this defaults to the first address in os.networkInterfaces(). For TCP, TLS & UDP servers this is most likely going to be 127.0.0.1 or ::1 |
| host | optional | If not specified this defaults to `ipc.config.networkHost`, which is loopback (`127.0.0.1` or `::1`). An explicit non-loopback host creates an external network boundary. |
| port | optional | The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified |

@@ -520,2 +686,4 @@ | UDPType | optional | If set this will create the server as a UDP socket. 'udp4' or 'udp6' are valid values. This defaults to not being set. When using udp6 make sure to specify a valid IPv6 host, like ` ::1 ` |

The Guarded and Assured profiles reject the lifecycle names `start`, `connect`, `disconnect`, `destroy`, `close`, `socket.disconnected`, `error`, and `data`, plus names inherited from `Object.prototype`. Guarded can restore lifecycle-name compatibility with `ipc.config.allowReservedEvents=true`; Assured cannot. The default Fast profile does not perform either name check, so use it only with trusted peers.
### Multiple IPC Instances

@@ -529,12 +697,6 @@

const ipc=new RawIPC;
const someOtherExplicitIPC=new RawIPC;
const ipc=new IPCModule;
const someOtherExplicitIPC=new IPCModule;
//OR
const ipc=from 'node-ipc');
const someOtherExplicitIPC=new ipc.IPC;
//setting explicit configs

@@ -557,3 +719,3 @@

### Basic Examples
You can find [Advanced Examples](https://github.com/RIAEvangelist/node-ipc/tree/master/example) in the examples folder. In the examples you will find more complex demos including multi client examples.
You can find [Advanced Examples](https://github.com/RIAEvangelist/node-ipc/tree/main/example) in the examples folder. In the examples you will find more complex demos including multi client examples.

@@ -850,3 +1012,3 @@ #### Server for Unix Sockets, Windows Sockets & TCP Sockets

const socketPath='/tmp/ipc.sock';
const socketPath=ipc.config.socketRoot+'ipc.sock';

@@ -889,3 +1051,3 @@ ipc.config.unlink = false;

const socketPath = '/tmp/ipc.sock';
const socketPath = ipc.config.socketRoot+'ipc.sock';

@@ -922,4 +1084,4 @@ //loop forever so you can see the pid of the cluster sever change in the logs

#### Licensed under MIT license
See the [MIT license](https://github.com/RIAEvangelist/node-ipc/blob/master/license) file.
See the [MIT license](https://github.com/RIAEvangelist/node-ipc/blob/main/licence) file.
I'm sorry.

@@ -5,12 +5,8 @@

import Server from '../dao/socketServer.js';
import util from 'util';
import util from 'node:util';
class IPC{
constructor(){
}
//public members
config=new Defaults;
of={};
of=Object.create(null);
server=false;

@@ -90,4 +86,6 @@

this.of[id].explicitlyDisconnected=true;
clearTimeout(this.of[id].retryTimer);
this.of[id].retryTimer=false;
this.of[id].off('*','*');
this.of[id].reset();
if(this.of[id].socket){

@@ -235,3 +233,3 @@ if(this.of[id].socket.destroy){

'ipc.config.socketRoot + ipc.config.appspace + id',
(this.config.socketRoot+this.config.appspace+id).data
this.config.socketRoot+this.config.appspace+id
);

@@ -251,2 +249,5 @@ path=this.config.socketRoot+this.config.appspace+id;

}
this.of[id].explicitlyDisconnected=true;
clearTimeout(this.of[id].retryTimer);
this.of[id].retryTimer=false;
this.of[id].socket.destroy();

@@ -305,6 +306,2 @@ }

if(typeof callback == 'string'){
UDPType=callback;
callback=false;
}
if(!callback){

@@ -325,2 +322,5 @@ callback=emptyCallback;

}
this.of[id].explicitlyDisconnected=true;
clearTimeout(this.of[id].retryTimer);
this.of[id].retryTimer=false;
this.of[id].socket.destroy();

@@ -327,0 +327,0 @@ }

coverage/**/* linguist-generated=true
# These are supported funding model platforms
github: RIAEvangelist
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
node_version:
- 14.x
- 16.x
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
async function delay(ms=100) {
return new Promise(
resolve => {
setTimeout(resolve, ms);
}
);
}
export {
delay as default,
delay
}
import lcov2badge from 'lcov2badge';
import {writeFileSync} from 'fs';
lcov2badge.badge(
'./coverage/lcov.info',
function(err, svgBadge){
if (err) throw err;
writeFileSync('./coverage/lcov.svg', svgBadge);
}
);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __require = typeof require !== "undefined" ? require : (x) => {
throw new Error('Dynamic require of "' + x + '" is not supported');
};
var __commonJS = (cb, mod) => function __require2() {
return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __reExport = (target, module2, desc) => {
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
}
return target;
};
var __toModule = (module2) => {
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
// node_modules/js-message/Message.js
var require_Message = __commonJS({
"node_modules/js-message/Message.js"(exports, module2) {
function Message3() {
Object.defineProperties(this, {
data: {
enumerable: true,
get: getData,
set: setData
},
type: {
enumerable: true,
get: getType,
set: setType
},
load: {
enumerable: true,
writable: false,
value: parse
},
JSON: {
enumerable: true,
get: getJSON
}
});
var type = "";
var data = {};
function getType() {
return type;
}
function getData() {
return data;
}
function getJSON() {
return JSON.stringify({
type,
data
});
}
function setType(value) {
type = value;
}
function setData(value) {
data = value;
}
function parse(message) {
try {
var message = JSON.parse(message);
type = message.type;
data = message.data;
} catch (err) {
var badMessage = message;
type = "error", data = {
message: "Invalid JSON response format",
err,
response: badMessage
};
}
}
}
module2.exports = Message3;
}
});
// node_modules/js-queue/queue.js
var require_queue = __commonJS({
"node_modules/js-queue/queue.js"(exports, module2) {
function Queue2(asStack) {
Object.defineProperties(this, {
add: {
enumerable: true,
writable: false,
value: addToQueue
},
next: {
enumerable: true,
writable: false,
value: run
},
clear: {
enumerable: true,
writable: false,
value: clearQueue
},
contents: {
enumerable: false,
get: getQueue,
set: setQueue
},
autoRun: {
enumerable: true,
writable: true,
value: true
},
stop: {
enumerable: true,
writable: true,
value: false
}
});
var queue = [];
var running = false;
var stop = false;
function clearQueue() {
queue = [];
return queue;
}
function getQueue() {
return queue;
}
function setQueue(val) {
queue = val;
return queue;
}
function addToQueue() {
for (var i in arguments) {
queue.push(arguments[i]);
}
if (!running && !this.stop && this.autoRun) {
this.next();
}
}
function run() {
running = true;
if (queue.length < 1 || this.stop) {
running = false;
return;
}
queue.shift().bind(this)();
}
}
module2.exports = Queue2;
}
});
// node-ipc.js
__export(exports, {
IPCModule: () => IPCModule,
default: () => singleton
});
// entities/Defaults.js
var import_os = __toModule(require("os"));
var Defaults = class {
constructor() {
__publicField(this, "appspace", "app.");
__publicField(this, "socketRoot", "/tmp/");
__publicField(this, "id", import_os.default.hostname());
__publicField(this, "encoding", "utf8");
__publicField(this, "rawBuffer", false);
__publicField(this, "sync", false);
__publicField(this, "unlink", true);
__publicField(this, "delimiter", "\f");
__publicField(this, "silent", false);
__publicField(this, "logDepth", 5);
__publicField(this, "logInColor", true);
__publicField(this, "logger", console.log.bind(console));
__publicField(this, "maxConnections", 100);
__publicField(this, "retry", 500);
__publicField(this, "maxRetries", Infinity);
__publicField(this, "stopRetrying", false);
__publicField(this, "IPType", getIPType());
__publicField(this, "tls", false);
__publicField(this, "networkHost", this.IPType == "IPv6" ? "::1" : "127.0.0.1");
__publicField(this, "networkPort", 8e3);
__publicField(this, "readableAll", false);
__publicField(this, "writableAll", false);
__publicField(this, "interface", {
localAddress: false,
localPort: false,
family: false,
hints: false,
lookup: false
});
}
};
function getIPType() {
const networkInterfaces = import_os.default.networkInterfaces();
let IPType = "";
if (networkInterfaces && Array.isArray(networkInterfaces) && networkInterfaces.length > 0) {
IPType = networkInterfaces[Object.keys(networkInterfaces)[0]][0].family;
}
return IPType;
}
// dao/client.js
var import_net = __toModule(require("net"));
var import_tls = __toModule(require("tls"));
// entities/EventParser.js
var Parser = class {
constructor(config) {
if (!config) {
config = new Defaults();
}
this.delimiter = config.delimiter;
}
format(message) {
if (!message.data && message.data !== false && message.data !== 0) {
message.data = {};
}
if (message.data["_maxListeners"]) {
message.data = {};
}
message = message.JSON + this.delimiter;
return message;
}
parse(data) {
let events = data.split(this.delimiter);
events.pop();
return events;
}
};
// dao/client.js
var import_js_message = __toModule(require_Message());
var import_fs = __toModule(require("fs"));
var import_js_queue = __toModule(require_queue());
// node_modules/strong-type/index.js
var Fake = class {
};
var FakeCore = class {
};
var Is = class {
constructor(strict = true) {
this.strict = strict;
}
throw(valueType, expectedType) {
let err = new TypeError();
err.message = `expected type of ${valueType} to be ${expectedType}`;
if (!this.strict) {
return false;
}
throw err;
}
typeCheck(value, type) {
if (typeof value === type) {
return true;
}
return this.throw(typeof value, type);
}
instanceCheck(value = new Fake(), constructor = FakeCore) {
if (value instanceof constructor) {
return true;
}
return this.throw(typeof value, constructor.name);
}
symbolStringCheck(value, type) {
if (Object.prototype.toString.call(value) == `[object ${type}]`) {
return true;
}
return this.throw(Object.prototype.toString.call(value), `[object ${type}]`);
}
compare(value, targetValue, typeName) {
if (value == targetValue) {
return true;
}
return this.throw(typeof value, typeName);
}
defined(value) {
const weakIs = new Is(false);
if (weakIs.undefined(value)) {
return this.throw("undefined", "defined");
}
return true;
}
any(value) {
return this.defined(value);
}
exists(value) {
return this.defined(value);
}
union(value, typesString) {
const types = typesString.split("|");
const weakIs = new Is(false);
let pass = false;
let type = "undefined";
for (type of types) {
try {
if (weakIs[type](value)) {
pass = true;
break;
}
} catch (err) {
return this.throw(type, "a method available on strong-type");
}
}
if (pass) {
return this[type](value);
}
return this.throw(typeof value, types.join("|"));
}
finite(value) {
if (isFinite(value)) {
return true;
}
return this.throw(typeof value, "finite");
}
NaN(value) {
if (!this.number(value)) {
return this.number(value);
}
if (isNaN(value)) {
return true;
}
return this.throw(typeof value, "NaN");
}
null(value) {
return this.compare(value, null, "null");
}
array(value) {
return this.instanceCheck(value, Array);
}
boolean(value) {
return this.typeCheck(value, "boolean");
}
bigInt(value) {
return this.typeCheck(value, "bigint");
}
date(value) {
return this.instanceCheck(value, Date);
}
generator(value) {
return this.symbolStringCheck(value, "Generator");
}
asyncGenerator(value) {
return this.symbolStringCheck(value, "AsyncGenerator");
}
globalThis(value) {
return this.compare(value, globalThis, "explicitly globalThis, not window, global nor self");
}
infinity(value) {
return this.compare(value, Infinity, "Infinity");
}
map(value) {
return this.instanceCheck(value, Map);
}
weakMap(value) {
return this.instanceCheck(value, WeakMap);
}
number(value) {
return this.typeCheck(value, "number");
}
object(value) {
return this.typeCheck(value, "object");
}
promise(value) {
return this.instanceCheck(value, Promise);
}
regExp(value) {
return this.instanceCheck(value, RegExp);
}
undefined(value) {
return this.typeCheck(value, "undefined");
}
set(value) {
return this.instanceCheck(value, Set);
}
weakSet(value) {
return this.instanceCheck(value, WeakSet);
}
string(value) {
return this.typeCheck(value, "string");
}
symbol(value) {
return this.typeCheck(value, "symbol");
}
function(value) {
return this.typeCheck(value, "function");
}
asyncFunction(value) {
return this.symbolStringCheck(value, "AsyncFunction");
}
generatorFunction(value) {
return this.symbolStringCheck(value, "GeneratorFunction");
}
asyncGeneratorFunction(value) {
return this.symbolStringCheck(value, "AsyncGeneratorFunction");
}
error(value) {
return this.instanceCheck(value, Error);
}
evalError(value) {
return this.instanceCheck(value, EvalError);
}
rangeError(value) {
return this.instanceCheck(value, RangeError);
}
referenceError(value) {
return this.instanceCheck(value, ReferenceError);
}
syntaxError(value) {
return this.instanceCheck(value, SyntaxError);
}
typeError(value) {
return this.instanceCheck(value, TypeError);
}
URIError(value) {
return this.instanceCheck(value, URIError);
}
bigInt64Array(value) {
return this.instanceCheck(value, BigInt64Array);
}
bigUint64Array(value) {
return this.instanceCheck(value, BigUint64Array);
}
float32Array(value) {
return this.instanceCheck(value, Float32Array);
}
float64Array(value) {
return this.instanceCheck(value, Float64Array);
}
int8Array(value) {
return this.instanceCheck(value, Int8Array);
}
int16Array(value) {
return this.instanceCheck(value, Int16Array);
}
int32Array(value) {
return this.instanceCheck(value, Int32Array);
}
uint8Array(value) {
return this.instanceCheck(value, Uint8Array);
}
uint8ClampedArray(value) {
return this.instanceCheck(value, Uint8ClampedArray);
}
uint16Array(value) {
return this.instanceCheck(value, Uint16Array);
}
uint32Array(value) {
return this.instanceCheck(value, Uint32Array);
}
arrayBuffer(value) {
return this.instanceCheck(value, ArrayBuffer);
}
dataView(value) {
return this.instanceCheck(value, DataView);
}
sharedArrayBuffer(value) {
return this.instanceCheck(value, function() {
try {
return SharedArrayBuffer;
} catch (e) {
return Fake;
}
}());
}
intlDateTimeFormat(value) {
return this.instanceCheck(value, Intl.DateTimeFormat);
}
intlCollator(value) {
return this.instanceCheck(value, Intl.Collator);
}
intlDisplayNames(value) {
return this.instanceCheck(value, Intl.DisplayNames);
}
intlListFormat(value) {
return this.instanceCheck(value, Intl.ListFormat);
}
intlLocale(value) {
return this.instanceCheck(value, Intl.Locale);
}
intlNumberFormat(value) {
return this.instanceCheck(value, Intl.NumberFormat);
}
intlPluralRules(value) {
return this.instanceCheck(value, Intl.PluralRules);
}
intlRelativeTimeFormat(value) {
return this.instanceCheck(value, Intl.RelativeTimeFormat);
}
intlRelativeTimeFormat(value) {
return this.instanceCheck(value, Intl.RelativeTimeFormat);
}
finalizationRegistry(value) {
return this.instanceCheck(value, FinalizationRegistry);
}
weakRef(value) {
return this.instanceCheck(value, WeakRef);
}
};
// node_modules/event-pubsub/index.js
var is = new Is();
var _handleOnce, _all, _once, _events;
var EventPubSub = class {
constructor() {
__privateAdd(this, _handleOnce, (type, handlers, ...args) => {
is.string(type);
is.array(handlers);
const deleteOnceHandled = [];
for (let handler of handlers) {
handler(...args);
if (handler[__privateGet(this, _once)]) {
deleteOnceHandled.push(handler);
}
}
for (let handler of deleteOnceHandled) {
this.off(type, handler);
}
});
__privateAdd(this, _all, Symbol.for("event-pubsub-all"));
__privateAdd(this, _once, Symbol.for("event-pubsub-once"));
__privateAdd(this, _events, {});
}
on(type, handler, once = false) {
is.string(type);
is.function(handler);
is.boolean(once);
if (type == "*") {
type = __privateGet(this, _all);
}
if (!__privateGet(this, _events)[type]) {
__privateGet(this, _events)[type] = [];
}
handler[__privateGet(this, _once)] = once;
__privateGet(this, _events)[type].push(handler);
return this;
}
once(type, handler) {
return this.on(type, handler, true);
}
off(type = "*", handler = "*") {
is.string(type);
if (type == __privateGet(this, _all).toString() || type == "*") {
type = __privateGet(this, _all);
}
if (!__privateGet(this, _events)[type]) {
return this;
}
if (handler == "*") {
delete __privateGet(this, _events)[type];
return this;
}
is.function(handler);
const handlers = __privateGet(this, _events)[type];
while (handlers.includes(handler)) {
handlers.splice(handlers.indexOf(handler), 1);
}
if (handlers.length < 1) {
delete __privateGet(this, _events)[type];
}
return this;
}
emit(type, ...args) {
is.string(type);
const globalHandlers = __privateGet(this, _events)[__privateGet(this, _all)] || [];
__privateGet(this, _handleOnce).call(this, __privateGet(this, _all).toString(), globalHandlers, type, ...args);
if (!__privateGet(this, _events)[type]) {
return this;
}
const handlers = __privateGet(this, _events)[type];
__privateGet(this, _handleOnce).call(this, type, handlers, ...args);
return this;
}
reset() {
this.off(__privateGet(this, _all).toString());
for (let type in __privateGet(this, _events)) {
this.off(type);
}
return this;
}
get list() {
return Object.assign({}, __privateGet(this, _events));
}
};
_handleOnce = new WeakMap();
_all = new WeakMap();
_once = new WeakMap();
_events = new WeakMap();
// dao/client.js
var eventParser = new Parser();
var Client = class extends EventPubSub {
constructor(config, log2) {
super();
__publicField(this, "Client", Client);
__publicField(this, "queue", new import_js_queue.default());
__publicField(this, "socket", false);
__publicField(this, "connect", connect);
__publicField(this, "emit", emit);
__publicField(this, "retriesRemaining", 0);
__publicField(this, "explicitlyDisconnected", false);
this.config = config;
this.log = log2;
this.publish = super.emit;
config.maxRetries ? this.retriesRemaining = config.maxRetries : 0;
eventParser = new Parser(this.config);
}
};
function emit(type, data) {
this.log("dispatching event to ", this.id, this.path, " : ", type, ",", data);
let message = new import_js_message.default();
message.type = type;
message.data = data;
if (this.config.rawBuffer) {
message = Buffer.from(type, this.config.encoding);
} else {
message = eventParser.format(message);
}
if (!this.config.sync) {
this.socket.write(message);
return;
}
this.queue.add(syncEmit.bind(this, message));
}
function syncEmit(message) {
this.log("dispatching event to ", this.id, this.path, " : ", message);
this.socket.write(message);
}
function connect() {
let client = this;
client.log("requested connection to ", client.id, client.path);
if (!this.path) {
client.log("\n\n######\nerror: ", client.id, " client has not specified socket path it wishes to connect to.");
return;
}
const options = {};
if (!client.port) {
client.log("Connecting client on Unix Socket :", client.path);
options.path = client.path;
if (process.platform === "win32" && !client.path.startsWith("\\\\.\\pipe\\")) {
options.path = options.path.replace(/^\//, "");
options.path = options.path.replace(/\//g, "-");
options.path = `\\\\.\\pipe\\${options.path}`;
}
client.socket = import_net.default.connect(options);
} else {
options.host = client.path;
options.port = client.port;
if (client.config.interface.localAddress) {
options.localAddress = client.config.interface.localAddress;
}
if (client.config.interface.localPort) {
options.localPort = client.config.interface.localPort;
}
if (client.config.interface.family) {
options.family = client.config.interface.family;
}
if (client.config.interface.hints) {
options.hints = client.config.interface.hints;
}
if (client.config.interface.lookup) {
options.lookup = client.config.interface.lookup;
}
if (!client.config.tls) {
client.log("Connecting client via TCP to", options);
client.socket = import_net.default.connect(options);
} else {
client.log("Connecting client via TLS to", client.path, client.port, client.config.tls);
if (client.config.tls.private) {
client.config.tls.key = import_fs.default.readFileSync(client.config.tls.private);
}
if (client.config.tls.public) {
client.config.tls.cert = import_fs.default.readFileSync(client.config.tls.public);
}
if (client.config.tls.trustedConnections) {
if (typeof client.config.tls.trustedConnections === "string") {
client.config.tls.trustedConnections = [client.config.tls.trustedConnections];
}
client.config.tls.ca = [];
for (let i = 0; i < client.config.tls.trustedConnections.length; i++) {
client.config.tls.ca.push(import_fs.default.readFileSync(client.config.tls.trustedConnections[i]));
}
}
Object.assign(client.config.tls, options);
client.socket = import_tls.default.connect(client.config.tls);
}
}
client.socket.setEncoding(this.config.encoding);
client.socket.on("error", function(err) {
client.log("\n\n######\nerror: ", err);
client.publish("error", err);
});
client.socket.on("connect", function connectionMade() {
client.publish("connect");
client.retriesRemaining = client.config.maxRetries;
client.log("retrying reset");
});
client.socket.on("close", function connectionClosed() {
client.log("connection closed", client.id, client.path, client.retriesRemaining, "tries remaining of", client.config.maxRetries);
if (client.config.stopRetrying || client.retriesRemaining < 1 || client.explicitlyDisconnected) {
client.publish("disconnect");
client.log(client.config.id, "exceeded connection rety amount of", " or stopRetrying flag set.");
client.socket.destroy();
client.publish("destroy");
client = void 0;
return;
}
setTimeout(function retryTimeout() {
if (client.explicitlyDisconnected) {
return;
}
client.retriesRemaining--;
client.connect();
}.bind(null, client), client.config.retry);
client.publish("disconnect");
});
client.socket.on("data", function(data) {
client.log("## received events ##");
if (client.config.rawBuffer) {
client.publish("data", Buffer.from(data, client.config.encoding));
if (!client.config.sync) {
return;
}
client.queue.next();
return;
}
if (!this.ipcBuffer) {
this.ipcBuffer = "";
}
data = this.ipcBuffer += data;
if (data.slice(-1) != eventParser.delimiter || data.indexOf(eventParser.delimiter) == -1) {
client.log("Messages are large, You may want to consider smaller messages.");
return;
}
this.ipcBuffer = "";
const events = eventParser.parse(data);
const eCount = events.length;
for (let i = 0; i < eCount; i++) {
let message = new import_js_message.default();
message.load(events[i]);
client.log("detected event", message.type, message.data);
client.publish(message.type, message.data);
}
if (!client.config.sync) {
return;
}
client.queue.next();
});
}
// dao/socketServer.js
var import_net2 = __toModule(require("net"));
var import_tls2 = __toModule(require("tls"));
var import_fs2 = __toModule(require("fs"));
var import_dgram = __toModule(require("dgram"));
var import_js_message2 = __toModule(require_Message());
var eventParser2 = new Parser();
var Server = class extends EventPubSub {
constructor(path, config, log2, port) {
super();
__publicField(this, "udp4", false);
__publicField(this, "udp6", false);
__publicField(this, "server", false);
__publicField(this, "sockets", []);
__publicField(this, "emit", emit2);
__publicField(this, "broadcast", broadcast);
this.config = config;
this.path = path;
this.port = port;
this.log = log2;
this.publish = super.emit;
eventParser2 = new Parser(this.config);
this.on("close", serverClosed.bind(this));
}
onStart(socket) {
this.publish("start", socket);
}
stop() {
this.server.close();
}
start() {
if (!this.path) {
this.log("Socket Server Path not specified, refusing to start");
return;
}
if (this.config.unlink) {
import_fs2.default.unlink(this.path, startServer.bind(this));
} else {
startServer.bind(this)();
}
}
};
function emit2(socket, type, data) {
this.log("dispatching event to socket", " : ", type, data);
let message = new import_js_message2.default();
message.type = type;
message.data = data;
if (this.config.rawBuffer) {
this.log(this.config.encoding);
message = Buffer.from(type, this.config.encoding);
} else {
message = eventParser2.format(message);
}
if (this.udp4 || this.udp6) {
if (!socket.address || !socket.port) {
this.log("Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets");
this.broadcast(type, data);
return;
}
this.server.write(message, socket);
return;
}
socket.write(message);
}
function broadcast(type, data) {
this.log("broadcasting event to all known sockets listening to ", this.path, " : ", this.port ? this.port : "", type, data);
let message = new import_js_message2.default();
message.type = type;
message.data = data;
if (this.config.rawBuffer) {
message = Buffer.from(type, this.config.encoding);
} else {
message = eventParser2.format(message);
}
if (this.udp4 || this.udp6) {
for (let i = 1, count = this.sockets.length; i < count; i++) {
this.server.write(message, this.sockets[i]);
}
} else {
for (let i = 0, count = this.sockets.length; i < count; i++) {
this.sockets[i].write(message);
}
}
}
function serverClosed() {
for (let i = 0, count = this.sockets.length; i < count; i++) {
let socket = this.sockets[i];
let destroyedSocketId = false;
if (socket) {
if (socket.readable) {
continue;
}
}
if (socket.id) {
destroyedSocketId = socket.id;
}
this.log("socket disconnected", destroyedSocketId.toString());
if (socket && socket.destroy) {
socket.destroy();
}
this.sockets.splice(i, 1);
this.publish("socket.disconnected", socket, destroyedSocketId);
return;
}
}
function gotData(socket, data, UDPSocket) {
let sock = this.udp4 || this.udp6 ? UDPSocket : socket;
if (this.config.rawBuffer) {
data = Buffer.from(data, this.config.encoding);
this.publish("data", data, sock);
return;
}
if (!sock.ipcBuffer) {
sock.ipcBuffer = "";
}
data = sock.ipcBuffer += data;
if (data.slice(-1) != eventParser2.delimiter || data.indexOf(eventParser2.delimiter) == -1) {
this.log("Messages are large, You may want to consider smaller messages.");
return;
}
sock.ipcBuffer = "";
data = eventParser2.parse(data);
while (data.length > 0) {
let message = new import_js_message2.default();
message.load(data.shift());
if (message.data && message.data.id) {
sock.id = message.data.id;
}
this.log("received event of : ", message.type, message.data);
this.publish(message.type, message.data, sock);
}
}
function socketClosed(socket) {
this.publish("close", socket);
}
function serverCreated(socket) {
this.sockets.push(socket);
if (socket.setEncoding) {
socket.setEncoding(this.config.encoding);
}
this.log("## socket connection to server detected ##");
socket.on("close", socketClosed.bind(this));
socket.on("error", function(err) {
this.log("server socket error", err);
this.publish("error", err);
}.bind(this));
socket.on("data", gotData.bind(this, socket));
socket.on("message", function(msg, rinfo) {
if (!rinfo) {
return;
}
this.log("Received UDP message from ", rinfo.address, rinfo.port);
let data;
if (this.config.rawSocket) {
data = Buffer.from(msg, this.config.encoding);
} else {
data = msg.toString();
}
socket.emit("data", data, rinfo);
}.bind(this));
this.publish("connect", socket);
if (this.config.rawBuffer) {
return;
}
}
function startServer() {
this.log("starting server on ", this.path, this.port ? `:${this.port}` : "");
if (!this.udp4 && !this.udp6) {
this.log("starting TLS server", this.config.tls);
if (!this.config.tls) {
this.server = import_net2.default.createServer(serverCreated.bind(this));
} else {
startTLSServer.bind(this)();
}
} else {
this.server = import_dgram.default.createSocket(this.udp4 ? "udp4" : "udp6");
this.server.write = UDPWrite.bind(this);
this.server.on("listening", function UDPServerStarted() {
serverCreated.bind(this)(this.server);
}.bind(this));
}
this.server.on("error", function(err) {
this.log("server error", err);
this.publish("error", err);
}.bind(this));
this.server.maxConnections = this.config.maxConnections;
if (!this.port) {
this.log("starting server as", "Unix || Windows Socket");
if (process.platform === "win32") {
this.path = this.path.replace(/^\//, "");
this.path = this.path.replace(/\//g, "-");
this.path = `\\\\.\\pipe\\${this.path}`;
}
this.server.listen({
path: this.path,
readableAll: this.config.readableAll,
writableAll: this.config.writableAll
}, this.onStart.bind(this));
return;
}
if (!this.udp4 && !this.udp6) {
this.log("starting server as", this.config.tls ? "TLS" : "TCP");
this.server.listen(this.port, this.path, this.onStart.bind(this));
return;
}
this.log("starting server as", this.udp4 ? "udp4" : "udp6");
this.server.bind(this.port, this.path);
this.onStart({
address: this.path,
port: this.port
});
}
function startTLSServer() {
this.log("starting TLS server", this.config.tls);
if (this.config.tls.private) {
this.config.tls.key = import_fs2.default.readFileSync(this.config.tls.private);
} else {
this.config.tls.key = import_fs2.default.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`);
}
if (this.config.tls.public) {
this.config.tls.cert = import_fs2.default.readFileSync(this.config.tls.public);
} else {
this.config.tls.cert = import_fs2.default.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`);
}
if (this.config.tls.dhparam) {
this.config.tls.dhparam = import_fs2.default.readFileSync(this.config.tls.dhparam);
}
if (this.config.tls.trustedConnections) {
if (typeof this.config.tls.trustedConnections === "string") {
this.config.tls.trustedConnections = [this.config.tls.trustedConnections];
}
this.config.tls.ca = [];
for (let i = 0; i < this.config.tls.trustedConnections.length; i++) {
this.config.tls.ca.push(import_fs2.default.readFileSync(this.config.tls.trustedConnections[i]));
}
}
this.server = import_tls2.default.createServer(this.config.tls, serverCreated.bind(this));
}
function UDPWrite(message, socket) {
let data = Buffer.from(message, this.config.encoding);
this.server.send(data, 0, data.length, socket.port, socket.address, function(err, bytes) {
if (err) {
this.log("error writing data to socket", err);
this.publish("error", function(err2) {
this.publish("error", err2);
});
}
});
}
// services/IPC.js
var import_util = __toModule(require("util"));
var IPC = class {
constructor() {
__publicField(this, "config", new Defaults());
__publicField(this, "of", {});
__publicField(this, "server", false);
}
get connectTo() {
return connect2;
}
get connectToNet() {
return connectNet;
}
get disconnect() {
return disconnect;
}
get serve() {
return serve;
}
get serveNet() {
return serveNet;
}
get log() {
return log;
}
set connectTo(value) {
return connect2;
}
set connectToNet(value) {
return connectNet;
}
set disconnect(value) {
return disconnect;
}
set serve(value) {
return serve;
}
set serveNet(value) {
return serveNet;
}
set log(value) {
return log;
}
};
function log(...args) {
if (this.config.silent) {
return;
}
for (let i = 0, count = args.length; i < count; i++) {
if (typeof args[i] != "object") {
continue;
}
args[i] = import_util.default.inspect(args[i], {
depth: this.config.logDepth,
colors: this.config.logInColor
});
}
this.config.logger(args.join(" "));
}
function disconnect(id) {
if (!this.of[id]) {
return;
}
this.of[id].explicitlyDisconnected = true;
this.of[id].off("*", "*");
if (this.of[id].socket) {
if (this.of[id].socket.destroy) {
this.of[id].socket.destroy();
}
}
delete this.of[id];
}
function serve(path, callback) {
if (typeof path == "function") {
callback = path;
path = false;
}
if (!path) {
this.log("Server path not specified, so defaulting to", "ipc.config.socketRoot + ipc.config.appspace + ipc.config.id", this.config.socketRoot + this.config.appspace + this.config.id);
path = this.config.socketRoot + this.config.appspace + this.config.id;
}
if (!callback) {
callback = emptyCallback;
}
this.server = new Server(path, this.config, log);
this.server.on("start", callback);
}
function emptyCallback() {
}
function serveNet(host, port, UDPType2, callback) {
if (typeof host == "number") {
callback = UDPType2;
UDPType2 = port;
port = host;
host = false;
}
if (typeof host == "function") {
callback = host;
UDPType2 = false;
host = false;
port = false;
}
if (!host) {
this.log("Server host not specified, so defaulting to", "ipc.config.networkHost", this.config.networkHost);
host = this.config.networkHost;
}
if (host.toLowerCase() == "udp4" || host.toLowerCase() == "udp6") {
callback = port;
UDPType2 = host.toLowerCase();
port = false;
host = this.config.networkHost;
}
if (typeof port == "string") {
callback = UDPType2;
UDPType2 = port;
port = false;
}
if (typeof port == "function") {
callback = port;
UDPType2 = false;
port = false;
}
if (!port) {
this.log("Server port not specified, so defaulting to", "ipc.config.networkPort", this.config.networkPort);
port = this.config.networkPort;
}
if (typeof UDPType2 == "function") {
callback = UDPType2;
UDPType2 = false;
}
if (!callback) {
callback = emptyCallback;
}
this.server = new Server(host, this.config, log, port);
if (UDPType2) {
this.server[UDPType2] = true;
if (UDPType2 === "udp4" && host === "::1") {
this.server.path = "127.0.0.1";
}
}
this.server.on("start", callback);
}
function connect2(id, path, callback) {
if (typeof path == "function") {
callback = path;
path = false;
}
if (!callback) {
callback = emptyCallback;
}
if (!id) {
this.log("Service id required", "Requested service connection without specifying service id. Aborting connection attempt");
return;
}
if (!path) {
this.log("Service path not specified, so defaulting to", "ipc.config.socketRoot + ipc.config.appspace + id", (this.config.socketRoot + this.config.appspace + id).data);
path = this.config.socketRoot + this.config.appspace + id;
}
if (this.of[id]) {
if (!this.of[id].socket.destroyed) {
this.log("Already Connected to", id, "- So executing success without connection");
callback();
return;
}
this.of[id].socket.destroy();
}
this.of[id] = new Client(this.config, this.log);
this.of[id].id = id;
this.of[id].socket ? this.of[id].socket.id = id : null;
this.of[id].path = path;
this.of[id].connect();
callback(this);
}
function connectNet(id, host, port, callback) {
if (!id) {
this.log("Service id required", "Requested service connection without specifying service id. Aborting connection attempt");
return;
}
if (typeof host == "number") {
callback = port;
port = host;
host = false;
}
if (typeof host == "function") {
callback = host;
host = false;
port = false;
}
if (!host) {
this.log("Server host not specified, so defaulting to", "ipc.config.networkHost", this.config.networkHost);
host = this.config.networkHost;
}
if (typeof port == "function") {
callback = port;
port = false;
}
if (!port) {
this.log("Server port not specified, so defaulting to", "ipc.config.networkPort", this.config.networkPort);
port = this.config.networkPort;
}
if (typeof callback == "string") {
UDPType = callback;
callback = false;
}
if (!callback) {
callback = emptyCallback;
}
if (this.of[id]) {
if (!this.of[id].socket.destroyed) {
this.log("Already Connected to", id, "- So executing success without connection");
callback();
return;
}
this.of[id].socket.destroy();
}
this.of[id] = new Client(this.config, this.log);
this.of[id].id = id;
this.of[id].socket ? this.of[id].socket.id = id : null;
this.of[id].path = host;
this.of[id].port = port;
this.of[id].connect();
callback(this);
}
// node-ipc.js
var IPCModule = class extends IPC {
constructor() {
super();
__publicField(this, "IPC", IPC);
}
};
var singleton = new IPCModule();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
IPCModule
});

Sorry, the diff of this file is not supported yet