npm package: @iso8583/toolkit
Description: A TypeScript-based ISO8583 TCP server toolkit for building and handling financial transaction messages using the ISO8583 protocol. Includes message parsing, building, and TCP transport support. Compatible with NestJS and other Node.js frameworks.
Author: Mateus Siqueira Carneiro
Latest version: 1.0.0

# @iso8583/toolkit

A TypeScript-based ISO8583 TCP/TLS server toolkit for building and handling financial transaction messages using the ISO8583 protocol. Includes message parsing, building, and secure transport support with both traditional and JSON-friendly APIs. Compatible with NestJS and other Node.js frameworks.

## ✨ Features

- **Dual API Support**: Traditional ISO8583 format and developer-friendly JSON format
- **TCP/TLS Server**: Full-featured server for handling ISO8583 messages over TCP and TLS
- **Secure Transport**: TLS support with configurable certificates and security options
- **Message Parser**: Parse ISO8583 messages from Buffer format to JSON or internal format
- **Message Builder**: Build ISO8583 messages from JSON or internal format to Buffer
- **Type Safety**: Comprehensive TypeScript types and interfaces
- **Field Validation**: Built-in validation for all ISO8583 field types
- **Configuration Validation**: Automatic validation of field definitions and configuration
- **Error Handling**: Standardized error classes for better debugging
- **Helper Functions**: Pre-built functions for common message types (echo, financial, etc.)
- **Event System**: Rich event handling for monitoring and debugging
- **Statistics**: Built-in connection and message tracking
- **Resource Management**: Proper cleanup and resource management
- **NestJS Integration**: Seamless integration with NestJS applications
- **Comprehensive Tests**: Full test suite covering all functionality including edge cases

## 🚀 Quick Start

### Installation

```bash
npm install @iso8583/toolkit
```

### Basic Usage (Node.js)

#### Traditional ISO8583 Mode

```typescript
import { 
  createDefaultServer, 
  FieldType,
  CommonMTI,
  ResponseCode 
} from '@iso8583/toolkit';

// Create server with traditional ISO8583 handling
const server = createDefaultServer(
  { port: 5000, host: 'localhost' },
  {
    async onMessage(message, socket) {
      console.log('Received message:', message.mti);
      
      // Create response with same fields + response code
      const responseFields = new Map(message.fields);
      responseFields.set(39, ResponseCode.APPROVED); // Response code
      
      return {
        mti: '0810', // Echo response
        bitmap: '', // Will be auto-generated
        fields: responseFields,
        buffer: Buffer.alloc(0) // Will be auto-generated
      };
    },
    
    onConnect(socket) {
      console.log('Client connected:', socket.remoteAddress);
    },
    
    onDisconnect(socket) {
      console.log('Client disconnected:', socket.remoteAddress);
    }
  }
);

// Start the server
await server.start();
console.log('ISO8583 server started on port 5000');
```

#### JSON Mode (Recommended)

```typescript
import { 
  createJsonServer, 
  createEchoRequest,
  createEchoResponse,
  createFinancialRequest,
  createFinancialResponse,
  CommonMTI,
  ResponseCode 
} from '@iso8583/toolkit';

// Create server with JSON mode enabled
const server = createJsonServer(
  { port: 5000, host: 'localhost', enableJsonMode: true },
  {
    async onMessage(message, socket) {
      console.log('Received JSON message:', message.mti);
      
      // Handle different message types
      switch (message.mti) {
        case CommonMTI.ECHO_REQUEST:
          return createEchoResponse(message);
          
        case CommonMTI.FINANCIAL_REQUEST:
          // Process financial transaction
          const isApproved = await processTransaction(message);
          return createFinancialResponse(
            message, 
            isApproved ? ResponseCode.APPROVED : ResponseCode.DECLINED
          );
          
        default:
          return createEchoResponse(message, {
            RESPONSE_CODE: ResponseCode.INVALID_MTI
          });
      }
    }
  }
);

await server.start();
console.log('ISO8583 JSON server started on port 5000');
```

#### TLS Server Mode

