@ya-modbus/emulator 0.4.1-refactor-scope-driver-packages.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +674 -0
  3. package/README.md +226 -0
  4. package/bin/ya-modbus-emulator.js +10 -0
  5. package/dist/behaviors/function-codes.d.ts +12 -0
  6. package/dist/behaviors/function-codes.d.ts.map +1 -0
  7. package/dist/behaviors/function-codes.js +139 -0
  8. package/dist/behaviors/function-codes.js.map +1 -0
  9. package/dist/behaviors/timing.d.ts +46 -0
  10. package/dist/behaviors/timing.d.ts.map +1 -0
  11. package/dist/behaviors/timing.js +90 -0
  12. package/dist/behaviors/timing.js.map +1 -0
  13. package/dist/cli.d.ts +10 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +124 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/device.d.ts +25 -0
  18. package/dist/device.d.ts.map +1 -0
  19. package/dist/device.js +93 -0
  20. package/dist/device.js.map +1 -0
  21. package/dist/emulator.d.ts +24 -0
  22. package/dist/emulator.d.ts.map +1 -0
  23. package/dist/emulator.js +116 -0
  24. package/dist/emulator.js.map +1 -0
  25. package/dist/index.d.ts +8 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/transports/base.d.ts +10 -0
  30. package/dist/transports/base.d.ts.map +1 -0
  31. package/dist/transports/base.js +6 -0
  32. package/dist/transports/base.js.map +1 -0
  33. package/dist/transports/memory.d.ts +16 -0
  34. package/dist/transports/memory.d.ts.map +1 -0
  35. package/dist/transports/memory.js +30 -0
  36. package/dist/transports/memory.js.map +1 -0
  37. package/dist/transports/rtu.d.ts +44 -0
  38. package/dist/transports/rtu.d.ts.map +1 -0
  39. package/dist/transports/rtu.js +121 -0
  40. package/dist/transports/rtu.js.map +1 -0
  41. package/dist/types/config.d.ts +54 -0
  42. package/dist/types/config.d.ts.map +1 -0
  43. package/dist/types/config.js +5 -0
  44. package/dist/types/config.js.map +1 -0
  45. package/dist/types/device.d.ts +27 -0
  46. package/dist/types/device.d.ts.map +1 -0
  47. package/dist/types/device.js +5 -0
  48. package/dist/types/device.js.map +1 -0
  49. package/dist/utils/config-loader.d.ts +21 -0
  50. package/dist/utils/config-loader.d.ts.map +1 -0
  51. package/dist/utils/config-loader.js +53 -0
  52. package/dist/utils/config-loader.js.map +1 -0
  53. package/package.json +51 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * RTU (serial) transport for Modbus emulator
