@flux-control/effect-modbus-rs 0.6.0 → 0.7.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 CHANGED
@@ -394,7 +394,23 @@ const damper =
394
394
  const same = yield * transport.batchingClient(3); // elsewhere, no options to restate
395
395
  ```
396
396
 
397
- `withBatchingClient` declares. Declaring a unit twice fails with `ModbusInvalidArgumentError`, whatever the second call asks for. `batchingClient` looks up, and fails the same way when nothing has declared that unit. A lookup that arrives while a declaration is still in flight waits for it, so neither call has to know which one ran first.
397
+ `withBatchingClient` declares. Declaring a unit twice fails with `ModbusUnitAlreadyDeclaredError`, whatever the second call asks for. `batchingClient` looks up, and fails with `ModbusInvalidArgumentError` when nothing has declared that unit. A lookup that arrives while a declaration is still in flight waits for it, so neither call has to know which one ran first.
398
+
399
+ A declaration belongs to the transport scope, not to the caller. It stays when the caller is interrupted, and when the owner that made it closes while the transport stays open. An owner that can start again over the same transport can catch the error and recover the existing client:
400
+
401
+ ```ts
402
+ const damper =
403
+ yield *
404
+ transport
405
+ .withBatchingClient(3, { debounce })
406
+ .pipe(
407
+ Effect.catchTag('ModbusUnitAlreadyDeclaredError', (error) =>
408
+ transport.batchingClient(error.unitId),
409
+ ),
410
+ );
411
+ ```
412
+
413
+ The recovered client keeps the options of the first declaration. `client.debounce` gives its debounce windows as frozen, resolved `Duration` values, so the owner can compare them with the windows that it expects. An omitted `maxHold` shows as four times the write window, which is the limit that the client applies.
398
414
 
399
415
  ### Shutdown
400
416
 
@@ -547,6 +563,8 @@ Errors from the underlying Rust layer are mapped to typed `Effect` errors via `D
547
563
 
548
564
  Handle with `Effect.catchTags`. The `ModbusError` union type covers all seven variants.
549
565
 