```typescript
import { 
  Iso8583TlsServer, 
  Iso8583Parser, 
  Iso8583Builder, 
  FieldType,
  CommonMTI,
  ResponseCode 
} from '@iso8583/toolkit';
import fs from 'fs';

// TLS configuration
const tlsConfig = {
  enabled: true,
  port: 5001, // Explicit TLS port (optional, defaults to TCP port + 1)
  cert: fs.readFileSync('./certs/server.crt'),
  key: fs.readFileSync('./certs/server.key'),
  ca: fs.readFileSync('./certs/ca.crt'), // Optional CA certificate
  requestCert: true, // Request client certificates
  rejectUnauthorized: false, // Allow self-signed certs in development
  ciphers: 'TLS_AES_128_GCM_SHA256',
  minVersion: 'TLSv1.2',
  maxVersion: 'TLSv1.3'
};

// Create parser and builder
const parser = new Iso8583Parser({
  fieldDefinitions: DEFAULT_FIELD_DEFINITIONS,
  encoding: 'ascii',
  includeRaw: false,
  enableJsonMode: true
});

const builder = new Iso8583Builder({
  fieldDefinitions: DEFAULT_FIELD_DEFINITIONS,
  encoding: 'ascii',
  enableJsonMode: true
});

// Create TLS server
const tlsServer = new Iso8583TlsServer(
  { 
    port: 5000, 
    host: 'localhost',
    enableJsonMode: true,
    tls: tlsConfig
  },
  {
    async onMessage(message, socket) {
      console.log('Received secure message:', message.mti);
      return createEchoResponse(message);
    },
    
    onSecureConnection(socket) {
      console.log('Secure connection established:', socket.getProtocol());
    },
    
    onConnect(socket) {
      console.log('Client connected:', socket.remoteAddress);
    },
    
    onDisconnect(socket) {
      console.log('Client disconnected:', socket.remoteAddress);
    }
  },
  parser,
  builder
);

// Start both TCP and TLS servers
await tlsServer.start();
console.log('ISO8583 TLS server started on ports 5000 (TCP) and 5001 (TLS)');
```

### Advanced Usage

#### Custom Field Definitions

```typescript
import { 
  Iso8583Server, 
  Iso8583Parser, 
  Iso8583Builder, 
  FieldType 
} from '@iso8583/toolkit';

// Define custom field definitions
const customFieldDefinitions = [
  { id: 2, name: 'PAN', type: FieldType.LLVAR, maxLength: 19, required: true },
  { id: 3, name: 'PROC_CODE', type: FieldType.NUMERIC, maxLength: 6, required: true },
  { id: 4, name: 'AMOUNT', type: FieldType.AMOUNT, maxLength: 12, required: true },
  { id: 7, name: 'TRANSMISSION_DATE_TIME', type: FieldType.NUMERIC, maxLength: 10, required: true },
  { id: 11, name: 'STAN', type: FieldType.NUMERIC, maxLength: 6, required: true },
  { id: 39, name: 'RESPONSE_CODE', type: FieldType.ALPHANUMERIC, maxLength: 2, required: false },
  { id: 62, name: 'RESERVED_PRIVATE', type: FieldType.LLLVAR, maxLength: 255, required: false },
  // Add more fields as needed...
];

// Create parser and builder with custom definitions
const parser = new Iso8583Parser({
  fieldDefinitions: customFieldDefinitions,
  encoding: 'ascii',
  includeRaw: false,
  enableJsonMode: true
});

const builder = new Iso8583Builder({
  fieldDefinitions: customFieldDefinitions,
  encoding: 'ascii',
  enableJsonMode: true
});

// Create server with custom components
const server = new Iso8583Server(
  { port: 5000, enableJsonMode: true },
  {
    async onMessage(message, socket) {
      // Handle messages with custom field definitions
      return createEchoResponse(message);
    }
  },
  parser,
  builder
);
```

#### Message Validation and Error Handling

```typescript
import { 
  createJsonConverter, 
  createEchoRequest,
  ResponseCode,
  Iso8583ValidationError,
  Iso8583ParsingError,
  Iso8583BuildingError 
} from '@iso8583/toolkit';

const converter = createJsonConverter();

// Validate message before processing
const message = createEchoRequest({
  PAN: '1234567890123456',
  PROC_CODE: '000000',
  AMOUNT: '000000012500'
});

const validation = converter.validateJsonMessage(message);
if (!validation.isValid) {
  console.error('Validation errors:', validation.errors);
  console.warn('Validation warnings:', validation.warnings);
  return;
}

// Handle specific error types
try {
  const isoMessage = converter.toIso8583(message);
  console.log('Converted message:', isoMessage);
} catch (error) {
  if (error instanceof Iso8583ValidationError) {
    console.error('Validation error:', error.message, 'Field:', error.field);
  } else if (error instanceof Iso8583ParsingError) {
    console.error('Parsing error:', error.message, 'Field:', error.field);
  } else if (error instanceof Iso8583BuildingError) {
    console.error('Building error:', error.message, 'Field:', error.field);
  } else {
    console.error('Unknown error:', error);
  }
}

// Convert to ISO8583 format
// (This is now handled in the try-catch block above)
```