3
+ *
4
+ * This implementation uses modbus-serial for protocol handling.
5
+ * Serial port communication will be added in future iterations.
6
+ */
7
+ import { BaseTransport } from './base.js';
8
+ export class RtuTransport extends BaseTransport {
9
+ requestHandler;
10
+ started = false;
11
+ constructor(_config) {
12
+ super();
13
+ // Config stored for future serial port implementation
14
+ }
15
+ start() {
16
+ this.started = true;
17
+ // Serial port initialization will be implemented when needed
18
+ // For now, this is a placeholder for the interface
19
+ return Promise.resolve();
20
+ }
21
+ stop() {
22
+ if (!this.started) {
23
+ return Promise.resolve();
24
+ }
25
+ this.started = false;
26
+ // Serial port cleanup will be implemented when needed
27
+ return Promise.resolve();
28
+ }
29
+ send(_slaveId, _response) {
30
+ if (!this.started) {
31
+ return Promise.reject(new Error('Transport not started'));
32
+ }
33
+ // Response sending will be implemented with serial port
34
+ return Promise.resolve();
35
+ }
36
+ onRequest(handler) {
37
+ this.requestHandler = handler;
38
+ }
39
+ /**
40
+ * Handle complete RTU frame (for future serial port implementation)
41
+ * @internal
42
+ */
43
+ async handleFrame(frame) {
44
+ // Minimum frame: slave_id + function_code + CRC (4 bytes)
45
+ if (frame.length < 4) {
46
+ return;
47
+ }
48
+ // Verify CRC
49
+ if (!this.verifyCRC(frame)) {
50
+ return;
51
+ }
52
+ // Extract slave ID (safe after length check)
53
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
54
+ const slaveId = frame[0];
55
+ // Remove CRC to get request data
56
+ const request = frame.subarray(0, frame.length - 2);
57
+ if (!this.requestHandler) {
58
+ return;
59
+ }
60
+ try {
61
+ // Get response from handler
62
+ const response = await this.requestHandler(slaveId, request);
63
+ // Send response (null check required by exactOptionalPropertyTypes)
64
+ if (response !== undefined) {
65
+ await this.send(slaveId, response);
66
+ }
67
+ }
68
+ catch {
69
+ // Don't send response if handler fails
70
+ }
71
+ }
72
+ /**
73
+ * Calculate Modbus RTU CRC-16 (Modbus variant)
74
+ *
75
+ * Returns CRC as a 16-bit value that can be written with writeUInt16LE
76
+ */
77
+ calculateCRC(buffer) {
78
+ let crc = 0xffff;
79
+ for (let i = 0; i < buffer.length; i++) {
80
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
81
+ crc ^= buffer[i];
82
+ for (let j = 0; j < 8; j++) {
83
+ if (crc & 0x0001) {
84
+ crc = (crc >> 1) ^ 0xa001;
85
+ }
86
+ else {
87
+ crc = crc >> 1;
88
+ }
89
+ }
90
+ }
91
+ // Swap bytes for little-endian representation
92
+ // CRC is stored low byte first in Modbus RTU
93
+ return ((crc & 0xff) << 8) | ((crc >> 8) & 0xff);
94
+ }
95
+ /**
96
+ * Verify CRC of RTU frame
97
+ */
98
+ verifyCRC(frame) {
99
+ if (frame.length < 4) {
100
+ return false;
101
+ }
102
+ // Get CRC from frame (last 2 bytes, little-endian)
103
+ const receivedCRC = frame.readUInt16LE(frame.length - 2);
104
+ // Calculate CRC of data (everything except last 2 bytes)
105
+ const data = frame.subarray(0, frame.length - 2);
106
+ const calculatedCRC = this.calculateCRC(data);
107
+ return receivedCRC === calculatedCRC;
108
+ }
109
+ /**
110
+ * Add CRC to buffer
111
+ * @internal
112
+ */
113
+ addCRC(buffer) {
114
+ const crc = this.calculateCRC(buffer);
115
+ const result = Buffer.alloc(buffer.length + 2);
116
+ buffer.copy(result);
117
+ result.writeUInt16LE(crc, buffer.length);
118
+ return result;
119
+ }
120
+ }
121
+ //# sourceMappingURL=rtu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtu.js","sourceRoot":"","sources":["../../src/transports/rtu.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Configuration types for the Modbus emulator
3
+ */
4
+ export interface EmulatorConfig {
5
+ /** Transport type */
6
+ transport: 'tcp' | 'rtu' | 'memory';
7
+ /** Port number (TCP) or serial port path (RTU) */
8
+ port?: number | string;
9
+ /** Host address for TCP transport */
10
+ host?: string;
11
+ /** Maximum number of connections (TCP) */
12
+ maxConnections?: number;
13
+ /** Baud rate for RTU transport */
14
+ baudRate?: number;
15
+ /** Parity for RTU transport */
16
+ parity?: 'none' | 'even' | 'odd';
17
+ /** Stop bits for RTU transport */
18
+ stopBits?: 1 | 2;
19
+ /** Data bits for RTU transport */
20
+ dataBits?: 7 | 8;
21
+ }
22
+ export interface RegisterStorage {
23
+ /** Holding registers (read/write) */
24
+ holding?: Record<number, number>;
25
+ /** Input registers (read-only) */
26
+ input?: Record<number, number>;
27
+ /** Coils (read/write bits) */
28
+ coils?: Record<number, boolean>;
29
+ /** Discrete inputs (read-only bits) */
30
+ discreteInputs?: Record<number, boolean>;
31
+ }
32
+ export interface TimingBehavior {
33
+ /** Time device takes to notice incoming command (ms) */
34
+ commandDetectionDelay?: number | [min: number, max: number];
35
+ /** Internal polling interval (ms) - realistic: 1-100ms */
36
+ pollingInterval?: number;
37
+ /** Base processing time per command (ms) */
38
+ processingDelay?: number | [min: number, max: number];
39
+ /** Additional delay per register read/written (ms) */
40
+ perRegisterDelay?: number;
41
+ /** Baud rate (affects transmission time for RTU) */
42
+ baudRate?: number;
43
+ /** Auto-calculate transmission delay based on frame size */
44
+ autoCalculateTransmissionDelay?: boolean;
45
+ }
46
+ export interface DeviceConfig {
47
+ /** Slave ID (1-247) */
48
+ slaveId: number;
49
+ /** Initial register values */
50
+ registers?: RegisterStorage;
51
+ /** Timing behavior configuration */
52
+ timing?: TimingBehavior;
53
+ }
54
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,SAAS,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAA;IACnC,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;IAChC,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IAChB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,qBAAqB,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;IAC3D,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;IACrD,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,8BAA8B,CAAC,EAAE,OAAO,CAAA;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,oCAAoC;IACpC,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Configuration types for the Modbus emulator
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Device-related types
3
+ */
4
+ import type { TimingSimulator } from '../behaviors/timing.js';
5
+ export interface EmulatedDevice {
6
+ /** Slave ID */
7
+ slaveId: number;
8
+ /** Get holding register value */
9
+ getHoldingRegister(address: number): number;
10
+ /** Set holding register value */
11
+ setHoldingRegister(address: number, value: number): void;
12
+ /** Get input register value */
13
+ getInputRegister(address: number): number;
14
+ /** Set input register value */
15
+ setInputRegister(address: number, value: number): void;
16
+ /** Get coil value */
17
+ getCoil(address: number): boolean;
18
+ /** Set coil value */
19
+ setCoil(address: number, value: boolean): void;
20
+ /** Get discrete input value */
21
+ getDiscreteInput(address: number): boolean;
22
+ /** Set discrete input value */
23
+ setDiscreteInput(address: number, value: boolean): void;
24
+ /** Get timing simulator */
25
+ getTimingSimulator(): TimingSimulator | undefined;
26
+ }
27
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/types/device.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAE7D,MAAM,WAAW,cAAc;IAC7B,eAAe;IACf,OAAO,EAAE,MAAM,CAAA;IACf,iCAAiC;IACjC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3C,iCAAiC;IACjC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACxD,+BAA+B;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;IACzC,+BAA+B;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACtD,qBAAqB;IACrB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IACjC,qBAAqB;IACrB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9C,+BAA+B;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;IAC1C,+BAA+B;IAC/B,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACvD,2BAA2B;IAC3B,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAAA;CAClD"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Device-related types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/types/device.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Configuration file loader for YAML and JSON formats
3
+ */
4
+ import type { DeviceConfig } from '../types/config.js';
5
+ export interface ConfigFile {
6
+ transport: {
7
+ type: 'tcp' | 'rtu' | 'memory';
8
+ port?: number | string;
9
+ host?: string;
10
+ baudRate?: number;
11
+ parity?: 'none' | 'even' | 'odd';
12
+ dataBits?: 7 | 8;
13
+ stopBits?: 1 | 2;
14
+ };
15
+ devices: DeviceConfig[];
16
+ }
17
+ /**
18
+ * Load configuration from YAML or JSON file
19
+ */
20
+ export declare function loadConfig(filePath: string): Promise<ConfigFile>;
21
+ //# sourceMappingURL=config-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE;QACT,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAA;QAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACtB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;QAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;QAChB,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;KACjB,CAAA;IACD,OAAO,EAAE,YAAY,EAAE,CAAA;CACxB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmBtE"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Configuration file loader for YAML and JSON formats
3
+ */
4
+ import { readFile } from 'fs/promises';
5
+ import yaml from 'js-yaml';
6
+ /**
7
+ * Load configuration from YAML or JSON file
8
+ */
9
+ export async function loadConfig(filePath) {
10
+ // Read file content
11
+ const content = await readFile(filePath, 'utf-8');
12
+ // Parse based on file extension
13
+ let config;
14
+ if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
15
+ config = yaml.load(content);
16
+ }
17
+ else if (filePath.endsWith('.json')) {
18
+ config = JSON.parse(content);
19
+ }
20
+ else {
21
+ throw new Error('Unsupported config format. Use .yaml, .yml, or .json');
22
+ }
23
+ // Validate configuration
24
+ validateConfig(config);
25
+ return config;
26
+ }
27
+ /**
28
+ * Validate configuration structure
29
+ */
30
+ function validateConfig(config) {
31
+ if (!config || typeof config !== 'object') {
32
+ throw new Error('Invalid configuration format');
33
+ }
34
+ const cfg = config;
35
+ // Validate transport
36
+ if (!cfg['transport']) {
37
+ throw new Error('Missing transport configuration');
38
+ }
39
+ if (typeof cfg['transport'] !== 'object' || cfg['transport'] === null) {
40
+ throw new Error('Invalid transport configuration');
41
+ }
42
+ // Validate devices
43
+ if (!cfg['devices']) {
44
+ throw new Error('Missing devices configuration');
45
+ }
46
+ if (!Array.isArray(cfg['devices'])) {
47
+ throw new Error('Devices must be an array');
48
+ }
49
+ if (cfg['devices'].length === 0) {
50
+ throw new Error('At least one device must be configured');
51
+ }
52
+ }
53
+ //# sourceMappingURL=config-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,IAAI,MAAM,SAAS,CAAA;AAiB1B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,oBAAoB;IACpB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAEjD,gCAAgC;IAChC,IAAI,MAAe,CAAA;IAEnB,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC9B,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IACzE,CAAC;IAED,yBAAyB;IACzB,cAAc,CAAC,MAAM,CAAC,CAAA;IAEtB,OAAO,MAAoB,CAAA;AAC7B,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,MAAe;IACrC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAA;IAE7C,qBAAqB;IACrB,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IAED,mBAAmB;IACnB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@ya-modbus/emulator",
3
+ "version": "0.4.1-refactor-scope-driver-packages.0",
4
+ "description": "Software Modbus device emulator for testing drivers without physical hardware",
5
+ "keywords": [
6
+ "modbus",
7
+ "emulator",
8
+ "testing",
9
+ "simulation"
10
+ ],
11
+ "author": "Geno Roupsky <geno@roupsky.name>",
12
+ "license": "GPL-3.0-or-later",
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "bin": {
17
+ "ya-modbus-emulator": "./bin/ya-modbus-emulator.js"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "bin",
22
+ "README.md",
23
+ "CHANGELOG.md"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/groupsky/ya-modbus.git",
28
+ "directory": "packages/emulator"
29
+ },
30
+ "homepage": "https://github.com/groupsky/ya-modbus/tree/main/packages/emulator#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/groupsky/ya-modbus/issues"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc --build",
39
+ "clean": "rm -rf dist",
40
+ "test": "jest"
41
+ },
42
+ "dependencies": {
43
+ "commander": "^12.1.0",
44
+ "js-yaml": "^4.1.0",
45
+ "modbus-serial": "^8.0.23"
46
+ },
47
+ "devDependencies": {
48
+ "@types/js-yaml": "^4.0.9"
49
+ },
50
+ "gitHead": "b55d909d67dfff46fb79951e68a2d47ac3fab267"
51
+ }