566
+ `withBatchingClient` can also fail with `ModbusUnitAlreadyDeclaredError` when the unit already has a batching client. This error is not a member of `ModbusError`, because it never comes from the bus. See [Declaring a unit, and reaching for it](#declaring-a-unit-and-reaching-for-it).
567
+
550
568
  ## Resilience: retries, reconnection, and circuit breaking
551
569
 
552
570
  > **These are application-level policies, and they are opt-in.**
package/dist/index.d.ts CHANGED
@@ -159,7 +159,7 @@ export type { DebouncedWrite, WriteDebouncer, WriteDebouncerOptions } from './sr
159
159
  export { createReadDebouncer } from './src/read-debouncer';
160
160
  export type { ReadDebouncer, ReadDebouncerOptions } from './src/read-debouncer';
161
161
  export { makeBatchingClient, createBatchingRegistry } from './src/batching-client';
162
- export type { BatchingClientOptions, BatchingDebounceOptions, BatchingModbusClient, BatchingRegistry, BatchingRegistryDeps, BatchingRegisterReader, } from './src/batching-client';
162
+ export type { BatchingClientOptions, BatchingDebounceOptions, BatchingDebounceWindows, BatchingModbusClient, BatchingRegistry, BatchingRegistryDeps, BatchingRegisterReader, } from './src/batching-client';
163
163
  export { mergeSpanAttributes } from './src/span-attributes';
164
164
  export type { ModbusSpanAttributes } from './src/span-attributes';
165
165
  export { AsciiTransportService } from './src/AsciiTransportService';
package/dist/index.js CHANGED
@@ -25,6 +25,9 @@ class ModbusNotConnectedError extends Data.TaggedError("ModbusNotConnectedError"
25
25
 
26
26
  class ModbusCircuitOpenError extends Data.TaggedError("ModbusCircuitOpenError") {
27
27
  }
28
+
29
+ class ModbusUnitAlreadyDeclaredError extends Data.TaggedError("ModbusUnitAlreadyDeclaredError") {
30
+ }
28
31
  function parseExceptionCode(message) {
29
32
  const m = message.match(/\[MODBUS_EXCEPTION:(\d+)\]/);
30
33
  return m ? Number(m[1]) : undefined;
@@ -393,9 +396,13 @@ var createRegisterCache = () => {
393
396
  };
394
397
  // src/write-debouncer.ts
395
398
  import { Clock, Deferred, Duration as Duration3, Effect as Effect3, Fiber, Semaphore } from "effect";
399
+ var resolveWriteHold = (window, maxHold) => {
400
+ const windowMs = Duration3.toMillis(Duration3.fromInputUnsafe(window));
401
+ const maxHoldMs = maxHold === undefined ? windowMs * 4 : Duration3.toMillis(Duration3.fromInputUnsafe(maxHold));
402
+ return { windowMs, maxHoldMs };
403
+ };
396
404
  var createWriteDebouncer = (options) => Effect3.gen(function* () {
397
- const windowMs = Duration3.toMillis(Duration3.fromInputUnsafe(options.window));
398
- const maxHoldMs = options.maxHold === undefined ? windowMs * 4 : Duration3.toMillis(Duration3.fromInputUnsafe(options.maxHold));
405
+ const { windowMs, maxHoldMs } = resolveWriteHold(options.window, options.maxHold);
399
406
  const scope = yield* Effect3.scope;
400
407
  const lock = yield* Semaphore.make(1);
401
408
  const flushLock = yield* Semaphore.make(1);
@@ -663,6 +670,7 @@ var createReadDebouncer = (options) => Effect4.gen(function* () {
663
670
  // src/batching-client.ts
664
671
  import {
665
672
  Deferred as Deferred3,
673
+ Duration as Duration5,
666
674
  Effect as Effect5,
667
675
  Exit as Exit2,
668
676
  Fiber as Fiber3,
@@ -693,6 +701,22 @@ var mergeSpanAttributes = (sources) => {
693
701
  };
694
702
 
695
703
  // src/batching-client.ts
704
+ var resolveDebounceWindows = (options) => {
705
+ if (options === undefined)
706
+ return;
707
+ const hold = options.writes === undefined ? undefined : resolveWriteHold(options.writes.window, options.writes.maxHold);
708
+ return Object.freeze({
709
+ ...hold && {
710
+ writes: Object.freeze({
711
+ window: Duration5.millis(hold.windowMs),
712
+ maxHold: Duration5.millis(hold.maxHoldMs)
713
+ })
714
+ },
715
+ ...options.reads && {
716
+ reads: Object.freeze({ window: Duration5.fromInputUnsafe(options.reads.window) })
717
+ }
718
+ });
719
+ };
696
720
  var makeBatchingClient = (options) => Effect5.gen(function* () {
697
721
  const { unitId, client, cache } = options;
698
722
  const scope = yield* Effect5.scope;
@@ -772,6 +796,7 @@ var makeBatchingClient = (options) => Effect5.gen(function* () {
772
796
  return {
773
797
  unitId,
774
798
  cache,
799
+ debounce: resolveDebounceWindows(options.debounce),
775
800
  write: writes.write,
776
801
  writeNow: writes.writeNow,
777
802
  writeAll: writes.writeAll,
@@ -842,7 +867,7 @@ var createBatchingRegistry = (deps) => {
842
867
  };
843
868
  const alreadyDeclaredError = (unitId) => {
844
869
  const message = `Unit ${unitId} already has a batching client. One unit has one batch, so a unit ` + `is declared once. Use batchingClient(${unitId}) to reach the existing one.`;
845
- return new ModbusInvalidArgumentError({ cause: new Error(message), message });
870
+ return new ModbusUnitAlreadyDeclaredError({ cause: new Error(message), message, unitId });
846
871
  };
847
872
  const notDeclaredError = (unitId) => {
848
873
  const message = `No batching client is declared for unit ${unitId}. Declare one with ` + `withBatchingClient(${unitId}) before reaching for it.`;
@@ -1694,6 +1719,7 @@ export {
1694
1719
  ModbusNotConnectedError,
1695
1720
  ModbusTimeoutError,
1696
1721
  ModbusTransportError,
1722
+ ModbusUnitAlreadyDeclaredError,
1697
1723
  RetryPolicies,
1698
1724
  RtuTransportService,
1699
1725
  SerialTransportService,
@@ -51,7 +51,7 @@ export declare class AsciiTransportService extends AsciiTransportService_base {
51
51
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
52
52
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
53
53
  readonly retry?: import("./retry").ModbusRetryPolicy;
54
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
54
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
55
55
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
56
56
  readonly touchedUnits: Set<number>;
57
57
  hasPendingRequests: () => boolean;
@@ -51,7 +51,7 @@ export declare class RtuTransportService extends RtuTransportService_base {
51
51
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
52
52
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
53
53
  readonly retry?: import("./retry").ModbusRetryPolicy;
54
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
54
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
55
55
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
56
56
  readonly touchedUnits: Set<number>;
57
57
  hasPendingRequests: () => boolean;
@@ -51,7 +51,7 @@ export declare class TcpTransportService extends TcpTransportService_base {
51
51
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
52
52
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
53
53
  readonly retry?: import("./retry").ModbusRetryPolicy;
54
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
54
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
55
55
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
56
56
  readonly touchedUnits: Set<number>;
57
57
  hasPendingRequests: () => boolean;
@@ -57,7 +57,7 @@ export declare class WasmAsciiTransportService extends WasmAsciiTransportService
57
57
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
58
58
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
59
59
  readonly retry?: import("./retry").ModbusRetryPolicy;
60
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
60
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
61
61
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
62
62
  readonly touchedUnits: Set<number>;
63
63
  hasPendingRequests: () => boolean;
@@ -57,7 +57,7 @@ export declare class WasmRtuTransportService extends WasmRtuTransportService_bas
57
57
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
58
58
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
59
59
  readonly retry?: import("./retry").ModbusRetryPolicy;
60
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
60
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
61
61
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
62
62
  readonly touchedUnits: Set<number>;
63
63
  hasPendingRequests: () => boolean;
@@ -44,7 +44,7 @@ export declare class WasmWsTransportService extends WasmWsTransportService_base
44
44
  close: () => import("effect/Effect").Effect<void, import("./errors").ModbusError, import("effect/Scope").Scope>;
45
45
  withBatchingClient: (unitId: number, options?: import("./batching-client").BatchingClientOptions & {
46
46
  readonly retry?: import("./retry").ModbusRetryPolicy;
47
- }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
47
+ }) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError | import("./errors").ModbusUnitAlreadyDeclaredError>;
48
48
  batchingClient: (unitId: number) => import("effect/Effect").Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusError>;
49
49
  readonly touchedUnits: Set<number>;
50
50
  hasPendingRequests: () => boolean;
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import { Duration, Effect, Scope, SubscriptionRef } from 'effect';
14
14
  import { ConnectionState } from './connection';
15
- import { type ModbusError } from './errors';
15
+ import { ModbusUnitAlreadyDeclaredError, type ModbusError } from './errors';
16
16
  import type { EffectModbusClient, ModbusOperations } from './modbus-client';
17
17
  import { type RegisterCache } from './register-cache';
18
18
  import { type PlanReadsOptions, type PlanWritesOptions, type RegisterWrite } from './register-plan';
@@ -44,6 +44,23 @@ export interface BatchingDebounceOptions {
44
44
  readonly window: Duration.Input;
45
45
  };
46
46
  }
47
+ /**
48
+ * The debounce windows that a batching client applies, as resolved values.
49
+ *
50
+ * A write entry always has `maxHold`. When the declaration omitted it, it is
51
+ * four times the window, which is the limit the write debouncer applies.
52
+ */
53
+ export interface BatchingDebounceWindows {
54
+ /** The write window and the hold limit. Omitted when writes are not debounced. */
55
+ readonly writes?: {
56
+ readonly window: Duration.Duration;
57
+ readonly maxHold: Duration.Duration;
58
+ };
59
+ /** The read window. Omitted when reads are not debounced. */
60
+ readonly reads?: {
61
+ readonly window: Duration.Duration;
62
+ };
63
+ }
47
64
  /** Options for {@link makeBatchingClient}. */
48
65
  export interface BatchingClientOptions {
49
66
  /**
@@ -111,6 +128,17 @@ export interface BatchingModbusClient extends BatchingRegisterReader {
111
128
  readonly flush: Effect.Effect<void>;
112
129
  /** The cache this client filters against, or `undefined` when `cache` is `false`. */
113
130
  readonly cache: RegisterCache | undefined;
131
+ /**
132
+ * The debounce windows this client applies, or `undefined` when its
133
+ * declaration had no `debounce` option.
134
+ *
135
+ * The values are resolved and frozen when the client is built. An omitted
136
+ * `maxHold` shows as four times the write window.
137
+ *
138
+ * A caller that recovers an existing client with `batchingClient` did not
139
+ * choose these windows. Compare them with the windows that the caller expects.
140
+ */
141
+ readonly debounce: BatchingDebounceWindows | undefined;
114
142
  /**
115
143
  * Runs an action when the calling scope closes, while the bus is still open
116
144
  * and before this client is torn down.
@@ -161,7 +189,10 @@ export interface BatchingRegistryDeps {
161
189
  /** The batching half of a transport's API. */
162
190
  export interface BatchingRegistry {
163
191
  /**
164
- * Declares the batching client for a unit. Fails if the unit already has one.
192
+ * Declares the batching client for a unit.
193
+ *
194
+ * Fails with `ModbusUnitAlreadyDeclaredError` if the unit already has a
195
+ * completed declaration or a declaration in progress.
165
196
  *
166
197
  * The declaration belongs to the registry's transport scope, not to the
167
198
  * calling fiber. Construction therefore continues if the caller is
@@ -171,7 +202,7 @@ export interface BatchingRegistry {
171
202
  */
172
203
  withBatchingClient(unitId: number, options?: BatchingClientOptions & {
173
204
  readonly retry?: ModbusRetryPolicy;
174
- }): Effect.Effect<BatchingModbusClient, ModbusError>;
205
+ }): Effect.Effect<BatchingModbusClient, ModbusError | ModbusUnitAlreadyDeclaredError>;
175
206
  /** The batching client for a unit. Fails if nothing has declared one. */
176
207
  batchingClient(unitId: number): Effect.Effect<BatchingModbusClient, ModbusError>;
177
208
  /** Disables raw holding-register writes once a batching client exists for the unit. */
@@ -162,6 +162,42 @@ export declare class ModbusCircuitOpenError extends ModbusCircuitOpenError_base<
162
162
  readonly message: string;
163
163
  }> {
164
164
  }
165
+ declare const ModbusUnitAlreadyDeclaredError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
166
+ readonly _tag: "ModbusUnitAlreadyDeclaredError";
167
+ } & Readonly<A>;
168
+ /**
169
+ * Error indicating that a unit already has a batching client on this transport.
170
+ *
171
+ * This is a **local** error. `modbus-rs` never returns it. The transport
172
+ * raises it from `withBatchingClient` when the unit has a completed
173
+ * declaration or a declaration in progress.
174
+ *
175
+ * The declaration belongs to the transport scope, not to the caller. It stays
176
+ * after its caller is interrupted, and after the owner that made it closes.
177
+ * Catch this error to recover the existing client with `batchingClient(unitId)`.
178
+ *
179
+ * This error is not a member of {@link ModbusError}. It can occur only when a
180
+ * caller declares a unit. It never occurs on the bus, so retry policies do not
181
+ * apply to it.
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * const client = yield* transport.withBatchingClient(3).pipe(
186
+ * Effect.catchTag('ModbusUnitAlreadyDeclaredError', (error) =>
187
+ * transport.batchingClient(error.unitId),
188
+ * ),
189
+ * );
190
+ * ```
191
+ */
192
+ export declare class ModbusUnitAlreadyDeclaredError extends ModbusUnitAlreadyDeclaredError_base<{
193
+ /** A descriptive error. */
194
+ readonly cause: Error;
195
+ /** Human-readable explanation of the error. */
196
+ readonly message: string;
197
+ /** The unit that already has a batching client. */
198
+ readonly unitId: number;
199
+ }> {
200
+ }
165
201
  /**
166
202
  * Union of all typed Modbus errors emitted by this library.
167
203
  *
@@ -153,7 +153,7 @@ export declare const createMockTransport: (devices: SlaveDeviceDefinitions) => (
153
153
  } | undefined) => Effect.Effect<import("./modbus-client").EffectModbusClient, ModbusInvalidArgumentError | ModbusNotConnectedError, never>;
154
154
  withBatchingClient: (unitId: number, clientOptions?: BatchingClientOptions & {
155
155
  readonly retry?: ModbusRetryPolicy;
156
- }) => Effect.Effect<import("./batching-client").BatchingModbusClient, ModbusError, never>;
156
+ }) => Effect.Effect<import("./batching-client").BatchingModbusClient, import("./errors").ModbusUnitAlreadyDeclaredError | ModbusError, never>;
157
157
  batchingClient: (unitId: number) => Effect.Effect<import("./batching-client").BatchingModbusClient, ModbusError, never>;
158
158
  readonly touchedUnits: Set<number>;
159
159
  setRequestTimeout: (_timeoutMs: number) => Effect.Effect<void, ModbusNotConnectedError, never>;
@@ -3,7 +3,7 @@ import type { AsyncAsciiTransport, AsyncRtuTransport, AsyncTcpTransport } from '
3
3
  import type { WasmAsciiTransport, WasmRtuTransport, WasmWsTransport } from 'modbus-rs/web';
4
4
  import { type BatchingClientOptions, type BatchingModbusClient } from './batching-client';
5
5
  import { ConnectionState, type ReconnectOptions } from './connection';
6
- import { ModbusNotConnectedError, type ModbusError } from './errors';
6
+ import { ModbusNotConnectedError, type ModbusError, type ModbusUnitAlreadyDeclaredError } from './errors';
7
7
  import { type AnyModbusClient, type EffectModbusClient } from './modbus-client';
8
8
  import type { ModbusRetryPolicy } from './retry';
9
9
  /**
@@ -145,8 +145,12 @@ export interface TransportServiceApi {
145
145
  * A unit is declared once, because every option here is a fact about the unit
146
146
  * rather than about a caller: one unit holds one batch, one belief about the
147
147
  * device, and one window. Declaring a unit twice fails with
148
- * `ModbusInvalidArgumentError`. Use {@link batchingClient} to reach a client
149
- * another part of the program declared.
148
+ * `ModbusUnitAlreadyDeclaredError`. Use {@link batchingClient} to reach a
149
+ * client another part of the program declared.
150
+ *
151
+ * The declaration lasts as long as the transport. A new owner that starts over
152
+ * a transport that stays open finds the unit declared. It can catch
153
+ * `ModbusUnitAlreadyDeclaredError` and use {@link batchingClient} instead.
150
154
  *
151
155
  * Nothing is debounced unless `debounce` asks for it, matching the rest of
152
156
  * this package: default timing stays predictable.
@@ -156,7 +160,7 @@ export interface TransportServiceApi {
156
160
  */
157
161
  withBatchingClient(unitId: number, options?: BatchingClientOptions & {
158
162
  readonly retry?: ModbusRetryPolicy;
159
- }): Effect.Effect<BatchingModbusClient, ModbusError>;
163
+ }): Effect.Effect<BatchingModbusClient, ModbusError | ModbusUnitAlreadyDeclaredError>;
160
164
  /**
161
165
  * The {@link BatchingModbusClient} declared for a unit.
162
166
  *
@@ -235,7 +239,7 @@ export declare function createTransportScoped<TOptions, TClient extends AnyModbu
235
239
  close: () => Effect.Effect<void, ModbusError, Scope.Scope>;
236
240
  withBatchingClient: (unitId: number, options?: BatchingClientOptions & {
237
241
  readonly retry?: ModbusRetryPolicy;
238
- }) => Effect.Effect<BatchingModbusClient, ModbusError>;
242
+ }) => Effect.Effect<BatchingModbusClient, ModbusError | ModbusUnitAlreadyDeclaredError>;
239
243
  batchingClient: (unitId: number) => Effect.Effect<BatchingModbusClient, ModbusError>;
240
244
  readonly touchedUnits: Set<number>;
241
245
  hasPendingRequests: () => boolean;
@@ -131,4 +131,17 @@ export interface WriteDebouncer {
131
131
  * debouncer.write({ address: 2001, value: 20 }),
132
132
  * ], { concurrency: 'unbounded' });
133
133
  */
134
+ /**
135
+ * Resolves the window and the hold limit that a write debouncer applies.
136
+ *
137
+ * The batching client reports these values, so both use this one rule.
138
+ *
139
+ * @param window - The write window.
140
+ * @param maxHold - The hold limit. When omitted, it is four times the window.
141
+ * @returns The window and the hold limit in milliseconds.
142
+ */
143
+ export declare const resolveWriteHold: (window: Duration.Input, maxHold: Duration.Input | undefined) => {
144
+ windowMs: number;
145
+ maxHoldMs: number;
146
+ };
134
147
  export declare const createWriteDebouncer: (options: WriteDebouncerOptions) => Effect.Effect<WriteDebouncer, never, Scope.Scope>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flux-control/effect-modbus-rs",
3
- "version": "0.6.0",
3
+ "version": "0.7.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": {
@@ -47,10 +47,10 @@
47
47
  "@effect/platform-bun": "^4.0.0-rc.109",
48
48
  "@oxlint/plugins": "1.76.0",
49
49
  "@types/bun": "latest",
50
- "effect": "^4.0.0-rc.109",
50
+ "effect": "4.0.0-rc.109",
51
51
  "fallow": "^2.104.0",
52
52
  "husky": "^9.1.7",
53
- "oxfmt": "^0.60.0",
53
+ "oxfmt": "^0.71.0",
54
54
  "oxlint": "1.76.0",
55
55
  "typescript": "^7.0.2"
56
56
  },