#### Broadcasting Messages

```typescript
import { createJsonServer, createEchoRequest } from '@iso8583/toolkit';

const server = createJsonServer(
  { port: 5000, enableJsonMode: true },
  {
    async onMessage(message, socket) {
      // Broadcast message to all connected clients
      const broadcastMessage = createEchoRequest({
        PAN: '1234567890123456',
        PROC_CODE: '000000'
      });
      
      const sentCount = server.broadcastJson(broadcastMessage);
      console.log(`Broadcasted message to ${sentCount} clients`);
      
      return createEchoResponse(message);
    }
  }
);
```

## 🏗️ NestJS Integration

### Basic NestJS Service

```typescript
// iso8583.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { 
  createJsonServer, 
  createEchoRequest,
  createEchoResponse,
  createFinancialRequest,
  createFinancialResponse,
  CommonMTI,
  ResponseCode,
  type Iso8583JsonMessage,
  type Iso8583JsonResponse 
} from '@iso8583/toolkit';

@Injectable()
export class Iso8583Service implements OnModuleInit, OnModuleDestroy {
  private server: any;

  async onModuleInit() {
    this.server = createJsonServer(
      { port: 5000, enableJsonMode: true },
      {
        onMessage: this.handleMessage.bind(this),
        onConnect: this.handleConnect.bind(this),
        onDisconnect: this.handleDisconnect.bind(this),
        onError: this.handleError.bind(this)
      }
    );

    await this.server.start();
    console.log('ISO8583 server started on port 5000');
  }

  async onModuleDestroy() {
    if (this.server) {
      await this.server.stop();
    }
  }

  private async handleMessage(
    message: Iso8583JsonMessage, 
    socket: any
  ): Promise<Iso8583JsonResponse | void> {
    console.log('Received message:', message.mti);

    switch (message.mti) {
      case CommonMTI.ECHO_REQUEST:
        return createEchoResponse(message);

      case CommonMTI.FINANCIAL_REQUEST:
        return await this.processFinancialTransaction(message);

      default:
        return createEchoResponse(message, {
          RESPONSE_CODE: ResponseCode.INVALID_MTI
        });
    }
  }

  private async processFinancialTransaction(
    message: Iso8583JsonMessage
  ): Promise<Iso8583JsonResponse> {
    // Implement your business logic here
    const isApproved = await this.validateTransaction(message);
    
    return createFinancialResponse(
      message,
      isApproved ? ResponseCode.APPROVED : ResponseCode.DECLINED
    );
  }

  private handleConnect(socket: any) {
    console.log('Client connected:', socket.remoteAddress);
  }

  private handleDisconnect(socket: any) {
    console.log('Client disconnected:', socket.remoteAddress);
  }

  private handleError(error: Error, socket?: any) {
    console.error('ISO8583 server error:', error);
  }

  // Public methods for external use
  getStats() {
    return this.server.getStats();
  }

  getConnections() {
    return this.server.getConnections();
  }

  broadcastMessage(message: Iso8583JsonMessage) {
    return this.server.broadcastJson(message);
  }
}
```

### NestJS Module

```typescript
// iso8583.module.ts
import { Module } from '@nestjs/common';
import { Iso8583Service } from './iso8583.service';
import { Iso8583Controller } from './iso8583.controller';

@Module({
  providers: [Iso8583Service],
  controllers: [Iso8583Controller],
  exports: [Iso8583Service]
})
export class Iso8583Module {}
```

### NestJS Controller

```typescript
// iso8583.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { Iso8583Service } from './iso8583.service';
import { createEchoRequest } from '@iso8583/toolkit';

@Controller('iso8583')
export class Iso8583Controller {
  constructor(private readonly iso8583Service: Iso8583Service) {}

  @Get('stats')
  getStats() {
    return this.iso8583Service.getStats();
  }

  @Get('connections')
  getConnections() {
    return this.iso8583Service.getConnections();
  }

  @Post('broadcast')
  broadcastMessage(@Body() message: any) {
    const echoMessage = createEchoRequest(message);
    const sentCount = this.iso8583Service.broadcastMessage(echoMessage);
    return { sentCount, message: echoMessage };
  }
}
```

### NestJS Application

```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { Iso8583Module } from './iso8583/iso8583.module';

@Module({
  imports: [Iso8583Module],
})
export class AppModule {}
```

```typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
  console.log('NestJS application started on port 3000');
}
bootstrap();
```

## 📋 API Reference

### Core Classes

#### `Iso8583Server`

Main server class for handling TCP connections and ISO8583 messages.

```typescript
const server = new Iso8583Server(config, handlers, parser, builder);
```

**Methods:**
- `start()`: Start the server
- `stop()`: Stop the server
- `getStats()`: Get server statistics
- `getConnections()`: Get active connections
- `broadcast(mti, fields)`: Broadcast message to all clients
- `broadcastJson(jsonMessage)`: Broadcast JSON message to all clients
- `sendMessage(socket, mti, fields)`: Send message to specific client
- `sendJsonMessage(socket, jsonMessage)`: Send JSON message to specific client
- `cleanup()`: Cleanup resources
- `destroy()`: Destroy server and cleanup resources

#### `Iso8583TlsServer`

Main server class for handling TCP and TLS connections and ISO8583 messages.

```typescript
const tlsServer = new Iso8583TlsServer(config, handlers, parser, builder);
```

**Methods:**
- `start()`: Start both TCP and TLS servers
- `stop()`: Stop both servers
- `getStats()`: Get server statistics including secure connections
- `getConnections()`: Get all active connections
- `getSecureConnections()`: Get only TLS connections
- `broadcast(mti, fields)`: Broadcast message to all clients
- `broadcastJson(jsonMessage)`: Broadcast JSON message to all clients
- `sendMessage(socket, mti, fields)`: Send message to specific client
- `sendJsonMessage(socket, jsonMessage)`: Send JSON message to specific client
- `isTlsEnabled()`: Check if TLS is enabled
- `getTlsConfig()`: Get TLS configuration
- `cleanup()`: Cleanup resources
- `destroy()`: Destroy server and cleanup resources

#### `Iso8583Parser`

Parse ISO8583 messages from Buffer format.

```typescript
const parser = new Iso8583Parser(config);
```

**Methods:**
- `parse(buffer)`: Parse Buffer to internal format
- `parseToJson(buffer)`: Parse Buffer to JSON format (JSON mode only)
- `validate(message)`: Validate parsed message
- `enableJsonMode()`: Enable JSON mode after construction

#### `Iso8583Builder`

Build ISO8583 messages to Buffer format.

```typescript
const builder = new Iso8583Builder(config);
```

**Methods:**
- `build(mti, fields)`: Build message from internal format
- `buildFromJson(jsonMessage)`: Build message from JSON (JSON mode only)
- `validate(mti, fields)`: Validate message before building
- `validateJson(jsonMessage)`: Validate JSON message (JSON mode only)
- `createResponse(request, responseMti, responseFields)`: Create response from request
- `createResponseFromJson(request, responseMti, responseFields, responseCode)`: Create JSON response
- `enableJsonMode()`: Enable JSON mode after construction

#### `Iso8583JsonConverter`

Convert between JSON and internal ISO8583 formats.

```typescript
const converter = new Iso8583JsonConverter(fieldDefinitions);
```

**Methods:**
- `toIso8583(jsonMessage)`: Convert JSON to internal format
- `toJson(isoMessage)`: Convert internal format to JSON
- `toIso8583Response(jsonResponse)`: Convert JSON response to internal format
- `toJsonResponse(isoResponse)`: Convert internal response to JSON
- `validateJsonMessage(jsonMessage)`: Validate JSON message
- `createResponse(request, responseMti, responseFields, responseCode)`: Create JSON response

### Helper Functions

#### Message Creation

```typescript
import { 
  createEchoRequest,
  createEchoResponse,
  createFinancialRequest,
  createFinancialResponse 
} from '@iso8583/toolkit';

// Create echo request
const echoRequest = createEchoRequest({
  PAN: '1234567890123456',
  PROC_CODE: '000000'
});

// Create echo response
const echoResponse = createEchoResponse(echoRequest);

// Create financial request
const financialRequest = createFinancialRequest({
  PAN: '1234567890123456',
  PROC_CODE: '000000',
  AMOUNT: '000000012500'
});

// Create financial response
const financialResponse = createFinancialResponse(
  financialRequest, 
  ResponseCode.APPROVED
);
```

#### Utility Functions

