@flux-control/effect-modbus-rs 0.1.0 → 0.2.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.
@@ -1,6 +1,6 @@
1
- import type { AsciiTransportOptions } from "modbus-rs";
2
- import { Effect, Layer } from "effect";
3
- import { SlaveDeviceDefinitions } from "./mocks";
1
+ import { Effect, Layer } from 'effect';
2
+ import type { AsciiTransportOptions } from 'modbus-rs';
3
+ import { SlaveDeviceDefinitions } from './mocks';
4
4
  declare const AsciiTransportService_base: Effect.Service.Class<AsciiTransportService, "AsciiTransportService", {
5
5
  readonly scoped: (options: AsciiTransportOptions) => Effect.Effect<{
6
6
  withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
@@ -1,6 +1,6 @@
1
- import type { RtuTransportOptions } from "modbus-rs";
2
- import { Effect, Layer } from "effect";
3
- import type { SlaveDeviceDefinitions } from "./mocks";
1
+ import { Effect, Layer } from 'effect';
2
+ import type { RtuTransportOptions } from 'modbus-rs';
3
+ import type { SlaveDeviceDefinitions } from './mocks';
4
4
  declare const RtuTransportService_base: Effect.Service.Class<RtuTransportService, "RtuTransportService", {
5
5
  readonly scoped: (options: RtuTransportOptions) => Effect.Effect<{
6
6
  withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
@@ -1,6 +1,6 @@
1
- import type { SerialServerOptions, ServerHandlers } from "modbus-rs";
2
- import { Layer } from "effect";
3
- import type { ModbusError } from "./errors";
1
+ import { Layer } from 'effect';
2
+ import type { SerialServerOptions, ServerHandlers } from 'modbus-rs';
3
+ import type { ModbusError } from './errors';
4
4
  /**
5
5
  * A scoped {@link Layer} that starts a Modbus serial RTU server.
6
6
  *
@@ -11,7 +11,7 @@ import type { ModbusError } from "./errors";
11
11
  * @example
12
12
  * ```ts
13
13
  * import { Effect, Layer } from "effect";
14
- * import { serialRtuServerLayer } from "effect-modbus-rs";
14
+ * import { serialRtuServerLayer } from "@flux-control/effect-modbus-rs";
15
15
  *
16
16
  * const ServerLive = serialRtuServerLayer(
17
17
  * { portPath: "/dev/ttyUSB0", baudRate: 9600, unitId: 1 },
@@ -35,7 +35,7 @@ export declare const serialRtuServerLayer: (options: SerialServerOptions, handle
35
35
  * @example
36
36
  * ```ts
37
37
  * import { Effect, Layer } from "effect";
38
- * import { serialAsciiServerLayer } from "effect-modbus-rs";
38
+ * import { serialAsciiServerLayer } from "@flux-control/effect-modbus-rs";
39
39
  *
40
40
  * const ServerLive = serialAsciiServerLayer(
41
41
  * { portPath: "/dev/ttyUSB0", baudRate: 9600, unitId: 1 },
@@ -1,7 +1,7 @@
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";
1
+ import { Context, Layer } from 'effect';
2
+ import type { AsciiTransportOptions, RtuTransportOptions } from 'modbus-rs';
3
+ import { type SlaveDeviceDefinitions } from './mocks';
4
+ import type { TransportServiceApi } from './shared-transport';
5
5
  declare const SerialTransportService_base: Context.TagClass<SerialTransportService, "SerialTransportService", TransportServiceApi>;
6
6
  /**
7
7
  * Abstract serial Modbus transport service tag.
@@ -1,6 +1,6 @@
1
- import type { GatewayBindOptions, GatewayConfig } from "modbus-rs";
2
- import { Layer } from "effect";
3
- import type { ModbusError } from "./errors";
1
+ import { Layer } from 'effect';
2
+ import type { GatewayBindOptions, GatewayConfig } from 'modbus-rs';
3
+ import type { ModbusError } from './errors';
4
4
  /**
5
5
  * A scoped {@link Layer} that starts a Modbus TCP gateway.
6
6
  *
@@ -17,7 +17,7 @@ import type { ModbusError } from "./errors";
17
17
  * @example
18
18
  * ```ts
19
19
  * import { Effect, Layer } from "effect";
20
- * import { tcpGatewayLayer } from "effect-modbus-rs";
20
+ * import { tcpGatewayLayer } from "@flux-control/effect-modbus-rs";
21
21
  *
22
22
  * const GatewayLive = tcpGatewayLayer(
23
23
  * { host: "0.0.0.0", port: 8502 },
@@ -1,6 +1,6 @@
1
- import type { ServerHandlers, TcpServerOptions } from "modbus-rs";
2
- import { Layer } from "effect";
3
- import type { ModbusError } from "./errors";
1
+ import { Layer } from 'effect';
2
+ import type { ServerHandlers, TcpServerOptions } from 'modbus-rs';
3
+ import type { ModbusError } from './errors';
4
4
  /**
5
5
  * A scoped {@link Layer} that starts a Modbus TCP server.
6
6
  *
@@ -15,7 +15,7 @@ import type { ModbusError } from "./errors";
15
15
  * @example
16
16
  * ```ts
17
17
  * import { Effect, Layer } from "effect";
18
- * import { tcpServerLayer } from "effect-modbus-rs";
18
+ * import { tcpServerLayer } from "@flux-control/effect-modbus-rs";
19
19
  *
20
20
  * const ServerLive = tcpServerLayer(
21
21
  * { host: "0.0.0.0", port: 502, unitId: 1 },
@@ -1,6 +1,6 @@
1
- import type { TcpTransportOptions } from "modbus-rs";
2
- import { Effect, Layer } from "effect";
3
- import { SlaveDeviceDefinitions } from "./mocks";
1
+ import { Effect, Layer } from 'effect';
2
+ import type { TcpTransportOptions } from 'modbus-rs';
3
+ import { SlaveDeviceDefinitions } from './mocks';
4
4
  declare const TcpTransportService_base: Effect.Service.Class<TcpTransportService, "TcpTransportService", {
5
5
  readonly scoped: (options: TcpTransportOptions) => Effect.Effect<{
6
6
  withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
@@ -0,0 +1,56 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import type { WasmSerialPortHandle, WasmSerialTransportOptions } from 'modbus-rs/web';
3
+ import { SlaveDeviceDefinitions } from './mocks';
4
+ /**
5
+ * Options for {@link WasmAsciiTransportService}. `WasmAsciiTransport.open()` takes the
6
+ * serial port handle and the connection options as two separate arguments; this
7
+ * combines them into one object so it fits {@link makeTransportScoped}'s single-options
8
+ * shape, with `port` destructured back out inside the service's `openMethod`.
9
+ *
10
+ * @see requestSerialPort — Obtains the `port` handle (must be called from a user gesture).
11
+ */
12
+ export type WasmAsciiTransportOpenOptions = WasmSerialTransportOptions & {
13
+ port: WasmSerialPortHandle;
14
+ };
15
+ declare const WasmAsciiTransportService_base: Effect.Service.Class<WasmAsciiTransportService, "WasmAsciiTransportService", {
16
+ readonly scoped: (options: WasmAsciiTransportOpenOptions) => Effect.Effect<{
17
+ withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
18
+ setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
19
+ clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
20
+ reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
21
+ close: () => Effect.Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
22
+ hasPendingRequests: () => boolean;
23
+ }, never, import("effect/Scope").Scope>;
24
+ }>;
25
+ /**
26
+ * Scoped Effect service wrapping `modbus-rs`'s browser {@link WasmAsciiTransport}
27
+ * for Modbus ASCII over the Web Serial API.
28
+ *
29
+ * The transport connection is opened lazily on the first call to
30
+ * `withClient(unitId)` and automatically closed when the consuming
31
+ * {@link Effect.Scope | Scope} finalizes.
32
+ *
33
+ * Clients are created per `unitId` via {@link WasmAsciiTransport.createClient} and
34
+ * cached, so repeated requests for the same unit ID reuse the same client.
35
+ *
36
+ * @see WasmAsciiTransport — Upstream `modbus-rs` browser Web Serial ASCII transport.
37
+ * @see requestSerialPort — Obtains the serial port handle this service's `port` option needs.
38
+ * @see makeTransportScoped — Generic lifecycle logic from shared-transport.
39
+ */
40
+ export declare class WasmAsciiTransportService extends WasmAsciiTransportService_base {
41
+ /**
42
+ * Creates a {@link Layer} providing an in-memory mock
43
+ * {@link WasmAsciiTransportService} for testing or development.
44
+ *
45
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
46
+ * simulated Modbus slaves and their register/coil maps.
47
+ *
48
+ * @param devices - Slave device definitions for the mock.
49
+ * @returns A function that takes {@link WasmAsciiTransportOpenOptions} and
50
+ * returns a scoped {@link Layer} providing the mock service.
51
+ *
52
+ * @see makeMockTransport — The underlying mock factory.
53
+ */
54
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmAsciiTransportOpenOptions) => Layer.Layer<WasmAsciiTransportService, never, never>;
55
+ }
56
+ export {};
@@ -0,0 +1,56 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import type { WasmSerialPortHandle, WasmSerialTransportOptions } from 'modbus-rs/web';
3
+ import { SlaveDeviceDefinitions } from './mocks';
4
+ /**
5
+ * Options for {@link WasmRtuTransportService}. `WasmRtuTransport.open()` takes the
6
+ * serial port handle and the connection options as two separate arguments; this
7
+ * combines them into one object so it fits {@link makeTransportScoped}'s single-options
8
+ * shape, with `port` destructured back out inside the service's `openMethod`.
9
+ *
10
+ * @see requestSerialPort — Obtains the `port` handle (must be called from a user gesture).
11
+ */
12
+ export type WasmRtuTransportOpenOptions = WasmSerialTransportOptions & {
13
+ port: WasmSerialPortHandle;
14
+ };
15
+ declare const WasmRtuTransportService_base: Effect.Service.Class<WasmRtuTransportService, "WasmRtuTransportService", {
16
+ readonly scoped: (options: WasmRtuTransportOpenOptions) => Effect.Effect<{
17
+ withClient: (unitId: number) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
18
+ setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
19
+ clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
20
+ reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
21
+ close: () => Effect.Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
22
+ hasPendingRequests: () => boolean;
23
+ }, never, import("effect/Scope").Scope>;
24
+ }>;
25
+ /**
26
+ * Scoped Effect service wrapping `modbus-rs`'s browser {@link WasmRtuTransport}
27
+ * for Modbus RTU over the Web Serial API.
28
+ *
29
+ * The transport connection is opened lazily on the first call to
30
+ * `withClient(unitId)` and automatically closed when the consuming
31
+ * {@link Effect.Scope | Scope} finalizes.
32
+ *
33
+ * Clients are created per `unitId` via {@link WasmRtuTransport.createClient} and
34
+ * cached, so repeated requests for the same unit ID reuse the same client.
35
+ *
36
+ * @see WasmRtuTransport — Upstream `modbus-rs` browser Web Serial RTU transport.
37
+ * @see requestSerialPort — Obtains the serial port handle this service's `port` option needs.
38
+ * @see makeTransportScoped — Generic lifecycle logic from shared-transport.
39
+ */
40
+ export declare class WasmRtuTransportService extends WasmRtuTransportService_base {
41
+ /**
42
+ * Creates a {@link Layer} providing an in-memory mock
43
+ * {@link WasmRtuTransportService} for testing or development.
44
+ *
45
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
46
+ * simulated Modbus slaves and their register/coil maps.
47
+ *
48
+ * @param devices - Slave device definitions for the mock.
49
+ * @returns A function that takes {@link WasmRtuTransportOpenOptions} and
50
+ * returns a scoped {@link Layer} providing the mock service.
51
+ *
52
+ * @see makeMockTransport — The underlying mock factory.
53
+ */
54
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmRtuTransportOpenOptions) => Layer.Layer<WasmRtuTransportService, never, never>;
55
+ }
56
+ export {};
@@ -0,0 +1,54 @@
1
+ import { Layer } from 'effect';
2
+ import type { ServerHandlers } from 'modbus-rs';
3
+ import type { WasmSerialServerOptions } from 'modbus-rs/web';
4
+ import type { ModbusError } from './errors';
5
+ /**
6
+ * A scoped {@link Layer} that starts a browser Modbus RTU server over the Web
7
+ * Serial API (experimental upstream surface).
8
+ *
9
+ * `options.serialPort` is the raw `SerialPort` object obtained from the
10
+ * consumer's own app code via `navigator.serial.requestPort()` (which has the
11
+ * `dom` lib types available) — **not** this package's {@link requestSerialPort}
12
+ * helper, which returns the `WasmSerialPortHandle` wrapper used only by the
13
+ * client-side transports (`WasmRtuTransportService`/`WasmAsciiTransportService`).
14
+ *
15
+ * Like {@link wasmWsServerLayer}, the WASM server requires a continuously-awaited
16
+ * `serve()` call to drive its request loop; this layer forks that call into the
17
+ * scope automatically so the returned `Layer` "just works".
18
+ *
19
+ * @param options - Serial port, baud rate, unit ID, etc.
20
+ * @param handlers - Callback functions that handle incoming Modbus requests
21
+ * (same {@link ServerHandlers} shape as the native TCP/serial servers).
22
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { Effect, Layer } from "effect";
27
+ * import { wasmSerialRtuServerLayer } from "@flux-control/effect-modbus-rs";
28
+ *
29
+ * const port = await navigator.serial.requestPort(); // user-gesture gated
30
+ * const ServerLive = wasmSerialRtuServerLayer(
31
+ * { serialPort: port, unitId: 1, baudRate: 19200 },
32
+ * { onReadCoils: (req) => [false, false] },
33
+ * );
34
+ *
35
+ * Layer.launch(ServerLive).pipe(Effect.runPromise);
36
+ * ```
37
+ *
38
+ * @see WasmSerialServerOptions — Options accepted by the upstream WASM serial server.
39
+ * @see ServerHandlers — Interface for request handler callbacks.
40
+ */
41
+ export declare const wasmSerialRtuServerLayer: (options: WasmSerialServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
42
+ /**
43
+ * A scoped {@link Layer} that starts a browser Modbus ASCII server over the Web
44
+ * Serial API. See {@link wasmSerialRtuServerLayer} for shared details (the
45
+ * `serialPort` source, and the `serve()`-forking behavior).
46
+ *
47
+ * @param options - Serial port, baud rate, unit ID, etc.
48
+ * @param handlers - Callback functions that handle incoming Modbus requests.
49
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
50
+ *
51
+ * @see WasmSerialServerOptions — Options accepted by the upstream WASM serial server.
52
+ * @see ServerHandlers — Interface for request handler callbacks.
53
+ */
54
+ export declare const wasmSerialAsciiServerLayer: (options: WasmSerialServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
@@ -0,0 +1,27 @@
1
+ import { Effect } from 'effect';
2
+ import type { WasmSerialPortHandle } from 'modbus-rs/web';
3
+ import type { ModbusError } from './errors';
4
+ /**
5
+ * Requests a browser serial port handle via the Web Serial API, for use with
6
+ * {@link WasmSerialTransportService.fromRtu} / `.fromAscii` (or
7
+ * `WasmRtuTransportService.Default` / `WasmAsciiTransportService.Default` directly).
8
+ *
9
+ * **Must be called synchronously from within a user-gesture event handler**
10
+ * (e.g. a `click` listener) — this is a hard Web Serial API / browser security
11
+ * constraint (`navigator.serial.requestPort()` semantics), not a library-imposed
12
+ * restriction. Calling it outside a gesture will reject.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * button.addEventListener("click", () => {
17
+ * Effect.runPromise(
18
+ * requestSerialPort().pipe(
19
+ * Effect.flatMap((port) => Effect.provide(program, WasmRtuTransportService.Default({ port, baudRate: 19200 }))),
20
+ * ),
21
+ * );
22
+ * });
23
+ * ```
24
+ *
25
+ * @see WasmSerialPortHandle — Opaque handle returned by `modbus-rs`'s WASM bindings.
26
+ */
27
+ export declare const requestSerialPort: () => Effect.Effect<WasmSerialPortHandle, ModbusError>;
@@ -0,0 +1,48 @@
1
+ import { Context, Layer } from 'effect';
2
+ import { type SlaveDeviceDefinitions } from './mocks';
3
+ import type { TransportServiceApi } from './shared-transport';
4
+ import { type WasmAsciiTransportOpenOptions } from './WasmAsciiTransportService';
5
+ import { type WasmRtuTransportOpenOptions } from './WasmRtuTransportService';
6
+ declare const WasmSerialTransportService_base: Context.TagClass<WasmSerialTransportService, "WasmSerialTransportService", TransportServiceApi>;
7
+ /**
8
+ * Abstract browser (WASM) serial Modbus transport service tag.
9
+ *
10
+ * Represents a Web Serial-based Modbus transport backed by either ASCII or RTU
11
+ * framing. Use this tag when you need a browser serial transport but don't care
12
+ * about the specific framing protocol.
13
+ *
14
+ * Consumers `yield* WasmSerialTransportService` to obtain a
15
+ * {@link TransportServiceApi} and satisfy the tag via one of the static
16
+ * provider methods:
17
+ *
18
+ * ```ts
19
+ * // Provide with ASCII framing
20
+ * Layer.provide(WasmSerialTransportService.fromAscii({ port, baudRate: 9600 }))
21
+ *
22
+ * // Provide with RTU framing
23
+ * Layer.provide(WasmSerialTransportService.fromRtu({ port, baudRate: 9600 }))
24
+ * ```
25
+ *
26
+ * @see requestSerialPort — Obtains the `port` handle both providers need (must be called from a user gesture).
27
+ */
28
+ export declare class WasmSerialTransportService extends WasmSerialTransportService_base {
29
+ /**
30
+ * Creates a {@link Layer} providing {@link WasmSerialTransportService}
31
+ * backed by an ASCII transport.
32
+ */
33
+ static fromAscii(options: WasmAsciiTransportOpenOptions): Layer.Layer<WasmSerialTransportService>;
34
+ /**
35
+ * Creates a {@link Layer} providing {@link WasmSerialTransportService}
36
+ * backed by an RTU transport.
37
+ */
38
+ static fromRtu(options: WasmRtuTransportOpenOptions): Layer.Layer<WasmSerialTransportService>;
39
+ /**
40
+ * Creates a mock {@link Layer} providing {@link WasmSerialTransportService}
41
+ * for testing or development.
42
+ *
43
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
44
+ * simulated Modbus slaves and their register/coil maps.
45
+ */
46
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmAsciiTransportOpenOptions | WasmRtuTransportOpenOptions) => Layer.Layer<WasmSerialTransportService>;
47
+ }
48
+ export {};
@@ -0,0 +1,38 @@
1
+ import { Layer } from 'effect';
2
+ import type { ServerHandlers } from 'modbus-rs';
3
+ import type { WasmTcpServerOptions } from 'modbus-rs/web';
4
+ import type { ModbusError } from './errors';
5
+ /**
6
+ * A scoped {@link Layer} that starts a browser Modbus server proxied over a
7
+ * WebSocket gateway (experimental upstream surface — browsers can't accept raw
8
+ * TCP connections, so this binds via `modbus-gateway` or an equivalent WS-to-TCP
9
+ * proxy).
10
+ *
11
+ * Unlike the native {@link tcpServerLayer}, the WASM server does not start
12
+ * serving on `bind()` — it requires an explicit, continuously-awaited `serve()`
13
+ * call to drive its request loop. This layer forks that call into the scope in
14
+ * the background so the returned `Layer` behaves the same as the native one
15
+ * from the consumer's perspective (no extra step needed).
16
+ *
17
+ * @param options - WebSocket gateway URL and unit ID.
18
+ * @param handlers - Callback functions that handle incoming Modbus requests
19
+ * (same {@link ServerHandlers} shape as the native TCP/serial servers).
20
+ * @returns A `Layer` that fails with {@link ModbusError} on bind failure.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { Effect, Layer } from "effect";
25
+ * import { wasmWsServerLayer } from "@flux-control/effect-modbus-rs";
26
+ *
27
+ * const ServerLive = wasmWsServerLayer(
28
+ * { wsUrl: "ws://localhost:8080", unitId: 1 },
29
+ * { onReadCoils: (req) => [false, false] },
30
+ * );
31
+ *
32
+ * Layer.launch(ServerLive).pipe(Effect.runPromise);
33
+ * ```
34
+ *
35
+ * @see WasmTcpServerOptions — Options accepted by the upstream WASM WS server.
36
+ * @see ServerHandlers — Interface for request handler callbacks.
37
+ */
38
+ export declare const wasmWsServerLayer: (options: WasmTcpServerOptions, handlers: ServerHandlers) => Layer.Layer<never, ModbusError>;
@@ -0,0 +1,45 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import type { WasmWsTransportOptions } from 'modbus-rs/web';
3
+ import { SlaveDeviceDefinitions } from './mocks';
4
+ declare const WasmWsTransportService_base: Effect.Service.Class<WasmWsTransportService, "WasmWsTransportService", {
5
+ readonly scoped: (options: WasmWsTransportOptions) => 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 `modbus-rs`'s browser {@link WasmWsTransport}
16
+ * for Modbus TCP over a WebSocket gateway (browsers can't open raw TCP sockets).
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 {@link WasmWsTransport.createClient} and
23
+ * cached, so repeated requests for the same unit ID reuse the same client.
24
+ *
25
+ * @see WasmWsTransport — Upstream `modbus-rs` browser WebSocket transport.
26
+ * @see WasmWsTransportOptions — Configuration for the WebSocket gateway connection.
27
+ * @see makeTransportScoped — Generic lifecycle logic from shared-transport.
28
+ */
29
+ export declare class WasmWsTransportService extends WasmWsTransportService_base {
30
+ /**
31
+ * Creates a {@link Layer} providing an in-memory mock
32
+ * {@link WasmWsTransportService} for testing or development.
33
+ *
34
+ * Accepts an array of {@link SlaveDeviceDefinition} describing the
35
+ * simulated Modbus slaves and their register/coil maps.
36
+ *
37
+ * @param devices - Slave device definitions for the mock.
38
+ * @returns A function that takes {@link WasmWsTransportOptions} and
39
+ * returns a scoped {@link Layer} providing the mock service.
40
+ *
41
+ * @see makeMockTransport — The underlying mock factory.
42
+ */
43
+ static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmWsTransportOptions) => Layer.Layer<WasmWsTransportService, never, never>;
44
+ }
45
+ export {};
@@ -1,7 +1,8 @@
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";
1
+ import { Effect, Schema } from 'effect';
2
+ import { type AsciiTransportOptions, type RtuTransportOptions, type TcpTransportOptions } from 'modbus-rs';
3
+ import type { WasmWsTransportOptions, WasmSerialTransportOptions } from 'modbus-rs/web';
4
+ import { ModbusInvalidArgumentError, type ModbusError } from './errors';
5
+ import type { EffectModbusClient } from './modbus-client';
5
6
  /**
6
7
  * Schema for a single coil (digital output) definition.
7
8
  *
@@ -124,7 +125,7 @@ export type SlaveDeviceDefinitions = Schema.Schema.Type<typeof SlaveDeviceDefini
124
125
  * @returns A transport factory function that returns a scoped Effect
125
126
  * providing the mock transport.
126
127
  */
127
- export declare const makeMockTransport: (devices: SlaveDeviceDefinitions) => (_options: RtuTransportOptions | AsciiTransportOptions | TcpTransportOptions) => Effect.Effect<{
128
+ export declare const makeMockTransport: (devices: SlaveDeviceDefinitions) => (_options: RtuTransportOptions | AsciiTransportOptions | TcpTransportOptions | WasmWsTransportOptions | WasmSerialTransportOptions) => Effect.Effect<{
128
129
  withClient: (unitId: number) => Effect.Effect<EffectModbusClient, ModbusInvalidArgumentError, never>;
129
130
  setRequestTimeout: (_timeoutMs: number) => Effect.Effect<void, never, never>;
130
131
  clearRequestTimeout: () => Effect.Effect<void, never, never>;
@@ -1,13 +1,19 @@
1
- import type { ReadRegistersOptions, WriteSingleRegisterOptions, WriteMultipleRegistersOptions, ReadWriteMultipleRegistersOptions, ReadBitsOptions, WriteSingleCoilOptions, WriteMultipleCoilsOptions, ReadFifoQueueOptions, ReadFileRecordOptions, WriteFileRecordOptions, DiagnosticsOptions, ReadDeviceIdentificationOptions, FifoQueueResponse, DiagnosticsResponse, DeviceIdentificationResponse, AsyncSerialModbusClient, AsyncTcpModbusClient } from "modbus-rs";
2
- import { Effect } from "effect";
3
- import type { ModbusError } from "./errors";
4
- export type AnyModbusClient = AsyncSerialModbusClient | AsyncTcpModbusClient;
1
+ import { Effect } from 'effect';
2
+ import type { ReadRegistersOptions, WriteSingleRegisterOptions, WriteMultipleRegistersOptions, ReadWriteMultipleRegistersOptions, ReadBitsOptions, WriteSingleCoilOptions, WriteMultipleCoilsOptions, ReadFifoQueueOptions, ReadFileRecordOptions, WriteFileRecordOptions, DiagnosticsOptions, ReadDeviceIdentificationOptions, FifoQueueResponse, DiagnosticsResponse, DeviceIdentificationResponse, AsyncSerialModbusClient, AsyncTcpModbusClient, CoilState } from 'modbus-rs';
3
+ import type { WasmWsModbusClient, WasmSerialModbusClient } from 'modbus-rs/web';
4
+ import type { ModbusError } from './errors';
5
+ /** The two native (napi) clients — same method surface, sharing one factory. */
6
+ export type NativeModbusClient = AsyncSerialModbusClient | AsyncTcpModbusClient;
7
+ /** The two browser (WASM) clients — same method surface, sharing one factory. */
8
+ export type WasmModbusClient = WasmSerialModbusClient | WasmWsModbusClient;
9
+ /** Any client this package knows how to wrap into an {@link EffectModbusClient}. */
10
+ export type AnyModbusClient = NativeModbusClient | WasmModbusClient;
5
11
  /**
6
12
  * Effect-ified Modbus client wrapping a `modbus-rs` transport client.
7
13
  *
8
- * Each method delegates to the equivalent `AsyncSerialModbusClient` or
9
- * `AsyncTcpModbusClient` method, converting the Promise-based API into
10
- * an {@link Effect.Effect} with typed {@link ModbusError} failures.
14
+ * Each method delegates to the equivalent method on the underlying native
15
+ * or WASM client, converting the Promise-based API into an
16
+ * {@link Effect.Effect} with typed {@link ModbusError} failures.
11
17
  *
12
18
  * Thrown errors are classified using {@link toModbusError}, mapping
13
19
  * `modbus-rs` error codes (timeout, transport, exception, etc.) into
@@ -27,7 +33,7 @@ export interface EffectModbusClient {
27
33
  * @see ReadRegistersOptions — Options shape from `modbus-rs`.
28
34
  * @see AsyncSerialModbusClient.readHoldingRegisters — Upstream implementation.
29
35
  */
30
- readHoldingRegisters(opts: ReadRegistersOptions): Effect.Effect<number[], ModbusError>;
36
+ readHoldingRegisters(opts: ReadRegistersOptions): Effect.Effect<Uint16Array, ModbusError>;
31
37
  /**
32
38
  * Reads input registers from the Modbus device (FC04).
33
39
  *
@@ -37,7 +43,7 @@ export interface EffectModbusClient {
37
43
  * @see ReadRegistersOptions — Options shape from `modbus-rs`.
38
44
  * @see AsyncSerialModbusClient.readInputRegisters — Upstream implementation.
39
45
  */
40
- readInputRegisters(opts: ReadRegistersOptions): Effect.Effect<number[], ModbusError>;
46
+ readInputRegisters(opts: ReadRegistersOptions): Effect.Effect<Uint16Array, ModbusError>;
41
47
  /**
42
48
  * Writes a single holding register (FC06).
43
49
  *
@@ -67,7 +73,7 @@ export interface EffectModbusClient {
67
73
  *
68
74
  * @see ReadWriteMultipleRegistersOptions — Options shape from `modbus-rs`.
69
75
  */
70
- readWriteMultipleRegisters(opts: ReadWriteMultipleRegistersOptions): Effect.Effect<number[], ModbusError>;
76
+ readWriteMultipleRegisters(opts: ReadWriteMultipleRegistersOptions): Effect.Effect<Uint16Array, ModbusError>;
71
77
  /**
72
78
  * Reads coils (digital outputs) from the Modbus device (FC01).
73
79
  *
@@ -76,7 +82,7 @@ export interface EffectModbusClient {
76
82
  *
77
83
  * @see ReadBitsOptions — Options shape from `modbus-rs`.
78
84
  */
79
- readCoils(opts: ReadBitsOptions): Effect.Effect<boolean[], ModbusError>;
85
+ readCoils(opts: ReadBitsOptions): Effect.Effect<CoilState[], ModbusError>;
80
86
  /**
81
87
  * Writes a single coil (digital output) (FC05).
82
88
  *
@@ -103,7 +109,7 @@ export interface EffectModbusClient {
103
109
  *
104
110
  * @see ReadBitsOptions — Options shape from `modbus-rs`.
105
111
  */
106
- readDiscreteInputs(opts: ReadBitsOptions): Effect.Effect<boolean[], ModbusError>;
112
+ readDiscreteInputs(opts: ReadBitsOptions): Effect.Effect<CoilState[], ModbusError>;
107
113
  /**
108
114
  * Reads the FIFO queue from the Modbus device (FC24).
109
115
  *
@@ -122,7 +128,7 @@ export interface EffectModbusClient {
122
128
  *
123
129
  * @see ReadFileRecordOptions — Options shape from `modbus-rs`.
124
130
  */
125
- readFileRecord(opts: ReadFileRecordOptions): Effect.Effect<number[][], ModbusError>;
131
+ readFileRecord(opts: ReadFileRecordOptions): Effect.Effect<Uint16Array[], ModbusError>;
126
132
  /**
127
133
  * Writes file records to the Modbus device (FC21).
128
134
  *
@@ -162,21 +168,23 @@ export interface EffectModbusClient {
162
168
  readDeviceIdentification(opts: ReadDeviceIdentificationOptions): Effect.Effect<DeviceIdentificationResponse, ModbusError>;
163
169
  }
164
170
  /**
165
- * Wraps a raw `modbus-rs` client into an {@link EffectModbusClient}.
171
+ * Wraps a raw `modbus-rs` client — native (napi) or browser (WASM) — into an
172
+ * {@link EffectModbusClient}.
166
173
  *
167
174
  * Each method converts a Promise-based call from the upstream client
168
175
  * into an `Effect` via {@link Effect.tryPromise}, routing errors through
169
176
  * {@link toModbusError} for typed error discrimination.
170
177
  *
171
- * Accepts both serial (`AsyncSerialModbusClient`) and TCP
172
- * (`AsyncTcpModbusClient`) clients since they share the same method
173
- * signatures.
178
+ * The native and WASM clients share the same method surface (same options
179
+ * shapes, same resolved value shapes `CoilState[]`, full `FifoQueueResponse`,
180
+ * full `DeviceIdentificationResponse`), so one factory covers both; no
181
+ * transport-specific reshaping is needed.
174
182
  *
175
- * @param client - The upstream `modbus-rs` client instance.
183
+ * @param client - The upstream `modbus-rs` or `modbus-rs/web` client instance.
176
184
  * @returns An `EffectModbusClient` that can be used within Effect
177
185
  * workflows.
178
186
  *
179
- * @see AsyncSerialModbusClient — Upstream serial client API.
180
- * @see AsyncTcpModbusClient — Upstream TCP client API.
187
+ * @see AsyncSerialModbusClient — Upstream native serial client API.
188
+ * @see AsyncTcpModbusClient — Upstream native TCP client API.
181
189
  */
182
- export declare const makeEffectModbusClient: (client: AsyncSerialModbusClient | AsyncTcpModbusClient) => EffectModbusClient;
190
+ export declare const makeEffectModbusClient: (client: AnyModbusClient) => EffectModbusClient;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
- import { Effect, Scope } from "effect";
2
- import { type ModbusError, ModbusNotConnectedError } from "./errors";
3
- import { type AnyModbusClient, type EffectModbusClient } from "./modbus-client";
1
+ import { Effect, Scope } from 'effect';
2
+ import { type ModbusError, ModbusNotConnectedError } from './errors';
3
+ import { type AnyModbusClient, type EffectModbusClient } from './modbus-client';
4
4
  /**
5
5
  * Shared API surface that every transport service exposes to consumers.
6
6
  *
@@ -51,9 +51,13 @@ interface TransportHandle<TClient> {
51
51
  * @param openMethod - A function that takes the transport constructor and options,
52
52
  * returning a promise for the opened transport.
53
53
  * @param serviceName - Logical name used in log messages and the finalizer guard.
54
+ * @param config - Optional module specifier override for browser WASM transports.
54
55
  * @returns An `Effect` that produces a {@link TransportServiceApi}.
55
56
  */
56
- export declare function makeTransportScoped<TOptions, TClient extends AnyModbusClient, TTransport extends TransportHandle<TClient>>(transportKey: string, openMethod: (TC: unknown, options: TOptions) => Promise<TTransport>, serviceName: string): (options: TOptions) => Effect.Effect<{
57
+ export declare function makeTransportScoped<TOptions, TClient extends AnyModbusClient, TTransport extends TransportHandle<TClient>>(transportKey: string, openMethod: (TC: unknown, options: TOptions) => Promise<TTransport>, serviceName: string, config?: {
58
+ /** Which `modbus-rs` conditional export to import from. Defaults to `"modbus-rs"` (native). */
59
+ moduleSpecifier?: 'modbus-rs' | 'modbus-rs/web';
60
+ }): (options: TOptions) => Effect.Effect<{
57
61
  withClient: (unitId: number) => Effect.Effect<EffectModbusClient, ModbusError, never>;
58
62
  setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, ModbusNotConnectedError, never>;
59
63
  clearRequestTimeout: () => Effect.Effect<undefined, ModbusNotConnectedError, never>;
@@ -0,0 +1 @@
1
+ export {};