@flux-control/effect-modbus-rs 0.1.1 → 0.3.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.
- package/README.md +344 -87
- package/dist/index.d.ts +85 -11
- package/dist/index.js +576 -280
- package/dist/src/AsciiTransportService.d.ts +29 -8
- package/dist/src/RtuTransportService.d.ts +29 -8
- package/dist/src/SerialModbusServerService.d.ts +5 -5
- package/dist/src/SerialTransportService.d.ts +8 -7
- package/dist/src/TcpGatewayService.d.ts +4 -4
- package/dist/src/TcpModbusServerService.d.ts +4 -4
- package/dist/src/TcpTransportService.d.ts +29 -8
- package/dist/src/WasmAsciiTransportService.d.ts +73 -0
- package/dist/src/WasmRtuTransportService.d.ts +73 -0
- package/dist/src/WasmSerialModbusServerService.d.ts +54 -0
- package/dist/src/WasmSerialPort.d.ts +27 -0
- package/dist/src/WasmSerialTransportService.d.ts +48 -0
- package/dist/src/WasmTcpServerService.d.ts +38 -0
- package/dist/src/WasmWsTransportService.d.ts +60 -0
- package/dist/src/connection.d.ts +170 -0
- package/dist/src/errors.d.ts +25 -1
- package/dist/src/mocks.d.ts +49 -9
- package/dist/src/modbus-client.d.ts +82 -23
- package/dist/src/modbus-client.wasm.test.d.ts +1 -0
- package/dist/src/resilience.test.d.ts +1 -0
- package/dist/src/retry.d.ts +227 -0
- package/dist/src/retry.test.d.ts +1 -0
- package/dist/src/shared-transport.d.ts +113 -8
- package/dist/src/shared-transport.test.d.ts +1 -0
- package/dist/src/upstream-options.test.d.ts +1 -0
- package/dist/src/wasm-mocks.test.d.ts +1 -0
- package/package.json +24 -17
|
@@ -1,9 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { SlaveDeviceDefinitions } from
|
|
1
|
+
import { Effect, Layer } from 'effect';
|
|
2
|
+
import type { AsciiTransportOptions } from 'modbus-rs';
|
|
3
|
+
import { SlaveDeviceDefinitions } from './mocks';
|
|
4
|
+
import type { MockFaultOptions } from './mocks';
|
|
5
|
+
import type { TransportResilienceOptions, WithoutUpstreamRetry } from './shared-transport';
|
|
6
|
+
/**
|
|
7
|
+
* {@link AsciiTransportOptions} minus the upstream retry knobs.
|
|
8
|
+
*
|
|
9
|
+
* @see WithoutUpstreamRetry — Why they are withheld.
|
|
10
|
+
*/
|
|
11
|
+
export type AsciiTransportOpenOptions = WithoutUpstreamRetry<AsciiTransportOptions>;
|
|
4
12
|
declare const AsciiTransportService_base: Effect.Service.Class<AsciiTransportService, "AsciiTransportService", {
|
|
5
|
-
readonly scoped: (options:
|
|
6
|
-
|
|
13
|
+
readonly scoped: (options: AsciiTransportOpenOptions & TransportResilienceOptions) => Effect.Effect<{
|
|
14
|
+
connectionState: import("effect/SubscriptionRef").SubscriptionRef<{
|
|
15
|
+
readonly _tag: "Connected";
|
|
16
|
+
} | {
|
|
17
|
+
readonly _tag: "Disconnected";
|
|
18
|
+
} | {
|
|
19
|
+
readonly _tag: "Down";
|
|
20
|
+
readonly cause: import("./errors").ModbusError;
|
|
21
|
+
} | {
|
|
22
|
+
readonly _tag: "Reconnecting";
|
|
23
|
+
readonly attempt: number;
|
|
24
|
+
}>;
|
|
25
|
+
withClient: (unitId: number, clientOptions?: {
|
|
26
|
+
readonly retry?: import("./retry").ModbusRetryPolicy;
|
|
27
|
+
} | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
|
|
7
28
|
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
8
29
|
clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
9
30
|
reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
|
|
@@ -24,7 +45,7 @@ declare const AsciiTransportService_base: Effect.Service.Class<AsciiTransportSer
|
|
|
24
45
|
* requests for the same unit ID reuse the same client.
|
|
25
46
|
*
|
|
26
47
|
* @see AsyncAsciiTransport — Upstream `modbus-rs` ASCII transport.
|
|
27
|
-
* @see
|
|
48
|
+
* @see AsciiTransportOpenOptions — Configuration for the ASCII serial port.
|
|
28
49
|
* @see makeTransportScoped — Generic lifecycle logic from shared-transport.
|
|
29
50
|
*/
|
|
30
51
|
export declare class AsciiTransportService extends AsciiTransportService_base {
|
|
@@ -36,11 +57,11 @@ export declare class AsciiTransportService extends AsciiTransportService_base {
|
|
|
36
57
|
* simulated Modbus slaves and their register/coil maps.
|
|
37
58
|
*
|
|
38
59
|
* @param devices - Slave device definitions for the mock.
|
|
39
|
-
* @returns A function that takes {@link
|
|
60
|
+
* @returns A function that takes {@link AsciiTransportOpenOptions} and
|
|
40
61
|
* returns a scoped {@link Layer} providing the mock service.
|
|
41
62
|
*
|
|
42
63
|
* @see makeMockTransport — The underlying mock factory.
|
|
43
64
|
*/
|
|
44
|
-
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options:
|
|
65
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: AsciiTransportOpenOptions & TransportResilienceOptions & MockFaultOptions) => Layer.Layer<AsciiTransportService, never, never>;
|
|
45
66
|
}
|
|
46
67
|
export {};
|
|
@@ -1,9 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
1
|
+
import { Effect, Layer } from 'effect';
|
|
2
|
+
import type { RtuTransportOptions } from 'modbus-rs';
|
|
3
|
+
import type { MockFaultOptions } from './mocks';
|
|
4
|
+
import type { SlaveDeviceDefinitions } from './mocks';
|
|
5
|
+
import type { TransportResilienceOptions, WithoutUpstreamRetry } from './shared-transport';
|
|
6
|
+
/**
|
|
7
|
+
* {@link RtuTransportOptions} minus the upstream retry knobs.
|
|
8
|
+
*
|
|
9
|
+
* @see WithoutUpstreamRetry — Why they are withheld.
|
|
10
|
+
*/
|
|
11
|
+
export type RtuTransportOpenOptions = WithoutUpstreamRetry<RtuTransportOptions>;
|
|
4
12
|
declare const RtuTransportService_base: Effect.Service.Class<RtuTransportService, "RtuTransportService", {
|
|
5
|
-
readonly scoped: (options:
|
|
6
|
-
|
|
13
|
+
readonly scoped: (options: RtuTransportOpenOptions & TransportResilienceOptions) => Effect.Effect<{
|
|
14
|
+
connectionState: import("effect/SubscriptionRef").SubscriptionRef<{
|
|
15
|
+
readonly _tag: "Connected";
|
|
16
|
+
} | {
|
|
17
|
+
readonly _tag: "Disconnected";
|
|
18
|
+
} | {
|
|
19
|
+
readonly _tag: "Down";
|
|
20
|
+
readonly cause: import("./errors").ModbusError;
|
|
21
|
+
} | {
|
|
22
|
+
readonly _tag: "Reconnecting";
|
|
23
|
+
readonly attempt: number;
|
|
24
|
+
}>;
|
|
25
|
+
withClient: (unitId: number, clientOptions?: {
|
|
26
|
+
readonly retry?: import("./retry").ModbusRetryPolicy;
|
|
27
|
+
} | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
|
|
7
28
|
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
8
29
|
clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
9
30
|
reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
|
|
@@ -24,7 +45,7 @@ declare const RtuTransportService_base: Effect.Service.Class<RtuTransportService
|
|
|
24
45
|
* requests for the same unit ID reuse the same client.
|
|
25
46
|
*
|
|
26
47
|
* @see AsyncRtuTransport — Upstream `modbus-rs` RTU transport.
|
|
27
|
-
* @see
|
|
48
|
+
* @see RtuTransportOpenOptions — Configuration for the RTU serial port.
|
|
28
49
|
* @see makeTransportScoped — Generic lifecycle logic from shared-transport.
|
|
29
50
|
*/
|
|
30
51
|
export declare class RtuTransportService extends RtuTransportService_base {
|
|
@@ -36,11 +57,11 @@ export declare class RtuTransportService extends RtuTransportService_base {
|
|
|
36
57
|
* simulated Modbus slaves and their register/coil maps.
|
|
37
58
|
*
|
|
38
59
|
* @param devices - Slave device definitions for the mock.
|
|
39
|
-
* @returns A function that takes {@link
|
|
60
|
+
* @returns A function that takes {@link RtuTransportOpenOptions} and
|
|
40
61
|
* returns a scoped {@link Layer} providing the mock service.
|
|
41
62
|
*
|
|
42
63
|
* @see makeMockTransport — The underlying mock factory.
|
|
43
64
|
*/
|
|
44
|
-
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options:
|
|
65
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: RtuTransportOpenOptions & TransportResilienceOptions & MockFaultOptions) => Layer.Layer<RtuTransportService, never, never>;
|
|
45
66
|
}
|
|
46
67
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { ModbusError } from
|
|
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,8 @@
|
|
|
1
|
-
import { Context, Layer } from
|
|
2
|
-
import
|
|
3
|
-
import type
|
|
4
|
-
import { type
|
|
1
|
+
import { Context, Layer } from 'effect';
|
|
2
|
+
import { type AsciiTransportOpenOptions } from './AsciiTransportService';
|
|
3
|
+
import { type SlaveDeviceDefinitions } from './mocks';
|
|
4
|
+
import { type RtuTransportOpenOptions } from './RtuTransportService';
|
|
5
|
+
import type { TransportResilienceOptions, TransportServiceApi } from './shared-transport';
|
|
5
6
|
declare const SerialTransportService_base: Context.TagClass<SerialTransportService, "SerialTransportService", TransportServiceApi>;
|
|
6
7
|
/**
|
|
7
8
|
* Abstract serial Modbus transport service tag.
|
|
@@ -27,12 +28,12 @@ export declare class SerialTransportService extends SerialTransportService_base
|
|
|
27
28
|
* Creates a {@link Layer} providing {@link SerialTransportService}
|
|
28
29
|
* backed by an ASCII transport.
|
|
29
30
|
*/
|
|
30
|
-
static fromAscii(options:
|
|
31
|
+
static fromAscii(options: AsciiTransportOpenOptions & TransportResilienceOptions): Layer.Layer<SerialTransportService>;
|
|
31
32
|
/**
|
|
32
33
|
* Creates a {@link Layer} providing {@link SerialTransportService}
|
|
33
34
|
* backed by an RTU transport.
|
|
34
35
|
*/
|
|
35
|
-
static fromRtu(options:
|
|
36
|
+
static fromRtu(options: RtuTransportOpenOptions & TransportResilienceOptions): Layer.Layer<SerialTransportService>;
|
|
36
37
|
/**
|
|
37
38
|
* Creates a mock {@link Layer} providing {@link SerialTransportService}
|
|
38
39
|
* for testing or development.
|
|
@@ -40,6 +41,6 @@ export declare class SerialTransportService extends SerialTransportService_base
|
|
|
40
41
|
* Accepts an array of {@link SlaveDeviceDefinition} describing the
|
|
41
42
|
* simulated Modbus slaves and their register/coil maps.
|
|
42
43
|
*/
|
|
43
|
-
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options:
|
|
44
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: (AsciiTransportOpenOptions | RtuTransportOpenOptions) & TransportResilienceOptions) => Layer.Layer<SerialTransportService>;
|
|
44
45
|
}
|
|
45
46
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { ModbusError } from
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
import type { ModbusError } from
|
|
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,9 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { SlaveDeviceDefinitions } from
|
|
1
|
+
import { Effect, Layer } from 'effect';
|
|
2
|
+
import type { TcpTransportOptions } from 'modbus-rs';
|
|
3
|
+
import { SlaveDeviceDefinitions } from './mocks';
|
|
4
|
+
import type { MockFaultOptions } from './mocks';
|
|
5
|
+
import type { TransportResilienceOptions, WithoutUpstreamRetry } from './shared-transport';
|
|
6
|
+
/**
|
|
7
|
+
* {@link TcpTransportOptions} minus the upstream retry knobs.
|
|
8
|
+
*
|
|
9
|
+
* @see WithoutUpstreamRetry — Why they are withheld.
|
|
10
|
+
*/
|
|
11
|
+
export type TcpTransportOpenOptions = WithoutUpstreamRetry<TcpTransportOptions>;
|
|
4
12
|
declare const TcpTransportService_base: Effect.Service.Class<TcpTransportService, "TcpTransportService", {
|
|
5
|
-
readonly scoped: (options:
|
|
6
|
-
|
|
13
|
+
readonly scoped: (options: TcpTransportOpenOptions & TransportResilienceOptions) => Effect.Effect<{
|
|
14
|
+
connectionState: import("effect/SubscriptionRef").SubscriptionRef<{
|
|
15
|
+
readonly _tag: "Connected";
|
|
16
|
+
} | {
|
|
17
|
+
readonly _tag: "Disconnected";
|
|
18
|
+
} | {
|
|
19
|
+
readonly _tag: "Down";
|
|
20
|
+
readonly cause: import("./errors").ModbusError;
|
|
21
|
+
} | {
|
|
22
|
+
readonly _tag: "Reconnecting";
|
|
23
|
+
readonly attempt: number;
|
|
24
|
+
}>;
|
|
25
|
+
withClient: (unitId: number, clientOptions?: {
|
|
26
|
+
readonly retry?: import("./retry").ModbusRetryPolicy;
|
|
27
|
+
} | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
|
|
7
28
|
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
8
29
|
clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
9
30
|
reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
|
|
@@ -24,7 +45,7 @@ declare const TcpTransportService_base: Effect.Service.Class<TcpTransportService
|
|
|
24
45
|
* requests for the same unit ID reuse the same client.
|
|
25
46
|
*
|
|
26
47
|
* @see AsyncTcpTransport — Upstream `modbus-rs` TCP transport.
|
|
27
|
-
* @see
|
|
48
|
+
* @see TcpTransportOpenOptions — Configuration for the TCP connection.
|
|
28
49
|
* @see makeTransportScoped — Generic lifecycle logic from shared-transport.
|
|
29
50
|
*/
|
|
30
51
|
export declare class TcpTransportService extends TcpTransportService_base {
|
|
@@ -36,11 +57,11 @@ export declare class TcpTransportService extends TcpTransportService_base {
|
|
|
36
57
|
* simulated Modbus slaves and their register/coil maps.
|
|
37
58
|
*
|
|
38
59
|
* @param devices - Slave device definitions for the mock.
|
|
39
|
-
* @returns A function that takes {@link
|
|
60
|
+
* @returns A function that takes {@link TcpTransportOpenOptions} and
|
|
40
61
|
* returns a scoped {@link Layer} providing the mock service.
|
|
41
62
|
*
|
|
42
63
|
* @see makeMockTransport — The underlying mock factory.
|
|
43
64
|
*/
|
|
44
|
-
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options:
|
|
65
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: TcpTransportOpenOptions & TransportResilienceOptions & MockFaultOptions) => Layer.Layer<TcpTransportService, never, never>;
|
|
45
66
|
}
|
|
46
67
|
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Effect, Layer } from 'effect';
|
|
2
|
+
import type { WasmSerialPortHandle, WasmSerialTransportOptions } from 'modbus-rs/web';
|
|
3
|
+
import { SlaveDeviceDefinitions } from './mocks';
|
|
4
|
+
import type { MockFaultOptions } from './mocks';
|
|
5
|
+
import type { TransportResilienceOptions } from './shared-transport';
|
|
6
|
+
/**
|
|
7
|
+
* Options for {@link WasmAsciiTransportService}. `WasmAsciiTransport.open()` takes the
|
|
8
|
+
* serial port handle and the connection options as two separate arguments; this
|
|
9
|
+
* combines them into one object so it fits {@link makeTransportScoped}'s single-options
|
|
10
|
+
* shape, with `port` destructured back out inside the service's `openMethod`.
|
|
11
|
+
*
|
|
12
|
+
* @see requestSerialPort — Obtains the `port` handle (must be called from a user gesture).
|
|
13
|
+
*/
|
|
14
|
+
export type WasmAsciiTransportOpenOptions = WasmSerialTransportOptions & {
|
|
15
|
+
port: WasmSerialPortHandle;
|
|
16
|
+
};
|
|
17
|
+
declare const WasmAsciiTransportService_base: Effect.Service.Class<WasmAsciiTransportService, "WasmAsciiTransportService", {
|
|
18
|
+
readonly scoped: (options: WasmSerialTransportOptions & {
|
|
19
|
+
port: WasmSerialPortHandle;
|
|
20
|
+
} & TransportResilienceOptions) => Effect.Effect<{
|
|
21
|
+
connectionState: import("effect/SubscriptionRef").SubscriptionRef<{
|
|
22
|
+
readonly _tag: "Connected";
|
|
23
|
+
} | {
|
|
24
|
+
readonly _tag: "Disconnected";
|
|
25
|
+
} | {
|
|
26
|
+
readonly _tag: "Down";
|
|
27
|
+
readonly cause: import("./errors").ModbusError;
|
|
28
|
+
} | {
|
|
29
|
+
readonly _tag: "Reconnecting";
|
|
30
|
+
readonly attempt: number;
|
|
31
|
+
}>;
|
|
32
|
+
withClient: (unitId: number, clientOptions?: {
|
|
33
|
+
readonly retry?: import("./retry").ModbusRetryPolicy;
|
|
34
|
+
} | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
|
|
35
|
+
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
36
|
+
clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
37
|
+
reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
|
|
38
|
+
close: () => Effect.Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
|
|
39
|
+
hasPendingRequests: () => boolean;
|
|
40
|
+
}, never, import("effect/Scope").Scope>;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Scoped Effect service wrapping `modbus-rs`'s browser {@link WasmAsciiTransport}
|
|
44
|
+
* for Modbus ASCII over the Web Serial API.
|
|
45
|
+
*
|
|
46
|
+
* The transport connection is opened lazily on the first call to
|
|
47
|
+
* `withClient(unitId)` and automatically closed when the consuming
|
|
48
|
+
* {@link Effect.Scope | Scope} finalizes.
|
|
49
|
+
*
|
|
50
|
+
* Clients are created per `unitId` via {@link WasmAsciiTransport.createClient} and
|
|
51
|
+
* cached, so repeated requests for the same unit ID reuse the same client.
|
|
52
|
+
*
|
|
53
|
+
* @see WasmAsciiTransport — Upstream `modbus-rs` browser Web Serial ASCII transport.
|
|
54
|
+
* @see requestSerialPort — Obtains the serial port handle this service's `port` option needs.
|
|
55
|
+
* @see makeTransportScoped — Generic lifecycle logic from shared-transport.
|
|
56
|
+
*/
|
|
57
|
+
export declare class WasmAsciiTransportService extends WasmAsciiTransportService_base {
|
|
58
|
+
/**
|
|
59
|
+
* Creates a {@link Layer} providing an in-memory mock
|
|
60
|
+
* {@link WasmAsciiTransportService} for testing or development.
|
|
61
|
+
*
|
|
62
|
+
* Accepts an array of {@link SlaveDeviceDefinition} describing the
|
|
63
|
+
* simulated Modbus slaves and their register/coil maps.
|
|
64
|
+
*
|
|
65
|
+
* @param devices - Slave device definitions for the mock.
|
|
66
|
+
* @returns A function that takes {@link WasmAsciiTransportOpenOptions} and
|
|
67
|
+
* returns a scoped {@link Layer} providing the mock service.
|
|
68
|
+
*
|
|
69
|
+
* @see makeMockTransport — The underlying mock factory.
|
|
70
|
+
*/
|
|
71
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmAsciiTransportOpenOptions & TransportResilienceOptions & MockFaultOptions) => Layer.Layer<WasmAsciiTransportService, never, never>;
|
|
72
|
+
}
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Effect, Layer } from 'effect';
|
|
2
|
+
import type { WasmSerialPortHandle, WasmSerialTransportOptions } from 'modbus-rs/web';
|
|
3
|
+
import { SlaveDeviceDefinitions } from './mocks';
|
|
4
|
+
import type { MockFaultOptions } from './mocks';
|
|
5
|
+
import type { TransportResilienceOptions } from './shared-transport';
|
|
6
|
+
/**
|
|
7
|
+
* Options for {@link WasmRtuTransportService}. `WasmRtuTransport.open()` takes the
|
|
8
|
+
* serial port handle and the connection options as two separate arguments; this
|
|
9
|
+
* combines them into one object so it fits {@link makeTransportScoped}'s single-options
|
|
10
|
+
* shape, with `port` destructured back out inside the service's `openMethod`.
|
|
11
|
+
*
|
|
12
|
+
* @see requestSerialPort — Obtains the `port` handle (must be called from a user gesture).
|
|
13
|
+
*/
|
|
14
|
+
export type WasmRtuTransportOpenOptions = WasmSerialTransportOptions & {
|
|
15
|
+
port: WasmSerialPortHandle;
|
|
16
|
+
};
|
|
17
|
+
declare const WasmRtuTransportService_base: Effect.Service.Class<WasmRtuTransportService, "WasmRtuTransportService", {
|
|
18
|
+
readonly scoped: (options: WasmSerialTransportOptions & {
|
|
19
|
+
port: WasmSerialPortHandle;
|
|
20
|
+
} & TransportResilienceOptions) => Effect.Effect<{
|
|
21
|
+
connectionState: import("effect/SubscriptionRef").SubscriptionRef<{
|
|
22
|
+
readonly _tag: "Connected";
|
|
23
|
+
} | {
|
|
24
|
+
readonly _tag: "Disconnected";
|
|
25
|
+
} | {
|
|
26
|
+
readonly _tag: "Down";
|
|
27
|
+
readonly cause: import("./errors").ModbusError;
|
|
28
|
+
} | {
|
|
29
|
+
readonly _tag: "Reconnecting";
|
|
30
|
+
readonly attempt: number;
|
|
31
|
+
}>;
|
|
32
|
+
withClient: (unitId: number, clientOptions?: {
|
|
33
|
+
readonly retry?: import("./retry").ModbusRetryPolicy;
|
|
34
|
+
} | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, import("./errors").ModbusError, never>;
|
|
35
|
+
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
36
|
+
clearRequestTimeout: () => Effect.Effect<undefined, import("./errors").ModbusNotConnectedError, never>;
|
|
37
|
+
reconnect: () => Effect.Effect<undefined, import("./errors").ModbusError, never>;
|
|
38
|
+
close: () => Effect.Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
|
|
39
|
+
hasPendingRequests: () => boolean;
|
|
40
|
+
}, never, import("effect/Scope").Scope>;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Scoped Effect service wrapping `modbus-rs`'s browser {@link WasmRtuTransport}
|
|
44
|
+
* for Modbus RTU over the Web Serial API.
|
|
45
|
+
*
|
|
46
|
+
* The transport connection is opened lazily on the first call to
|
|
47
|
+
* `withClient(unitId)` and automatically closed when the consuming
|
|
48
|
+
* {@link Effect.Scope | Scope} finalizes.
|
|
49
|
+
*
|
|
50
|
+
* Clients are created per `unitId` via {@link WasmRtuTransport.createClient} and
|
|
51
|
+
* cached, so repeated requests for the same unit ID reuse the same client.
|
|
52
|
+
*
|
|
53
|
+
* @see WasmRtuTransport — Upstream `modbus-rs` browser Web Serial RTU transport.
|
|
54
|
+
* @see requestSerialPort — Obtains the serial port handle this service's `port` option needs.
|
|
55
|
+
* @see makeTransportScoped — Generic lifecycle logic from shared-transport.
|
|
56
|
+
*/
|
|
57
|
+
export declare class WasmRtuTransportService extends WasmRtuTransportService_base {
|
|
58
|
+
/**
|
|
59
|
+
* Creates a {@link Layer} providing an in-memory mock
|
|
60
|
+
* {@link WasmRtuTransportService} for testing or development.
|
|
61
|
+
*
|
|
62
|
+
* Accepts an array of {@link SlaveDeviceDefinition} describing the
|
|
63
|
+
* simulated Modbus slaves and their register/coil maps.
|
|
64
|
+
*
|
|
65
|
+
* @param devices - Slave device definitions for the mock.
|
|
66
|
+
* @returns A function that takes {@link WasmRtuTransportOpenOptions} and
|
|
67
|
+
* returns a scoped {@link Layer} providing the mock service.
|
|
68
|
+
*
|
|
69
|
+
* @see makeMockTransport — The underlying mock factory.
|
|
70
|
+
*/
|
|
71
|
+
static makeMockTransport: (devices: SlaveDeviceDefinitions) => (options: WasmRtuTransportOpenOptions & TransportResilienceOptions & MockFaultOptions) => Layer.Layer<WasmRtuTransportService, never, never>;
|
|
72
|
+
}
|
|
73
|
+
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>;
|