```typescript
import { 
  createDefaultParser,
  createDefaultBuilder,
  createDefaultServer,
  createJsonParser,
  createJsonBuilder,
  createJsonServer,
  createJsonConverter 
} from '@iso8583/toolkit';

// Traditional mode
const parser = createDefaultParser();
const builder = createDefaultBuilder();
const server = createDefaultServer(config, handlers);

// JSON mode
const jsonParser = createJsonParser();
const jsonBuilder = createJsonBuilder();
const jsonServer = createJsonServer(config, handlers);
const converter = createJsonConverter();
```

### Error Classes

```typescript
import { 
  Iso8583Error,
  Iso8583ValidationError,
  Iso8583ParsingError,
  Iso8583BuildingError 
} from '@iso8583/toolkit';

// Base error class
Iso8583Error

// Specific error types
Iso8583ValidationError  // For validation errors
Iso8583ParsingError     // For parsing errors
Iso8583BuildingError    // For building errors
```

### Constants

```typescript
import { 
  CommonMTI, 
  ResponseCode, 
  FieldType,
  DEFAULT_FIELD_DEFINITIONS 
} from '@iso8583/toolkit';

// Common MTIs
CommonMTI.ECHO_REQUEST        // '0800'
CommonMTI.ECHO_RESPONSE       // '0810'
CommonMTI.FINANCIAL_REQUEST   // '0200'
CommonMTI.FINANCIAL_RESPONSE  // '0210'

// Response codes
ResponseCode.APPROVED         // '00'
ResponseCode.DECLINED         // '05'
ResponseCode.INSUFFICIENT_FUNDS // '51'
ResponseCode.SYSTEM_ERROR     // '96'

// Field types
FieldType.NUMERIC
FieldType.ALPHA
FieldType.ALPHANUMERIC
FieldType.BINARY
FieldType.LLVAR
FieldType.LLLVAR
FieldType.DATE
FieldType.TIME
FieldType.AMOUNT
```

## 🧪 Testing

```bash
# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Run specific test files
npm test -- test/tls-server.test.ts
npm test -- test/critical-bug-fixes.test.ts
```

## 🏗️ Development

```bash
# Install dependencies
npm install

# Build the project
npm run build

# Run in development mode (watch for changes)
npm run dev

# Clean build artifacts
npm run clean
```

## 📁 Project Structure

```
iso8583-toolkit/
├── src/
│   ├── index.ts              # Main entry point
│   ├── types.ts              # TypeScript type definitions
│   ├── parser.ts             # ISO8583 message parser
│   ├── builder.ts            # ISO8583 message builder
│   ├── server.ts             # TCP server implementation
│   ├── tls-server.ts         # TLS server implementation
│   └── json-converter.ts     # JSON conversion utilities
├── test/
│   ├── server.test.ts        # TCP server test suite
│   ├── tls-server.test.ts    # TLS server test suite
│   ├── critical-bug-fixes.test.ts # Critical bug fixes verification
│   ├── parser.test.ts        # Parser test suite
│   ├── builder.test.ts       # Builder test suite
│   ├── json-converter.test.ts # JSON converter test suite
│   └── certs/                # Test certificates
├── dist/                     # Built output
├── package.json              # Package configuration
├── tsconfig.json             # TypeScript configuration
├── tsup.config.ts            # Build configuration
├── vitest.config.ts          # Test configuration
├── BUGS_AND_IMPROVEMENTS.md  # Bug analysis and improvements
└── README.md                 # This file
```

## 🤝 Contributing

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

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🆘 Support

- **Issues**: [GitHub Issues](https://github.com/themsiqueira/iso8583-toolkit/issues)
- **Discussions**: [GitHub Discussions](https://github.com/themsiqueira/iso8583-toolkit/discussions)
- **Documentation**: [GitHub Wiki](https://github.com/themsiqueira/iso8583-toolkit/wiki)

## 📈 Changelog

### v1.1.0
- **TLS Server Support**: Added full TLS server implementation with configurable certificates
- **Critical Bug Fixes**: Fixed bitmap generation crash with empty fields and LLLVAR field handling
- **Configuration Validation**: Added automatic validation of field definitions and configuration
- **Error Handling**: Implemented standardized error classes for better debugging
- **Resource Management**: Added proper cleanup and resource management methods
- **Enhanced Testing**: Comprehensive test suite including edge cases and TLS functionality
- **Documentation**: Updated documentation with TLS examples and error handling

### v1.0.0
- Initial release
- Traditional ISO8583 mode support
- JSON mode support for developer-friendly API
- TCP server implementation
- Message parsing and building
- Field validation
- Helper functions for common message types
- NestJS integration examples
- Comprehensive test suite
- TypeScript support with full type safety