@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
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { Duration, Effect, Schedule } from 'effect';
|
|
2
|
+
import type { ModbusError } from './errors';
|
|
3
|
+
/**
|
|
4
|
+
* The `_tag` of every {@link ModbusError} variant.
|
|
5
|
+
*
|
|
6
|
+
* Used to key per-error retry behaviour in
|
|
7
|
+
* {@link ModbusRetryPolicyOptions.errors}.
|
|
8
|
+
*/
|
|
9
|
+
export type ModbusErrorTag = ModbusError['_tag'];
|
|
10
|
+
/**
|
|
11
|
+
* Backoff curve for a single error category.
|
|
12
|
+
*
|
|
13
|
+
* The delay before retry _n_ (zero-based) is
|
|
14
|
+
* `min(maxDelay, baseDelay * factor ** n)`, optionally jittered by the
|
|
15
|
+
* policy-level {@link ModbusRetryPolicyOptions.jitter | jitter} setting.
|
|
16
|
+
*
|
|
17
|
+
* @see Schedule.exponential — The equivalent built-in Effect schedule.
|
|
18
|
+
*/
|
|
19
|
+
export interface RetryDelayOptions {
|
|
20
|
+
/** Delay before the first retry. */
|
|
21
|
+
readonly baseDelay?: Duration.DurationInput;
|
|
22
|
+
/** Multiplier applied to the delay after each attempt. */
|
|
23
|
+
readonly factor?: number;
|
|
24
|
+
/** Upper bound on the delay, whatever the attempt count. */
|
|
25
|
+
readonly maxDelay?: Duration.DurationInput;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Per-error retry configuration.
|
|
29
|
+
*
|
|
30
|
+
* - `false` — never retry this error.
|
|
31
|
+
* - `true` — retry using the policy-level backoff curve.
|
|
32
|
+
* - {@link RetryDelayOptions} — retry using a curve specific to this error.
|
|
33
|
+
*/
|
|
34
|
+
export type RetryErrorOptions = boolean | RetryDelayOptions;
|
|
35
|
+
/**
|
|
36
|
+
* Options accepted by {@link makeRetryPolicy} and by every preset in
|
|
37
|
+
* {@link RetryPolicies}.
|
|
38
|
+
*
|
|
39
|
+
* Nothing here is applied automatically — a policy only takes effect once it is
|
|
40
|
+
* attached to a transport, to a client, or piped over an effect with
|
|
41
|
+
* {@link retryModbus}. Library defaults stay single-shot so that timing is
|
|
42
|
+
* predictable unless retries are explicitly opted into.
|
|
43
|
+
*
|
|
44
|
+
* These are **application-level** retries, and the only ones in play: the
|
|
45
|
+
* transport-level knobs `modbus-rs` offers are withheld from every transport
|
|
46
|
+
* constructor in this package, so the two layers cannot be combined by
|
|
47
|
+
* accident. See `UpstreamRetryOptionKey` in `src/shared-transport.ts`.
|
|
48
|
+
*/
|
|
49
|
+
export interface ModbusRetryPolicyOptions {
|
|
50
|
+
/** Maximum number of retries (attempts = `maxRetries + 1`). Default `3`. */
|
|
51
|
+
readonly maxRetries?: number;
|
|
52
|
+
/** Wall-clock budget for the whole retry sequence. Unbounded by default. */
|
|
53
|
+
readonly maxElapsed?: Duration.DurationInput;
|
|
54
|
+
/**
|
|
55
|
+
* Randomness applied to each delay, as a multiplier range.
|
|
56
|
+
*
|
|
57
|
+
* `true` (default) uses Effect's `0.8 – 1.2` range; `false` disables jitter;
|
|
58
|
+
* an object customises the range. Jitter keeps a fleet of pollers from
|
|
59
|
+
* re-hitting a recovering device in lockstep.
|
|
60
|
+
*
|
|
61
|
+
* @see Schedule.jitteredWith — The underlying combinator.
|
|
62
|
+
*/
|
|
63
|
+
readonly jitter?: boolean | {
|
|
64
|
+
readonly min?: number;
|
|
65
|
+
readonly max?: number;
|
|
66
|
+
};
|
|
67
|
+
/** Policy-level delay before the first retry. Default `100 millis`. */
|
|
68
|
+
readonly baseDelay?: Duration.DurationInput;
|
|
69
|
+
/** Policy-level backoff multiplier. Default `2`. */
|
|
70
|
+
readonly factor?: number;
|
|
71
|
+
/** Policy-level delay ceiling. Default `5 seconds`. */
|
|
72
|
+
readonly maxDelay?: Duration.DurationInput;
|
|
73
|
+
/**
|
|
74
|
+
* Which {@link ModbusError} variants are retryable, with optional
|
|
75
|
+
* per-error backoff overrides.
|
|
76
|
+
*
|
|
77
|
+
* Defaults retry the errors that a healthy bus recovers from on its own —
|
|
78
|
+
* {@link ModbusTimeoutError}, {@link ModbusTransportError},
|
|
79
|
+
* {@link ModbusConnectionClosedError}, and the transient exception codes in
|
|
80
|
+
* {@link retryableExceptionCodes} — and never retry
|
|
81
|
+
* {@link ModbusInvalidArgumentError}, {@link ModbusNotConnectedError}, or
|
|
82
|
+
* {@link ModbusInternalError}.
|
|
83
|
+
*/
|
|
84
|
+
readonly errors?: Partial<Record<ModbusErrorTag, RetryErrorOptions>>;
|
|
85
|
+
/**
|
|
86
|
+
* Modbus exception codes worth retrying when the device answers with an
|
|
87
|
+
* exception response. Default {@link retryableExceptionCodes}.
|
|
88
|
+
*
|
|
89
|
+
* Only consulted when `ModbusExceptionError` is retryable at all.
|
|
90
|
+
*/
|
|
91
|
+
readonly retryableExceptions?: ReadonlyArray<number>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A resolved retry policy: a schedule plus the predicates that produced it.
|
|
95
|
+
*
|
|
96
|
+
* Produced by {@link makeRetryPolicy} or a {@link RetryPolicies} preset, and
|
|
97
|
+
* attached to a transport or client (or piped with {@link retryModbus}). The
|
|
98
|
+
* `schedule` is a plain Effect `Schedule`, so it can also be handed straight
|
|
99
|
+
* to `Effect.retry`, `Effect.repeat`, or `Stream.retry`.
|
|
100
|
+
*/
|
|
101
|
+
export interface ModbusRetryPolicy {
|
|
102
|
+
/**
|
|
103
|
+
* Schedule driving the retries. Its input is the failing {@link ModbusError},
|
|
104
|
+
* its output the `[retryIndex, error]` pair that produced the delay.
|
|
105
|
+
*/
|
|
106
|
+
readonly schedule: Schedule.Schedule<[number, ModbusError], ModbusError>;
|
|
107
|
+
/** Whether this policy retries the given error at all. */
|
|
108
|
+
readonly isRetryable: (error: ModbusError) => boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Modbus exception codes retried by default.
|
|
112
|
+
*
|
|
113
|
+
* These are the codes that mean "ask again later" rather than "your request is
|
|
114
|
+
* wrong": `5` ACKNOWLEDGE, `6` SERVER_DEVICE_BUSY,
|
|
115
|
+
* `10` GATEWAY_PATH_UNAVAILABLE, `11` GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND.
|
|
116
|
+
*
|
|
117
|
+
* Codes such as `1` ILLEGAL_FUNCTION, `2` ILLEGAL_DATA_ADDRESS, and
|
|
118
|
+
* `3` ILLEGAL_DATA_VALUE are deterministic — retrying them only adds bus
|
|
119
|
+
* traffic and latency.
|
|
120
|
+
*/
|
|
121
|
+
export declare const retryableExceptionCodes: ReadonlyArray<number>;
|
|
122
|
+
/**
|
|
123
|
+
* Builds a {@link ModbusRetryPolicy} from {@link ModbusRetryPolicyOptions}.
|
|
124
|
+
*
|
|
125
|
+
* The resulting schedule is exponential, jittered, capped per error category,
|
|
126
|
+
* and bounded by `maxRetries` (and `maxElapsed`, when set). The retry budget is
|
|
127
|
+
* shared across error categories — only the delay curve is per-error — so an
|
|
128
|
+
* operation that fails with a mix of timeouts and transport errors still stops
|
|
129
|
+
* after `maxRetries` retries.
|
|
130
|
+
*
|
|
131
|
+
* @param options - Policy configuration. Defaults to a general-purpose policy:
|
|
132
|
+
* 3 retries, `100 millis` base, factor `2`, `5 seconds` ceiling, jittered.
|
|
133
|
+
* @returns A resolved policy for a transport, a client, or {@link retryModbus}.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const policy = makeRetryPolicy({
|
|
138
|
+
* maxRetries: 5,
|
|
139
|
+
* baseDelay: "50 millis",
|
|
140
|
+
* errors: { ModbusExceptionError: false },
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* @see RetryPolicies — Ready-made templates built on top of this factory.
|
|
145
|
+
*/
|
|
146
|
+
export declare const makeRetryPolicy: (options?: ModbusRetryPolicyOptions) => ModbusRetryPolicy;
|
|
147
|
+
/**
|
|
148
|
+
* Retry templates for common deployments.
|
|
149
|
+
*
|
|
150
|
+
* Each entry is a factory taking optional overrides, so a template can be used
|
|
151
|
+
* as-is or as a starting point:
|
|
152
|
+
*
|
|
153
|
+
* ```ts
|
|
154
|
+
* RetryPolicies.serial();
|
|
155
|
+
* RetryPolicies.serial({ maxRetries: 6 });
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* None of these are applied implicitly — pick one and pipe through
|
|
159
|
+
* {@link retryModbus}.
|
|
160
|
+
*/
|
|
161
|
+
export declare const RetryPolicies: {
|
|
162
|
+
/**
|
|
163
|
+
* No retries — the library default behaviour, stated explicitly.
|
|
164
|
+
*
|
|
165
|
+
* Useful as a base for opting individual call sites out of an
|
|
166
|
+
* application-wide policy.
|
|
167
|
+
*/
|
|
168
|
+
readonly none: (overrides?: ModbusRetryPolicyOptions) => ModbusRetryPolicy;
|
|
169
|
+
/**
|
|
170
|
+
* Serial (RTU/ASCII) buses: short delays, tight ceiling.
|
|
171
|
+
*
|
|
172
|
+
* A framing or CRC error on RS-485 is usually a collision or a noise burst,
|
|
173
|
+
* so retrying quickly is the right move; timeouts back off a little further
|
|
174
|
+
* to let a slow device finish its turnaround. Reconnects are reserved for a
|
|
175
|
+
* genuinely closed port — reopening a USB serial adapter is expensive.
|
|
176
|
+
*/
|
|
177
|
+
readonly serial: (overrides?: ModbusRetryPolicyOptions) => ModbusRetryPolicy;
|
|
178
|
+
/**
|
|
179
|
+
* Modbus/TCP: room for a TCP handshake to re-establish.
|
|
180
|
+
*
|
|
181
|
+
* A transport error over TCP generally means the socket is gone rather than
|
|
182
|
+
* a corrupted frame, so it reconnects alongside an explicit connection close.
|
|
183
|
+
*/
|
|
184
|
+
readonly tcp: (overrides?: ModbusRetryPolicyOptions) => ModbusRetryPolicy;
|
|
185
|
+
/**
|
|
186
|
+
* Long-running background polling: keep trying, but stop hammering.
|
|
187
|
+
*
|
|
188
|
+
* Backs off to a 30-second ceiling and gives up after 5 minutes of failures
|
|
189
|
+
* so a permanently dead device surfaces as an error instead of silently
|
|
190
|
+
* retrying forever.
|
|
191
|
+
*/
|
|
192
|
+
readonly persistent: (overrides?: ModbusRetryPolicyOptions) => ModbusRetryPolicy;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Applies a {@link ModbusRetryPolicy} to an effect.
|
|
196
|
+
*
|
|
197
|
+
* Errors the policy considers non-retryable fail through immediately, so an
|
|
198
|
+
* `ModbusInvalidArgumentError` still surfaces on the first attempt under a
|
|
199
|
+
* policy tuned for flaky wiring.
|
|
200
|
+
*
|
|
201
|
+
* **This wraps rather than replaces.** `withClient(unitId, { retry })` and
|
|
202
|
+
* `client.withRetry(policy)` are resolved inside the client, so they discard
|
|
203
|
+
* the policy already in force. `retryModbus` is piped *around* an effect the
|
|
204
|
+
* client has already wrapped in its own retry, and nothing in that path can see
|
|
205
|
+
* the inner policy — so over a policied client both run and the attempt counts
|
|
206
|
+
* multiply (a `maxRetries: 2` client under a `maxRetries: 3` pipe makes 3 × 4 =
|
|
207
|
+
* 12 attempts). Reach for it only over a {@link RetryPolicies.none} client, to
|
|
208
|
+
* drive a compound operation as a unit; for a single operation, prefer
|
|
209
|
+
* `client.withRetry(policy)`.
|
|
210
|
+
*
|
|
211
|
+
* @param policy - The policy to apply.
|
|
212
|
+
* @returns A combinator that can be piped over any effect failing with
|
|
213
|
+
* {@link ModbusError}.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* // A read-modify-write retried as a unit — retrying either frame alone
|
|
218
|
+
* // would be wrong. The client carries no policy of its own.
|
|
219
|
+
* const client = yield* transport.withClient(1, { retry: RetryPolicies.none() });
|
|
220
|
+
*
|
|
221
|
+
* yield* Effect.gen(function* () {
|
|
222
|
+
* const current = yield* client.readHoldingRegisters({ address: 0, quantity: 2 });
|
|
223
|
+
* yield* client.writeMultipleRegisters({ address: 0, values: bump(current) });
|
|
224
|
+
* }).pipe(retryModbus(RetryPolicies.serial()));
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
export declare const retryModbus: (policy: ModbusRetryPolicy) => <A, E extends ModbusError, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,63 @@
|
|
|
1
|
-
import { Effect, Scope } from
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
1
|
+
import { Effect, Scope, SubscriptionRef } from 'effect';
|
|
2
|
+
import { ConnectionState, type ReconnectOptions } from './connection';
|
|
3
|
+
import { type ModbusError, ModbusNotConnectedError } from './errors';
|
|
4
|
+
import { type AnyModbusClient, type EffectModbusClient } from './modbus-client';
|
|
5
|
+
import type { ModbusRetryPolicy } from './retry';
|
|
6
|
+
/**
|
|
7
|
+
* Resilience configuration accepted by every transport service alongside its
|
|
8
|
+
* `modbus-rs` options.
|
|
9
|
+
*
|
|
10
|
+
* Both are opt-in: with neither set, a transport behaves exactly as it always
|
|
11
|
+
* has — one attempt per operation, reconnection only when asked for.
|
|
12
|
+
*/
|
|
13
|
+
export interface TransportResilienceOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Retry policy applied to every operation of every client from this
|
|
16
|
+
* transport. Overridable per client and per operation.
|
|
17
|
+
*/
|
|
18
|
+
readonly retry?: ModbusRetryPolicy;
|
|
19
|
+
/**
|
|
20
|
+
* Hands reconnection to a supervisor fiber owned by this transport, and
|
|
21
|
+
* enables the circuit breaker that keeps callers off a dead bus.
|
|
22
|
+
*/
|
|
23
|
+
readonly reconnect?: ReconnectOptions;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The `modbus-rs` transport-level retry knobs this package deliberately does
|
|
27
|
+
* not expose.
|
|
28
|
+
*
|
|
29
|
+
* They are withheld rather than merely discouraged because enabling them is
|
|
30
|
+
* never the right call under this design:
|
|
31
|
+
*
|
|
32
|
+
* - **They retry below the Effect boundary.** A failure they paper over never
|
|
33
|
+
* reaches the policy, the circuit breaker, or the logs — the caller sees one
|
|
34
|
+
* slow success instead of several failures and a recovery, and any
|
|
35
|
+
* caller-side timeout is measuring inflated time.
|
|
36
|
+
* - **They reconnect.** Upstream re-establishes the link inline and replays
|
|
37
|
+
* in-flight requests after it, which races the one supervisor fiber that is
|
|
38
|
+
* supposed to own reconnection for the whole transport.
|
|
39
|
+
* - **They multiply.** Neither layer knows about the other, so attempt counts
|
|
40
|
+
* compound and the two backoff curves interleave.
|
|
41
|
+
* - **`retryDelayMs` is flat and unjittered**, the collision pattern that
|
|
42
|
+
* `RetryPolicies.serial()` exists to break up; `retryBackoffStrategy` is
|
|
43
|
+
* documented upstream as inert, so setting it does nothing at all.
|
|
44
|
+
*
|
|
45
|
+
* Use the `retry` and `reconnect` options on {@link TransportResilienceOptions}
|
|
46
|
+
* instead. Callers who genuinely need frame-level resends can construct a raw
|
|
47
|
+
* `modbus-rs` client directly, where the trade-off is explicit.
|
|
48
|
+
*/
|
|
49
|
+
export type UpstreamRetryOptionKey = 'retryAttempts' | 'retryDelayMs' | 'retryBackoffStrategy';
|
|
50
|
+
/**
|
|
51
|
+
* Upstream `modbus-rs` transport options with the retry knobs removed.
|
|
52
|
+
*
|
|
53
|
+
* Applied to every transport-creation entry point this package exposes. All
|
|
54
|
+
* three keys are optional upstream, so the result stays assignable to the
|
|
55
|
+
* original type and still satisfies the upstream `open`/`connect` call.
|
|
56
|
+
*
|
|
57
|
+
* @typeParam TOptions - The upstream options type (e.g. `RtuTransportOptions`).
|
|
58
|
+
* @see UpstreamRetryOptionKey — Why these are withheld.
|
|
59
|
+
*/
|
|
60
|
+
export type WithoutUpstreamRetry<TOptions> = Omit<TOptions, UpstreamRetryOptionKey>;
|
|
4
61
|
/**
|
|
5
62
|
* Shared API surface that every transport service exposes to consumers.
|
|
6
63
|
*
|
|
@@ -10,13 +67,44 @@ import { type AnyModbusClient, type EffectModbusClient } from "./modbus-client";
|
|
|
10
67
|
* @see makeTransportScoped — Factory that produces this API from a raw transport.
|
|
11
68
|
*/
|
|
12
69
|
export interface TransportServiceApi {
|
|
13
|
-
/**
|
|
14
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Obtains an {@link EffectModbusClient} for the given unit ID.
|
|
72
|
+
*
|
|
73
|
+
* The client carries the transport's retry policy unless `options.retry`
|
|
74
|
+
* replaces it — useful when one bus hosts device types that need different
|
|
75
|
+
* logic. The underlying `modbus-rs` client is cached per unit ID, so clients
|
|
76
|
+
* built with different policies still share one connection.
|
|
77
|
+
*
|
|
78
|
+
* @param unitId - Modbus unit ID to address.
|
|
79
|
+
* @param options - Per-client policy replacing the transport default.
|
|
80
|
+
*/
|
|
81
|
+
withClient(unitId: number, options?: {
|
|
82
|
+
readonly retry?: ModbusRetryPolicy;
|
|
83
|
+
}): Effect.Effect<EffectModbusClient, ModbusError>;
|
|
84
|
+
/**
|
|
85
|
+
* Live connection state, published by the transport.
|
|
86
|
+
*
|
|
87
|
+
* Read it with `SubscriptionRef.get`, or subscribe with `.changes` to drive
|
|
88
|
+
* a status indicator:
|
|
89
|
+
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* yield* Stream.runForEach(transport.connectionState.changes, (state) =>
|
|
92
|
+
* Console.log(`link: ${state._tag}`))
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
readonly connectionState: SubscriptionRef.SubscriptionRef<ConnectionState>;
|
|
15
96
|
/** Sets a request timeout (ms) on the underlying transport. Fails if not connected. */
|
|
16
97
|
setRequestTimeout(timeoutMs: number): Effect.Effect<void, ModbusError>;
|
|
17
98
|
/** Clears the request timeout. Fails if not connected. */
|
|
18
99
|
clearRequestTimeout(): Effect.Effect<void, ModbusError>;
|
|
19
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Reconnects the transport. Opens lazily if no prior connection exists.
|
|
102
|
+
*
|
|
103
|
+
* Concurrent calls are coalesced: fibers arriving while a reconnect is in
|
|
104
|
+
* flight join it rather than starting another, and all of them observe its
|
|
105
|
+
* result. Fails with `ModbusNotConnectedError` if the transport was closed
|
|
106
|
+
* while the reconnect was running.
|
|
107
|
+
*/
|
|
20
108
|
reconnect(): Effect.Effect<void, ModbusError>;
|
|
21
109
|
/** Closes the transport and its scope immediately. */
|
|
22
110
|
close(): Effect.Effect<void, ModbusError, Scope.Scope>;
|
|
@@ -51,10 +139,27 @@ interface TransportHandle<TClient> {
|
|
|
51
139
|
* @param openMethod - A function that takes the transport constructor and options,
|
|
52
140
|
* returning a promise for the opened transport.
|
|
53
141
|
* @param serviceName - Logical name used in log messages and the finalizer guard.
|
|
142
|
+
* @param config - Optional module specifier override for browser WASM transports.
|
|
54
143
|
* @returns An `Effect` that produces a {@link TransportServiceApi}.
|
|
55
144
|
*/
|
|
56
|
-
export declare function makeTransportScoped<TOptions, TClient extends AnyModbusClient, TTransport extends TransportHandle<TClient>>(transportKey: string, openMethod: (TC: unknown, options: TOptions) => Promise<TTransport>, serviceName: string
|
|
57
|
-
|
|
145
|
+
export declare function makeTransportScoped<TOptions, TClient extends AnyModbusClient, TTransport extends TransportHandle<TClient>>(transportKey: string, openMethod: (TC: unknown, options: TOptions) => Promise<TTransport>, serviceName: string, config?: {
|
|
146
|
+
/** Which `modbus-rs` conditional export to import from. Defaults to `"modbus-rs"` (native). */
|
|
147
|
+
moduleSpecifier?: 'modbus-rs' | 'modbus-rs/web';
|
|
148
|
+
}): (options: TOptions & TransportResilienceOptions) => Effect.Effect<{
|
|
149
|
+
connectionState: SubscriptionRef.SubscriptionRef<{
|
|
150
|
+
readonly _tag: "Connected";
|
|
151
|
+
} | {
|
|
152
|
+
readonly _tag: "Disconnected";
|
|
153
|
+
} | {
|
|
154
|
+
readonly _tag: "Down";
|
|
155
|
+
readonly cause: ModbusError;
|
|
156
|
+
} | {
|
|
157
|
+
readonly _tag: "Reconnecting";
|
|
158
|
+
readonly attempt: number;
|
|
159
|
+
}>;
|
|
160
|
+
withClient: (unitId: number, clientOptions?: {
|
|
161
|
+
readonly retry?: ModbusRetryPolicy;
|
|
162
|
+
} | undefined) => Effect.Effect<EffectModbusClient, ModbusError, never>;
|
|
58
163
|
setRequestTimeout: (timeoutMs: number) => Effect.Effect<undefined, ModbusNotConnectedError, never>;
|
|
59
164
|
clearRequestTimeout: () => Effect.Effect<undefined, ModbusNotConnectedError, never>;
|
|
60
165
|
reconnect: () => Effect.Effect<undefined, ModbusError, never>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flux-control/effect-modbus-rs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Type-safe Modbus communication via Effect-TS, wrapping the modbus-rs npm bindings.",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/flux-control-solutions/Effect-modbus-rs.git"
|
|
9
9
|
},
|
|
10
|
-
"type": "module",
|
|
11
10
|
"files": [
|
|
12
11
|
"dist/**/*.js",
|
|
13
12
|
"dist/**/*.d.ts"
|
|
14
13
|
],
|
|
15
|
-
"
|
|
16
|
-
"access": "public"
|
|
17
|
-
},
|
|
14
|
+
"type": "module",
|
|
18
15
|
"exports": {
|
|
19
16
|
"./package.json": "./package.json",
|
|
20
17
|
".": {
|
|
@@ -22,30 +19,40 @@
|
|
|
22
19
|
"default": "./dist/index.js"
|
|
23
20
|
}
|
|
24
21
|
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
25
|
"scripts": {
|
|
26
|
+
"build": "rm -rf ./dist && bun build ./index.ts --outdir ./dist --target node --external effect --external modbus-rs && tsc --noEmit false --emitDeclarationOnly --outDir ./dist --rootDir . --project tsconfig.build.json",
|
|
26
27
|
"changeset": "changeset",
|
|
28
|
+
"docs": "bun install --cwd tools/typedoc --frozen-lockfile && bun run --cwd \"$PWD/tools/typedoc\" generate",
|
|
29
|
+
"format": "oxfmt --check",
|
|
30
|
+
"format:fix": "oxfmt",
|
|
31
|
+
"lint": "oxlint",
|
|
32
|
+
"lint:fix": "oxlint --fix",
|
|
33
|
+
"prepare": "husky",
|
|
34
|
+
"release": "changeset publish",
|
|
27
35
|
"test": "bun test ./src/ ./examples/",
|
|
28
36
|
"test:coverage": "bun test --coverage ./src/ ./examples/",
|
|
29
37
|
"typecheck": "tsc --noEmit",
|
|
30
|
-
"build": "rm -rf ./dist && bun build ./index.ts --outdir ./dist --target node --external effect --external modbus-rs && tsc --noEmit false --emitDeclarationOnly --outDir ./dist --rootDir . --project tsconfig.build.json",
|
|
31
|
-
"docs": "typedoc",
|
|
32
|
-
"release": "changeset publish",
|
|
33
38
|
"version": "changeset version"
|
|
34
39
|
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"modbus-rs": "0.16.1"
|
|
42
|
+
},
|
|
35
43
|
"devDependencies": {
|
|
36
44
|
"@changesets/cli": "^2.31.1",
|
|
37
|
-
"@effect/language-service": "^0.86.
|
|
45
|
+
"@effect/language-service": "^0.86.6",
|
|
38
46
|
"@effect/platform-bun": "^0.90.0",
|
|
39
47
|
"@types/bun": "latest",
|
|
40
|
-
"effect": "^3.
|
|
41
|
-
"fallow": "^2.
|
|
42
|
-
"
|
|
43
|
-
"
|
|
48
|
+
"effect": "^3.22.0",
|
|
49
|
+
"fallow": "^2.104.0",
|
|
50
|
+
"husky": "^9.1.7",
|
|
51
|
+
"oxfmt": "^0.60.0",
|
|
52
|
+
"oxlint": "^1.75.0",
|
|
53
|
+
"typescript": "^7.0.2"
|
|
44
54
|
},
|
|
45
55
|
"peerDependencies": {
|
|
46
|
-
"effect": "^3.
|
|
47
|
-
},
|
|
48
|
-
"dependencies": {
|
|
49
|
-
"modbus-rs": "^0.15.3"
|
|
56
|
+
"effect": "^3.22.0"
|
|
50
57
|
}
|
|
51
58
|
}
|