@flux-control/effect-modbus-rs 0.1.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.
@@ -0,0 +1,51 @@
1
+ import type { SerialServerOptions, ServerHandlers } from "modbus-rs";
2
+ import { Layer } from "effect";
3
+ import type { ModbusError } from "./errors";
4
+ /**
5
+ * A scoped {@link Layer} that starts a Modbus serial RTU server.
6
+ *
7
+ * @param options - Serial port options (path, baud rate, unit ID, etc.).
8
+ * @param handlers - Callback functions that handle incoming Modbus requests.
9
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Effect, Layer } from "effect";
14
+ * import { serialRtuServerLayer } from "effect-modbus-rs";
15
+ *
16
+ * const ServerLive = serialRtuServerLayer(
17
+ * { portPath: "/dev/ttyUSB0", baudRate: 9600, unitId: 1 },
18
+ * { onReadCoils: (req) => [false, false] },
19
+ * );
20
+ *
21
+ * Layer.launch(ServerLive).pipe(Effect.runPromise);
22
+ * ```
23
+ *
24
+ * @see SerialServerOptions — Options accepted by the upstream serial server.
25
+ * @see ServerHandlers — Interface for request handler callbacks.
26
+ */
27
+ export declare const serialRtuServerLayer: (options: SerialServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
28
+ /**
29
+ * A scoped {@link Layer} that starts a Modbus serial ASCII server.
30
+ *
31
+ * @param options - Serial port options (path, baud rate, unit ID, etc.).
32
+ * @param handlers - Callback functions that handle incoming Modbus requests.
33
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { Effect, Layer } from "effect";
38
+ * import { serialAsciiServerLayer } from "effect-modbus-rs";
39
+ *
40
+ * const ServerLive = serialAsciiServerLayer(
41
+ * { portPath: "/dev/ttyUSB0", baudRate: 9600, unitId: 1 },
42
+ * { onReadCoils: (req) => [false, false] },
43
+ * );
44
+ *
45
+ * Layer.launch(ServerLive).pipe(Effect.runPromise);
46
+ * ```
47
+ *
48
+ * @see SerialServerOptions — Options accepted by the upstream serial server.
49
+ * @see ServerHandlers — Interface for request handler callbacks.
50
+ */
51
+ export declare const serialAsciiServerLayer: (options: SerialServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
@@ -0,0 +1,45 @@
1
+ import { Context, Layer } from "effect";
2
+ import type { AsciiTransportOptions, RtuTransportOptions } from "modbus-rs";
3
+ import type { TransportServiceApi } from "./shared-transport";
4
+ import { type SlaveDeviceDefinitions } from "./mocks";
5
+ declare const SerialTransportService_base: Context.TagClass<SerialTransportService, "SerialTransportService", TransportServiceApi>;
6
+ /**
7
+ * Abstract serial Modbus transport service tag.
8
+ *
9
+ * Represents a serial (RS-232/485) Modbus transport backed by either
10
+ * ASCII or RTU framing. Use this tag when you need a serial transport
11
+ * but don't care about the specific framing protocol.
12
+ *
13
+ * Consumers `yield* SerialTransportService` to obtain a
14
+ * {@link TransportServiceApi} and satisfy the tag via one of the static
15
+ * provider methods:
16
+ *
17
+ * ```ts
18
+ * // Provide with ASCII framing
19
+ * Layer.provide(SerialTransportService.fromAscii({ path: "/dev/ttyUSB0", baudRate: 9600 }))
20
+ *
21
+ * // Provide with RTU framing
22
+ * Layer.provide(SerialTransportService.fromRtu({ path: "/dev/ttyUSB0", baudRate: 9600 }))
23
+ * ```
24
+ */
25
+ export declare class SerialTransportService extends SerialTransportService_base {
26
+ /**
27
+ * Creates a {@link Layer} providing {@link SerialTransportService}
28
+ * backed by an ASCII transport.
29
+ */
30
+ static fromAscii(options: AsciiTransportOptions): Layer.Layer<SerialTransportService>;
31
+ /**
32
+ * Creates a {@link Layer} providing {@link SerialTransportService}
33
+ * backed by an RTU transport.
34
+ */
35
+ static fromRtu(options: RtuTransportOptions): Layer.Layer<SerialTransportService>;
36
+ /**
37
+ * Creates a mock {@link Layer} providing {@link SerialTransportService}
38
+ * for testing or development.
39
+ *
40
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
41
+ * simulated Modbus slaves and their register/coil maps.
42
+ */
43
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: AsciiTransportOptions | RtuTransportOptions) => Layer.Layer<SerialTransportService>;
44
+ }
45
+ export {};
@@ -0,0 +1,42 @@
1
+ import type { GatewayBindOptions, GatewayConfig } from "modbus-rs";
2
+ import { Layer } from "effect";
3
+ import type { ModbusError } from "./errors";
4
+ /**
5
+ * A scoped {@link Layer} that starts a Modbus TCP gateway.
6
+ *
7
+ * The gateway binds to the specified host and port, forwarding incoming
8
+ * Modbus requests to downstream servers based on unit ID routing defined
9
+ * in the {@link GatewayConfig}. The gateway is automatically shut down
10
+ * when the consuming scope finalizes.
11
+ *
12
+ * @param options - Gateway bind options (host, port).
13
+ * @param gatewayConfig - Routing configuration with downstream server
14
+ * definitions and a unit-ID-to-channel route table.
15
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { Effect, Layer } from "effect";
20
+ * import { tcpGatewayLayer } from "effect-modbus-rs";
21
+ *
22
+ * const GatewayLive = tcpGatewayLayer(
23
+ * { host: "0.0.0.0", port: 8502 },
24
+ * {
25
+ * downstreams: [
26
+ * { host: "192.168.1.10", port: 502 },
27
+ * { host: "192.168.1.20", port: 502 },
28
+ * ],
29
+ * routes: [
30
+ * { unitId: 1, channel: 0 },
31
+ * { unitId: 2, channel: 1 },
32
+ * ],
33
+ * },
34
+ * );
35
+ *
36
+ * Layer.launch(GatewayLive).pipe(Effect.runPromise);
37
+ * ```
38
+ *
39
+ * @see GatewayBindOptions — Options for the gateway bind address.
40
+ * @see GatewayConfig — Configuration for downstream servers and routing.
41
+ */
42
+ export declare const tcpGatewayLayer: (options: GatewayBindOptions, gatewayConfig: GatewayConfig) => Layer.Layer<never, ModbusError>;
@@ -0,0 +1,31 @@
1
+ import type { ServerHandlers, TcpServerOptions } from "modbus-rs";
2
+ import { Layer } from "effect";
3
+ import type { ModbusError } from "./errors";
4
+ /**
5
+ * A scoped {@link Layer} that starts a Modbus TCP server.
6
+ *
7
+ * The server binds to the specified host and port, handling incoming
8
+ * Modbus requests via the provided {@link ServerHandlers}. The connection
9
+ * is automatically shut down when the consuming scope finalizes.
10
+ *
11
+ * @param options - Server bind options (host, port, unit ID).
12
+ * @param handlers - Callback functions that handle incoming Modbus requests.
13
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Effect, Layer } from "effect";
18
+ * import { tcpServerLayer } from "effect-modbus-rs";
19
+ *
20
+ * const ServerLive = tcpServerLayer(
21
+ * { host: "0.0.0.0", port: 502, unitId: 1 },
22
+ * { onReadCoils: (req) => [false, false] },
23
+ * );
24
+ *
25
+ * Layer.launch(ServerLive).pipe(Effect.runPromise);
26
+ * ```
27
+ *
28
+ * @see TcpServerOptions — Options accepted by the upstream TCP server.
29
+ * @see ServerHandlers — Interface for request handler callbacks.
30
+ */
31
+ export declare const tcpServerLayer: (options: TcpServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
@@ -0,0 +1,46 @@
1
+ import type { TcpTransportOptions } from "modbus-rs";
2
+ import { Effect, Layer } from "effect";
3
+ import { SlaveDeviceDefinitions } from "./mocks";
4
+ declare const TcpTransportService_base: Effect.Service.Class<TcpTransportService, "TcpTransportService", {
5
+ readonly scoped: (options: TcpTransportOptions) => Effect.Effect<{
6
+ withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
7
+ setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
8
+ clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
9
+ reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
10
+ close: () => Effect.Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
11
+ hasPendingRequests: () => boolean;
12
+ }, never, import("effect/Scope").Scope>;
13
+ }>;
14
+ /**
15
+ * Scoped Effect service wrapping the `modbus-rs` {@link AsyncTcpTransport}
16
+ * for TCP/IP Modbus communication.
17
+ *
18
+ * The transport connection is opened lazily on the first call to
19
+ * `withClient(unitId)` and automatically closed when the consuming
20
+ * {@link Effect.Scope | Scope} finalizes.
21
+ *
22
+ * Clients are created per `unitId` via
23
+ * {@link AsyncTcpTransport.createClient} and cached, so repeated
24
+ * requests for the same unit ID reuse the same client.
25
+ *
26
+ * @see AsyncTcpTransport — Upstream `modbus-rs` TCP transport.
27
+ * @see TcpTransportOptions — Configuration for the TCP connection.
28
+ * @see makeTransportScoped — Generic lifecycle logic from shared-transport.
29
+ */
30
+ export declare class TcpTransportService extends TcpTransportService_base {
31
+ /**
32
+ * Creates a {@link Layer} providing an in-memory mock
33
+ * {@link TcpTransportService} for testing or development.
34
+ *
35
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
36
+ * simulated Modbus slaves and their register/coil maps.
37
+ *
38
+ * @param devices - Slave device definitions for the mock.
39
+ * @returns A function that takes {@link TcpTransportOptions} and
40
+ * returns a scoped {@link Layer} providing the mock service.
41
+ *
42
+ * @see makeMockTransport — The underlying mock factory.
43
+ */
44
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: TcpTransportOptions) => Layer.Layer<TcpTransportService, never, never>;
45
+ }
46
+ export {};
@@ -0,0 +1,170 @@
1
+ declare const ModbusExceptionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "ModbusExceptionError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * Error originating from a Modbus protocol exception response.
6
+ *
7
+ * Mapped from {@link ModbusErrorCode.EXCEPTION} via `modbus-rs`.
8
+ * The {@link exception} field holds the Modbus exception code
9
+ * (e.g. 1 = ILLEGAL_FUNCTION, 2 = ILLEGAL_DATA_ADDRESS, 3 = ILLEGAL_DATA_VALUE).
10
+ *
11
+ * @see ModbusErrorCode.EXCEPTION — `modbus-rs` error code that triggers this error.
12
+ */
13
+ export declare class ModbusExceptionError extends ModbusExceptionError_base<{
14
+ /** Original error thrown by `modbus-rs`. */
15
+ readonly cause: Error;
16
+ /** Parsed Modbus exception code extracted from the error message. */
17
+ readonly exception: number;
18
+ /** Error message from the underlying `modbus-rs` error. */
19
+ readonly message: string;
20
+ }> {
21
+ }
22
+ declare const ModbusTimeoutError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
23
+ readonly _tag: "ModbusTimeoutError";
24
+ } & Readonly<A>;
25
+ /**
26
+ * Error indicating a request timed out while waiting for a response.
27
+ *
28
+ * Mapped from {@link ModbusErrorCode.TIMEOUT} via `modbus-rs`.
29
+ * Adjust timeouts via `setRequestTimeout` on the transport, or configure
30
+ * with {@link RtuTransportOptions.requestTimeoutMs | requestTimeoutMs} /
31
+ * {@link RtuTransportOptions.responseTimeoutMs | responseTimeoutMs}.
32
+ *
33
+ * @see ModbusErrorCode.TIMEOUT — `modbus-rs` error code that triggers this error.
34
+ */
35
+ export declare class ModbusTimeoutError extends ModbusTimeoutError_base<{
36
+ /** Original error thrown by `modbus-rs`. */
37
+ readonly cause: Error;
38
+ /** Error message from the underlying `modbus-rs` error. */
39
+ readonly message: string;
40
+ }> {
41
+ }
42
+ declare const ModbusTransportError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
43
+ readonly _tag: "ModbusTransportError";
44
+ } & Readonly<A>;
45
+ /**
46
+ * Error indicating a transport-level failure (framing, CRC, or I/O error).
47
+ *
48
+ * Mapped from {@link ModbusErrorCode.TRANSPORT} via `modbus-rs`.
49
+ * Common causes: serial port issues, wiring problems, or baud rate mismatch.
50
+ *
51
+ * @see ModbusErrorCode.TRANSPORT — `modbus-rs` error code that triggers this error.
52
+ */
53
+ export declare class ModbusTransportError extends ModbusTransportError_base<{
54
+ /** Original error thrown by `modbus-rs`. */
55
+ readonly cause: Error;
56
+ /** Error message from the underlying `modbus-rs` error. */
57
+ readonly message: string;
58
+ }> {
59
+ }
60
+ declare const ModbusInvalidArgumentError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
61
+ readonly _tag: "ModbusInvalidArgumentError";
62
+ } & Readonly<A>;
63
+ /**
64
+ * Error indicating an invalid argument was passed to a Modbus API call.
65
+ *
66
+ * Mapped from {@link ModbusErrorCode.INVALID_ARGUMENT} via `modbus-rs`.
67
+ * Typically thrown when register/coil addresses or quantities are out of range.
68
+ *
69
+ * @see ModbusErrorCode.INVALID_ARGUMENT — `modbus-rs` error code that triggers this error.
70
+ */
71
+ export declare class ModbusInvalidArgumentError extends ModbusInvalidArgumentError_base<{
72
+ /** Original error thrown by `modbus-rs`. */
73
+ readonly cause: Error;
74
+ /** Error message from the underlying `modbus-rs` error. */
75
+ readonly message: string;
76
+ }> {
77
+ }
78
+ declare const ModbusConnectionClosedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
79
+ readonly _tag: "ModbusConnectionClosedError";
80
+ } & Readonly<A>;
81
+ /**
82
+ * Error indicating the transport connection was closed unexpectedly.
83
+ *
84
+ * Mapped from {@link ModbusErrorCode.CONNECTION_CLOSED} via `modbus-rs`.
85
+ * The transport can be re-established using `reconnect()` on the transport service.
86
+ *
87
+ * @see ModbusErrorCode.CONNECTION_CLOSED — `modbus-rs` error code that triggers this error.
88
+ */
89
+ export declare class ModbusConnectionClosedError extends ModbusConnectionClosedError_base<{
90
+ /** Original error thrown by `modbus-rs`. */
91
+ readonly cause: Error;
92
+ /** Error message from the underlying `modbus-rs` error. */
93
+ readonly message: string;
94
+ }> {
95
+ }
96
+ declare const ModbusInternalError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
97
+ readonly _tag: "ModbusInternalError";
98
+ } & Readonly<A>;
99
+ /**
100
+ * Error indicating an internal library error not covered by other categories.
101
+ *
102
+ * Mapped from any unrecognized error code returned by
103
+ * {@link getModbusErrorCode} (acts as the catch-all fallback).
104
+ *
105
+ * @see ModbusErrorCode.INTERNAL — `modbus-rs` error code for internal failures.
106
+ */
107
+ export declare class ModbusInternalError extends ModbusInternalError_base<{
108
+ /** Original error thrown by `modbus-rs`. */
109
+ readonly cause: Error;
110
+ /** Error message from the underlying `modbus-rs` error. */
111
+ readonly message: string;
112
+ }> {
113
+ }
114
+ declare const ModbusNotConnectedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
115
+ readonly _tag: "ModbusNotConnectedError";
116
+ } & Readonly<A>;
117
+ /**
118
+ * Error indicating a transport operation was attempted before the
119
+ * connection was established or after it was closed.
120
+ *
121
+ * This is a **local** error — it is never returned by `modbus-rs`.
122
+ * It is thrown by the transport service when `setRequestTimeout`,
123
+ * `clearRequestTimeout`, or `withClient` is called before a
124
+ * successful connection.
125
+ *
126
+ * Connect by calling `withClient(unitId)` on the transport service.
127
+ * The connection is established lazily on the first call.
128
+ *
129
+ * @see ModbusNotConnectedError — Triggered when the transport is null.
130
+ */
131
+ export declare class ModbusNotConnectedError extends ModbusNotConnectedError_base<{
132
+ /** The original cause (typically a descriptive error). */
133
+ readonly cause: Error;
134
+ /** Human-readable explanation of the error. */
135
+ readonly message: string;
136
+ }> {
137
+ }
138
+ /**
139
+ * Union of all typed Modbus errors emitted by this library.
140
+ *
141
+ * Handle with {@linkcode Effect.catchTags}:
142
+ *
143
+ * ```ts
144
+ * Effect.catchTags(client.readHoldingRegisters({ address: 0, quantity: 10 }), {
145
+ * ModbusTimeoutError: () => ...,
146
+ * ModbusTransportError: () => ...,
147
+ * ModbusExceptionError: (e) => ...,
148
+ * })
149
+ * ```
150
+ *
151
+ * Each variant maps to a specific {@link ModbusErrorCode} from `modbus-rs`.
152
+ *
153
+ * @see ModbusErrorCode — The upstream error code enum driving this mapping.
154
+ */
155
+ export type ModbusError = ModbusExceptionError | ModbusTimeoutError | ModbusTransportError | ModbusInvalidArgumentError | ModbusConnectionClosedError | ModbusNotConnectedError | ModbusInternalError;
156
+ /**
157
+ * Converts a raw `Error` from `modbus-rs` into a typed {@link ModbusError}.
158
+ *
159
+ * Uses {@link getModbusErrorCode} to classify the error by its internal
160
+ * error code, then constructs the appropriate `Data.TaggedError` variant.
161
+ * Unknown/unrecognized codes fall through to {@link ModbusInternalError}.
162
+ *
163
+ * @param cause - The raw `Error` thrown by a `modbus-rs` API call.
164
+ * @returns A typed `ModbusError` variant matching the error code.
165
+ *
166
+ * @see getModbusErrorCode — Upstream function that extracts the error discriminant.
167
+ * @see ModbusErrorCode — Enum of possible error codes.
168
+ */
169
+ export declare const toModbusError: (cause: Error) => ModbusError;
170
+ export {};
@@ -0,0 +1,134 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { AsciiTransportOptions, RtuTransportOptions, TcpTransportOptions } from "modbus-rs";
3
+ import { ModbusInvalidArgumentError, type ModbusError } from "./errors";
4
+ import type { EffectModbusClient } from "./modbus-client";
5
+ /**
6
+ * Schema for a single coil (digital output) definition.
7
+ *
8
+ * Each entry declares a coil's address and its default boolean state
9
+ * used when the mock transport initialises.
10
+ */
11
+ export declare const CoilDefinition: Schema.Struct<{
12
+ address: typeof Schema.Number;
13
+ default: typeof Schema.Boolean;
14
+ }>;
15
+ /**
16
+ * Schema for a single discrete input (digital input) definition.
17
+ *
18
+ * Each entry declares a discrete input's address and its default
19
+ * boolean state used when the mock transport initialises.
20
+ */
21
+ export declare const DiscreteInputDefinition: Schema.Struct<{
22
+ address: typeof Schema.Number;
23
+ default: typeof Schema.Boolean;
24
+ }>;
25
+ /**
26
+ * Schema for a single register (holding or input) definition.
27
+ *
28
+ * Each entry declares a register's address and its default 16-bit
29
+ * value used when the mock transport initialises.
30
+ */
31
+ export declare const RegisterDefinition: Schema.Struct<{
32
+ address: typeof Schema.Number;
33
+ default: typeof Schema.Number;
34
+ }>;
35
+ /**
36
+ * Schema for a complete slave device definition.
37
+ *
38
+ * Describes a Modbus slave identified by `unitId`, with optional
39
+ * arrays of coils, discrete inputs, holding registers, and input
40
+ * registers. All arrays default to `[]` when omitted.
41
+ */
42
+ export declare const SlaveDeviceDefinition: Schema.Struct<{
43
+ unitId: typeof Schema.Number;
44
+ coils: Schema.optionalWith<Schema.Array$<Schema.Struct<{
45
+ address: typeof Schema.Number;
46
+ default: typeof Schema.Boolean;
47
+ }>>, {
48
+ default: () => never[];
49
+ }>;
50
+ discreteInputs: Schema.optionalWith<Schema.Array$<Schema.Struct<{
51
+ address: typeof Schema.Number;
52
+ default: typeof Schema.Boolean;
53
+ }>>, {
54
+ default: () => never[];
55
+ }>;
56
+ holdingRegisters: Schema.optionalWith<Schema.Array$<Schema.Struct<{
57
+ address: typeof Schema.Number;
58
+ default: typeof Schema.Number;
59
+ }>>, {
60
+ default: () => never[];
61
+ }>;
62
+ inputRegisters: Schema.optionalWith<Schema.Array$<Schema.Struct<{
63
+ address: typeof Schema.Number;
64
+ default: typeof Schema.Number;
65
+ }>>, {
66
+ default: () => never[];
67
+ }>;
68
+ }>;
69
+ /**
70
+ * Schema for an array of {@link SlaveDeviceDefinition} — the complete
71
+ * set of slave devices the mock transport should simulate.
72
+ */
73
+ export declare const SlaveDeviceDefinitions: Schema.Array$<Schema.Struct<{
74
+ unitId: typeof Schema.Number;
75
+ coils: Schema.optionalWith<Schema.Array$<Schema.Struct<{
76
+ address: typeof Schema.Number;
77
+ default: typeof Schema.Boolean;
78
+ }>>, {
79
+ default: () => never[];
80
+ }>;
81
+ discreteInputs: Schema.optionalWith<Schema.Array$<Schema.Struct<{
82
+ address: typeof Schema.Number;
83
+ default: typeof Schema.Boolean;
84
+ }>>, {
85
+ default: () => never[];
86
+ }>;
87
+ holdingRegisters: Schema.optionalWith<Schema.Array$<Schema.Struct<{
88
+ address: typeof Schema.Number;
89
+ default: typeof Schema.Number;
90
+ }>>, {
91
+ default: () => never[];
92
+ }>;
93
+ inputRegisters: Schema.optionalWith<Schema.Array$<Schema.Struct<{
94
+ address: typeof Schema.Number;
95
+ default: typeof Schema.Number;
96
+ }>>, {
97
+ default: () => never[];
98
+ }>;
99
+ }>>;
100
+ /** Inferred TypeScript type for a {@link CoilDefinition} schema. */
101
+ export type CoilDefinition = Schema.Schema.Type<typeof CoilDefinition>;
102
+ /** Inferred TypeScript type for a {@link DiscreteInputDefinition} schema. */
103
+ export type DiscreteInputDefinition = Schema.Schema.Type<typeof DiscreteInputDefinition>;
104
+ /** Inferred TypeScript type for a {@link RegisterDefinition} schema. */
105
+ export type RegisterDefinition = Schema.Schema.Type<typeof RegisterDefinition>;
106
+ /** Inferred TypeScript type for a {@link SlaveDeviceDefinition} schema. */
107
+ export type SlaveDeviceDefinition = Schema.Schema.Type<typeof SlaveDeviceDefinition>;
108
+ /** Inferred TypeScript type for a {@link SlaveDeviceDefinitions} schema. */
109
+ export type SlaveDeviceDefinitions = Schema.Schema.Type<typeof SlaveDeviceDefinitions>;
110
+ /**
111
+ * Creates a mock transport factory suitable for use as a `scoped`
112
+ * {@link Layer} dependency in tests or development.
113
+ *
114
+ * Accepts an array of {@link SlaveDeviceDefinition} that describe the
115
+ * simulated Modbus slaves, their register maps, and coil states.
116
+ * The returned factory matches the signature expected by the transport
117
+ * service constructors (`RtuTransportOptions | AsciiTransportOptions |
118
+ * TcpTransportOptions`) so it can be injected into any service layer.
119
+ *
120
+ * Unsupported function codes (FIFO queue, file records) return
121
+ * {@link ModbusInvalidArgumentError}.
122
+ *
123
+ * @param devices - Array of slave device definitions to simulate.
124
+ * @returns A transport factory function that returns a scoped Effect
125
+ * providing the mock transport.
126
+ */
127
+ export declare const makeMockTransport: (devices: SlaveDeviceDefinitions) => (_options: RtuTransportOptions | AsciiTransportOptions | TcpTransportOptions) => Effect.Effect<{
128
+ withClient: (unitId: number) => Effect.Effect<EffectModbusClient, ModbusInvalidArgumentError, never>;
129
+ setRequestTimeout: (_timeoutMs: number) => Effect.Effect<void, never, never>;
130
+ clearRequestTimeout: () => Effect.Effect<void, never, never>;
131
+ reconnect: () => Effect.Effect<void, ModbusError, never>;
132
+ close: () => Effect.Effect<void, ModbusError, never>;
133
+ hasPendingRequests: () => false;
134
+ }, never, never>;
@@ -0,0 +1 @@
1
+ export {};