node-opcua-client 2.168.0 → 2.170.1

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.
Files changed (38) hide show
  1. package/dist/client_monitored_item.d.ts +4 -4
  2. package/dist/client_monitored_item.js +6 -5
  3. package/dist/client_monitored_item.js.map +1 -1
  4. package/dist/client_monitored_item_base.d.ts +7 -7
  5. package/dist/client_monitored_item_toolbox.d.ts +5 -5
  6. package/dist/client_monitored_item_toolbox.js +26 -19
  7. package/dist/client_monitored_item_toolbox.js.map +1 -1
  8. package/dist/client_session_keepalive_manager.d.ts +2 -0
  9. package/dist/client_session_keepalive_manager.js +33 -5
  10. package/dist/client_session_keepalive_manager.js.map +1 -1
  11. package/dist/private/client_base_impl.js +28 -4
  12. package/dist/private/client_base_impl.js.map +1 -1
  13. package/dist/private/client_monitored_item_group_impl.d.ts +7 -6
  14. package/dist/private/client_monitored_item_group_impl.js +6 -8
  15. package/dist/private/client_monitored_item_group_impl.js.map +1 -1
  16. package/dist/private/client_monitored_item_impl.d.ts +10 -9
  17. package/dist/private/client_monitored_item_impl.js +40 -26
  18. package/dist/private/client_monitored_item_impl.js.map +1 -1
  19. package/dist/private/client_session_impl.d.ts +1 -0
  20. package/dist/private/client_session_impl.js +12 -0
  21. package/dist/private/client_session_impl.js.map +1 -1
  22. package/dist/private/client_subscription_impl.d.ts +7 -4
  23. package/dist/private/client_subscription_impl.js +101 -77
  24. package/dist/private/client_subscription_impl.js.map +1 -1
  25. package/dist/private/opcua_client_impl.d.ts +1 -0
  26. package/dist/private/opcua_client_impl.js +11 -0
  27. package/dist/private/opcua_client_impl.js.map +1 -1
  28. package/package.json +42 -42
  29. package/source/client_monitored_item.ts +5 -4
  30. package/source/client_monitored_item_base.ts +13 -8
  31. package/source/client_monitored_item_toolbox.ts +24 -20
  32. package/source/client_session_keepalive_manager.ts +44 -11
  33. package/source/private/client_base_impl.ts +27 -6
  34. package/source/private/client_monitored_item_group_impl.ts +15 -16
  35. package/source/private/client_monitored_item_impl.ts +56 -38
  36. package/source/private/client_session_impl.ts +29 -14
  37. package/source/private/client_subscription_impl.ts +151 -91
  38. package/source/private/opcua_client_impl.ts +13 -0
@@ -12,9 +12,19 @@ import type { DataValue } from "node-opcua-data-value";
12
12
  import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
13
13
  import { coerceNodeId } from "node-opcua-nodeid";
14
14
  import { ClientSecureChannelLayer } from "node-opcua-secure-channel";
15
+ import type { StatusCode } from "node-opcua-status-code";
16
+ import { StatusCodes } from "node-opcua-status-code";
15
17
  import type { ClientSessionImpl } from "./private/client_session_impl";
16
18
  import type { IClientBase } from "./private/i_private_client";
17
19
 
20
+ interface ServiceFaultAnnotatedError extends Error {
21
+ response?: {
22
+ responseHeader?: {
23
+ serviceResult?: StatusCode;
24
+ };
25
+ };
26
+ }
27
+
18
28
  const serverStatusStateNodeId = coerceNodeId(VariableIds.Server_ServerStatus_State);
19
29
 
20
30
  const debugLog = make_debugLog(__filename);
@@ -24,14 +34,18 @@ const warningLog = make_warningLog(__filename);
24
34
  export interface ClientSessionKeepAliveManagerEvents {
25
35
  on(event: "keepalive", eventHandler: (lastKnownServerState: ServerState, count: number) => void): this;
26
36
  on(event: "failure", eventHandler: () => void): this;
37
+ on(event: "keepalive_failure", eventHandler: () => void): this;
27
38
  }
28
39
 
40
+ const maxBackoffInterval = 60_000;
41
+
29
42
  export class ClientSessionKeepAliveManager extends EventEmitter implements ClientSessionKeepAliveManagerEvents {
30
43
  private readonly session: ClientSessionImpl;
31
44
  private timerId?: NodeJS.Timeout;
32
45
  private pingTimeout: number;
33
46
  private lastKnownState?: ServerState;
34
47
  private transactionInProgress = false;
48
+ private consecutiveFailures = 0;
35
49
  public count = 0;
36
50
  public checkInterval: number;
37
51
 
@@ -86,7 +100,9 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
86
100
  return; // stop here
87
101
  }
88
102
  if (this.timerId) {
89
- const timeout = Math.max(1, this.checkInterval - delta);
103
+ // When delta exceeds checkInterval it is an explicit backoff requested by _ping_server;
104
+ // otherwise delta is the time already consumed this cycle.
105
+ const timeout = delta > this.checkInterval ? delta : Math.max(1, this.checkInterval - delta);
90
106
  this.timerId = setTimeout(() => this.ping_server(), timeout);
91
107
  }
92
108
  });
@@ -153,25 +169,41 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
153
169
  (err: Error | null, dataValue?: DataValue) => {
154
170
  this.transactionInProgress = false;
155
171
 
156
- if (err || !dataValue || !dataValue.value) {
157
- if (err) {
158
- warningLog(
159
- chalk.cyan(" warning : ClientSessionKeepAliveManager#ping_server "),
160
- chalk.yellow(err.message)
161
- );
172
+ if (err) {
173
+ warningLog(chalk.cyan(" warning : ClientSessionKeepAliveManager#ping_server "), chalk.yellow(err.message));
174
+ const serviceFaultResponse = (err as ServiceFaultAnnotatedError).response;
175
+ if (serviceFaultResponse) {
176
+ const sc = serviceFaultResponse.responseHeader?.serviceResult;
177
+ if (sc?.equals(StatusCodes.BadSessionIdInvalid) || sc?.equals(StatusCodes.BadSessionClosed)) {
178
+ this.emit("failure");
179
+ warningLog(
180
+ "Keep alive has failed, considering a network outage is in place, forcing a reconnection"
181
+ );
182
+ terminateConnection(session._client);
183
+ resolve(0);
184
+ } else {
185
+ this.consecutiveFailures++;
186
+ warningLog("Keep alive received ServiceFault from server (session intact):", sc?.toString());
187
+ this.emit("keepalive_failure");
188
+ resolve(Math.min(this.checkInterval * 2 ** this.consecutiveFailures, maxBackoffInterval));
189
+ }
190
+ } else {
191
+ this.emit("failure");
192
+ warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
193
+ terminateConnection(session._client);
194
+ resolve(0);
162
195
  }
196
+ return;
197
+ }
198
+ if (!dataValue || !dataValue.value) {
163
199
  /**
164
200
  * @event failure
165
201
  * raised when the server is not responding or is responding with en error to
166
202
  * the keep alive read Variable value transaction
167
203
  */
168
204
  this.emit("failure");
169
-
170
- // also simulate a connection by closing the channel abruptly from our end ...
171
205
  warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
172
-
173
206
  terminateConnection(session._client);
174
-
175
207
  resolve(0);
176
208
  return;
177
209
  }
@@ -190,6 +222,7 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
190
222
  this.lastKnownState = newState;
191
223
  this.count++; // increase successful counter
192
224
  }
225
+ this.consecutiveFailures = 0;
193
226
  debugLog("emit keepalive");
194
227
  this.emit("keepalive", this.lastKnownState, this.count);
195
228
  resolve(0);
@@ -230,7 +230,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
230
230
  */
231
231
  async function _verify_serverCertificate(certificateManager: OPCUACertificateManager, serverCertificate: Certificate) {
232
232
  const status = await certificateManager.checkCertificate(serverCertificate);
233
- if (status !== StatusCodes.Good) {
233
+ if (!status.isGood()) {
234
234
  // c8 ignore next
235
235
  if (doDebug) {
236
236
  // do it again for debug purposes
@@ -1481,14 +1481,35 @@ export class ClientBaseImpl<Events extends OPCUAClientBaseEvents = OPCUAClientBa
1481
1481
  warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
1482
1482
  warningLog(" clientCertificateManager.rootDir = ", this.clientCertificateManager.rootDir);
1483
1483
 
1484
- const f = (b: Buffer) =>
1485
- ` ${b.toString("base64").replace(/(.{80})/g, "$1\n ")}`;
1486
-
1487
1484
  const chain = split_der(endpoint.serverCertificate);
1488
- warningLog(` server certificate contains ${chain.length} elements`);
1485
+ warningLog(` server certificate chain contains ${chain.length} element(s)`);
1489
1486
  for (let i = 0; i < chain.length; i++) {
1490
1487
  const c = chain[i];
1491
- warningLog("certificate", i, `\n${f(c)}`);
1488
+ const thumbprint = makeSHA1Thumbprint(c).toString("hex");
1489
+ try {
1490
+ const { exploreCertificate } = require("node-opcua-crypto");
1491
+ const info = exploreCertificate(c);
1492
+ const tbs = info.tbsCertificate;
1493
+ const cn = tbs.subject?.commonName ?? "unknown";
1494
+ const issuerCN = tbs.issuer?.commonName ?? "unknown";
1495
+ const isCA = tbs.extensions?.basicConstraints?.cA === true;
1496
+ const isSelfSigned = JSON.stringify(tbs.subject) === JSON.stringify(tbs.issuer);
1497
+ const certType = isCA
1498
+ ? (isSelfSigned ? "Root CA" : "Intermediate CA")
1499
+ : (isSelfSigned ? "Application (self-signed)" : "Application (CA-signed)");
1500
+ const ski = tbs.extensions?.subjectKeyIdentifier ?? "-";
1501
+ const aki = tbs.extensions?.authorityKeyIdentifier?.keyIdentifier ?? "-";
1502
+ const notBefore = tbs.validity.notBefore.toISOString();
1503
+ const notAfter = tbs.validity.notAfter.toISOString();
1504
+ warningLog(` [${i + 1}/${chain.length}] "${cn}" (${certType})`);
1505
+ warningLog(` thumbprint: ${thumbprint}`);
1506
+ warningLog(` issuer: "${issuerCN}"`);
1507
+ warningLog(` SKI: ${ski}`);
1508
+ warningLog(` AKI: ${aki}`);
1509
+ warningLog(` validity: ${notBefore} → ${notAfter}`);
1510
+ } catch {
1511
+ warningLog(` [${i + 1}/${chain.length}] thumbprint: ${thumbprint} (details unavailable)`);
1512
+ }
1492
1513
  }
1493
1514
  if (chain.length > 1) {
1494
1515
  warningLog(
@@ -2,14 +2,14 @@
2
2
  * @module node-opcua-client-private
3
3
  */
4
4
  // tslint:disable:no-empty
5
- import { EventEmitter } from "events";
5
+ import { EventEmitter } from "node:events";
6
6
  import { assert } from "node-opcua-assert";
7
7
  import { coerceTimestampsToReturn, type DataValue, TimestampsToReturn } from "node-opcua-data-value";
8
8
  import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
9
- import { resolveNodeId } from "node-opcua-nodeid";
9
+ import { NodeId, resolveNodeId } from "node-opcua-nodeid";
10
10
  import { MonitoringMode, type MonitoringParametersOptions } from "node-opcua-service-subscription";
11
11
  import type { Callback, ErrorCallback, StatusCode } from "node-opcua-status-code";
12
- import type { ReadValueIdOptions } from "node-opcua-types";
12
+ import type { MonitoredItemModifyResult, ReadValueIdOptions } from "node-opcua-types";
13
13
  import type { ClientMonitoredItemBase } from "../client_monitored_item_base";
14
14
  import { ClientMonitoredItemGroup } from "../client_monitored_item_group";
15
15
  import { type ClientMonitoredItemBaseEx, ClientMonitoredItemToolbox } from "../client_monitored_item_toolbox";
@@ -17,8 +17,7 @@ import type { ClientSubscription } from "../client_subscription";
17
17
  import { ClientMonitoredItemImpl } from "./client_monitored_item_impl";
18
18
  import type { ClientSubscriptionImpl } from "./client_subscription_impl";
19
19
 
20
- const debugLog = make_debugLog(__filename);
21
- const doDebug = checkDebugFlag(__filename);
20
+
22
21
  const warningLog = make_warningLog(__filename);
23
22
 
24
23
  /**
@@ -38,7 +37,7 @@ export class ClientMonitoredItemGroupImpl extends EventEmitter implements Client
38
37
 
39
38
  constructor(
40
39
  subscription: ClientSubscription,
41
- itemsToMonitor: any[],
40
+ itemsToMonitor: ReadValueIdOptions[],
42
41
  monitoringParameters: MonitoringParametersOptions,
43
42
  timestampsToReturn: TimestampsToReturn,
44
43
  monitoringMode: MonitoringMode = MonitoringMode.Reporting
@@ -47,7 +46,7 @@ export class ClientMonitoredItemGroupImpl extends EventEmitter implements Client
47
46
  assert(Array.isArray(itemsToMonitor));
48
47
  // Try to resolve the nodeId and fail fast if we can't.
49
48
  itemsToMonitor.forEach((itemToMonitor: ReadValueIdOptions) => {
50
- itemToMonitor.nodeId = resolveNodeId(itemToMonitor.nodeId!);
49
+ itemToMonitor.nodeId = resolveNodeId(itemToMonitor.nodeId || NodeId.nullNodeId);
51
50
  });
52
51
 
53
52
  timestampsToReturn = coerceTimestampsToReturn(timestampsToReturn);
@@ -82,8 +81,8 @@ export class ClientMonitoredItemGroupImpl extends EventEmitter implements Client
82
81
  )
83
82
  .join("\n") +
84
83
  "\n];\n";
85
- ret += "timestampsToReturn: " + TimestampsToReturn[this.timestampsToReturn] + "\n";
86
- ret += "monitoringMode " + MonitoringMode[this.monitoringMode];
84
+ ret += `timestampsToReturn: ${TimestampsToReturn[this.timestampsToReturn]}\n`;
85
+ ret += `monitoringMode ${MonitoringMode[this.monitoringMode]}`;
87
86
  return ret;
88
87
  }
89
88
 
@@ -109,13 +108,13 @@ export class ClientMonitoredItemGroupImpl extends EventEmitter implements Client
109
108
  /**
110
109
 
111
110
  */
112
- public async modify(parameters: MonitoringParametersOptions): Promise<StatusCode>;
113
- public async modify(parameters: MonitoringParametersOptions, timestampsToReturn: TimestampsToReturn): Promise<StatusCode>;
114
- public modify(parameters: MonitoringParametersOptions, callback: (err: Error | null, statusCode?: StatusCode) => void): void;
111
+ public async modify(parameters: MonitoringParametersOptions): Promise<MonitoredItemModifyResult>;
112
+ public async modify(parameters: MonitoringParametersOptions, timestampsToReturn: TimestampsToReturn): Promise<MonitoredItemModifyResult>;
113
+ public modify(parameters: MonitoringParametersOptions, callback: Callback<MonitoredItemModifyResult>): void;
115
114
  public modify(
116
115
  parameters: MonitoringParametersOptions,
117
116
  timestampsToReturn: TimestampsToReturn | null,
118
- callback: (err: Error | null, statusCode?: StatusCode) => void
117
+ callback: Callback<MonitoredItemModifyResult>
119
118
  ): void;
120
119
  public modify(...args: any[]): any {
121
120
  if (args.length === 2) {
@@ -223,8 +222,8 @@ ClientMonitoredItemGroupImpl.prototype.modify = withCallback(ClientMonitoredItem
223
222
 
224
223
  ClientMonitoredItemGroup.create = (
225
224
  subscription: ClientSubscription,
226
- itemsToMonitor: any[],
227
- monitoringParameters: any,
225
+ itemsToMonitor: ReadValueIdOptions[],
226
+ monitoringParameters: MonitoringParametersOptions,
228
227
  timestampsToReturn: TimestampsToReturn
229
228
  ) => {
230
229
  const monitoredItemGroup = new ClientMonitoredItemGroupImpl(
@@ -238,7 +237,7 @@ ClientMonitoredItemGroup.create = (
238
237
  if (err) {
239
238
  return;
240
239
  }
241
- monitoredItemGroup._monitor((err1?: Error) => {
240
+ monitoredItemGroup._monitor((_err1?: Error) => {
242
241
  /** */
243
242
  });
244
243
  });
@@ -3,7 +3,7 @@
3
3
  */
4
4
  // tslint:disable:unified-signatures
5
5
  // tslint:disable:no-empty
6
- import { EventEmitter } from "events";
6
+ import { EventEmitter } from "node:events";
7
7
  import { assert } from "node-opcua-assert";
8
8
 
9
9
  import { AttributeIds } from "node-opcua-data-model";
@@ -11,7 +11,7 @@ import { coerceTimestampsToReturn, type DataValue } from "node-opcua-data-value"
11
11
  import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
12
12
  import type { ExtensionObject } from "node-opcua-extension-object";
13
13
  import { EventFilter } from "node-opcua-service-filter";
14
- import { ReadValueId, type ReadValueIdOptions, type TimestampsToReturn } from "node-opcua-service-read";
14
+ import { ReadValueId, type ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
15
15
  import {
16
16
  type MonitoredItemCreateResult,
17
17
  type MonitoredItemModifyResult,
@@ -27,9 +27,9 @@ import { type ClientMonitoredItemBaseEx, ClientMonitoredItemToolbox } from "../c
27
27
  import type { ClientSubscription } from "../client_subscription";
28
28
  import { ClientMonitoredItem_create, type ClientSubscriptionImpl } from "./client_subscription_impl";
29
29
 
30
- const debugLog = make_debugLog(__filename);
30
+ const _debugLog = make_debugLog(__filename);
31
31
  const warningLog = make_warningLog(__filename);
32
- const doDebug = checkDebugFlag(__filename);
32
+ const _doDebug = checkDebugFlag(__filename);
33
33
 
34
34
  export type PrepareForMonitoringResult =
35
35
  | { error: string }
@@ -58,7 +58,7 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
58
58
  public subscription: ClientSubscriptionImpl;
59
59
  public monitoringMode: MonitoringMode;
60
60
  public statusCode: StatusCode;
61
- public monitoredItemId?: any;
61
+ public monitoredItemId?: number;
62
62
  public result?: MonitoredItemCreateResult;
63
63
  public filterResult?: ExtensionObject;
64
64
  public timestampsToReturn: TimestampsToReturn;
@@ -66,6 +66,8 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
66
66
  #pendingDataValue?: DataValue[];
67
67
  #pendingEvents?: Variant[][];
68
68
 
69
+ #terminated?: boolean;
70
+
69
71
  public internalSetMonitoringMode(monitoringMode: MonitoringMode): void {
70
72
  this.monitoringMode = monitoringMode;
71
73
  }
@@ -93,49 +95,67 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
93
95
  this.timestampsToReturn = timestampsToReturn;
94
96
  }
95
97
 
98
+ public toJSON(): Record<string, string | number | undefined> {
99
+ return {
100
+ itemToMonitor: this.itemToMonitor.toString(),
101
+ monitoringParameters: this.monitoringParameters.toString(),
102
+ timestampsToReturn: TimestampsToReturn[this.timestampsToReturn],
103
+ monitoredItemId: this.monitoredItemId,
104
+ statusCode: this.statusCode?.toString(),
105
+ result: this.result?.toString()
106
+ };
107
+ }
108
+
96
109
  public toString(): string {
97
110
  let ret = "";
98
- ret += "itemToMonitor: " + this.itemToMonitor.toString() + "\n";
99
- ret += "monitoringParameters: " + this.monitoringParameters.toString() + "\n";
100
- ret += "timestampsToReturn: " + this.timestampsToReturn.toString() + "\n";
101
- ret += "itemToMonitor " + this.itemToMonitor.nodeId + "\n";
102
- ret += "statusCode " + this.statusCode?.toString() + "\n";
103
- ret += "result =" + this.result?.toString() + "\n";
111
+ ret += `itemToMonitor: ${this.itemToMonitor.toString()}\n`;
112
+ ret += `monitoringParameters: ${this.monitoringParameters.toString()}\n`;
113
+ ret += `timestampsToReturn: ${TimestampsToReturn[this.timestampsToReturn]}\n`;
114
+ ret += `monitoredItemId: ${this.monitoredItemId}\n`;
115
+ ret += `statusCode: ${this.statusCode?.toString()}\n`;
116
+ ret += `result: ${this.result?.toString()}\n`;
104
117
  return ret;
105
118
  }
106
119
 
120
+ public [Symbol.for("nodejs.util.inspect.custom")](): string {
121
+ return this.toString();
122
+ }
123
+
107
124
  /**
108
125
  * terminate the monitored item by removing the MonitoredItem from its subscription
109
126
  */
110
127
  public async terminate(): Promise<void>;
111
- public terminate(done: ErrorCallback): void;
112
- public terminate(...args: any[]): any {
113
- const done = args[0];
114
- assert(typeof done === "function");
115
-
128
+ public terminate(callback: ErrorCallback): void;
129
+ public terminate(callback?: ErrorCallback): Promise<void> | undefined {
116
130
  const subscription = this.subscription as ClientSubscriptionImpl;
117
131
  subscription._delete_monitored_items([this], (err?: Error) => {
118
- if (done) {
119
- done(err);
132
+ if (callback) {
133
+ callback(err);
120
134
  }
121
135
  });
136
+ return undefined;
122
137
  }
123
138
 
124
- public async modify(parameters: MonitoringParametersOptions): Promise<StatusCode>;
125
- public async modify(parameters: MonitoringParametersOptions, timestampsToReturn: TimestampsToReturn): Promise<StatusCode>;
126
- public modify(parameters: MonitoringParametersOptions, callback: (err: Error | null, statusCode?: StatusCode) => void): void;
139
+ public async modify(parameters: MonitoringParametersOptions): Promise<MonitoredItemModifyResult>;
140
+ public async modify(
141
+ parameters: MonitoringParametersOptions,
142
+ timestampsToReturn: TimestampsToReturn
143
+ ): Promise<MonitoredItemModifyResult>;
144
+ public modify(parameters: MonitoringParametersOptions, callback: Callback<MonitoredItemModifyResult>): void;
127
145
  public modify(
128
146
  parameters: MonitoringParametersOptions,
129
147
  timestampsToReturn: TimestampsToReturn | null,
130
- callback: (err: Error | null, statusCode?: StatusCode) => void
148
+ callback: Callback<MonitoredItemModifyResult>
131
149
  ): void;
132
- public modify(...args: any[]): any {
150
+ public modify(...args: unknown[]): undefined | Promise<MonitoredItemModifyResult> {
151
+ // remember we are garantied to be in a callback env here.
133
152
  if (args.length === 2) {
134
- return this.modify(args[0], null, args[1]);
153
+ this.modify(args[0] as MonitoringParametersOptions, null, args[1] as Callback<MonitoredItemModifyResult>);
154
+ return undefined;
135
155
  }
136
156
  const parameters = args[0] as MonitoringParametersOptions;
137
157
  const timestampsToReturn = args[1] as TimestampsToReturn;
138
- const callback = args[2];
158
+ const callback = args[2] as Callback<MonitoredItemModifyResult>;
139
159
  this.timestampsToReturn = timestampsToReturn || this.timestampsToReturn;
140
160
  ClientMonitoredItemToolbox._toolbox_modify(
141
161
  this.subscription,
@@ -149,26 +169,25 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
149
169
  if (!results) {
150
170
  return callback(new Error("internal error"));
151
171
  }
152
- assert(results!.length === 1);
153
- callback(null, results![0]);
172
+ assert(results?.length === 1);
173
+ callback(null, results[0]);
154
174
  }
155
175
  );
176
+ return undefined;
156
177
  }
157
178
 
158
179
  public async setMonitoringMode(monitoringMode: MonitoringMode): Promise<StatusCode>;
159
180
  public setMonitoringMode(monitoringMode: MonitoringMode, callback: Callback<StatusCode>): void;
160
- public setMonitoringMode(...args: any[]): any {
161
- const monitoringMode = args[0] as MonitoringMode;
162
- const callback = args[1] as Callback<StatusCode>;
163
-
181
+ public setMonitoringMode(monitoringMode: MonitoringMode, callback?: Callback<StatusCode>): undefined | Promise<StatusCode> {
164
182
  ClientMonitoredItemToolbox._toolbox_setMonitoringMode(
165
183
  this.subscription,
166
184
  [this],
167
185
  monitoringMode,
168
186
  (err?: Error | null, statusCodes?: StatusCode[]) => {
169
- callback(err ? err : null, statusCodes ? statusCodes[0] : undefined);
187
+ callback?.(err ? err : null, statusCodes ? statusCodes[0] : undefined);
170
188
  }
171
189
  );
190
+ return undefined;
172
191
  }
173
192
 
174
193
  /**
@@ -260,7 +279,7 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
260
279
  // toDO
261
280
 
262
281
  // note : the EventFilter is used when monitoring Events.
263
- this.monitoringParameters.filter = this.monitoringParameters.filter! || new EventFilter({});
282
+ this.monitoringParameters.filter = this.monitoringParameters.filter || new EventFilter({});
264
283
 
265
284
  const filter = this.monitoringParameters.filter;
266
285
 
@@ -365,14 +384,13 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
365
384
  }
366
385
 
367
386
  public _terminate_and_emit(err?: Error): void {
368
- if ((this as any)._terminated) {
387
+ if (this.#terminated) {
369
388
  return; // already terminated
370
389
  }
371
390
  if (err) {
372
391
  this.emit("err", err.message);
373
392
  }
374
- assert(!(this as any)._terminated);
375
- (this as any)._terminated = true;
393
+ this.#terminated = true;
376
394
  /**
377
395
  * Notify the observer that this monitored item has been terminated.
378
396
  * @event terminated
@@ -390,7 +408,7 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
390
408
  // tslint:disable:max-line-length
391
409
  import { withCallback } from "thenify-ex";
392
410
 
393
- const opts = { multiArgs: false };
411
+ const _opts = { multiArgs: false };
394
412
 
395
413
  ClientMonitoredItemImpl.prototype.terminate = withCallback(ClientMonitoredItemImpl.prototype.terminate);
396
414
  ClientMonitoredItemImpl.prototype.setMonitoringMode = withCallback(ClientMonitoredItemImpl.prototype.setMonitoringMode);
@@ -400,7 +418,7 @@ ClientMonitoredItem.create = (
400
418
  subscription: ClientSubscription,
401
419
  itemToMonitor: ReadValueIdOptions,
402
420
  monitoringParameters: MonitoringParametersOptions,
403
- timestampsToReturn: TimestampsToReturn,
421
+ timestampsToReturn: TimestampsToReturn = TimestampsToReturn.Neither,
404
422
  monitoringMode: MonitoringMode = MonitoringMode.Reporting
405
423
  ): ClientMonitoredItem => {
406
424
  return ClientMonitoredItem_create(subscription, itemToMonitor, monitoringParameters, timestampsToReturn, monitoringMode);
@@ -268,6 +268,21 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
268
268
  return this._client ? this._client.isReconnecting || this._reconnecting?.reconnecting : false;
269
269
  }
270
270
 
271
+ public toJSON(): Record<string, string | number | boolean> {
272
+ return {
273
+ name: this.name,
274
+ sessionId: this.sessionId.toString(),
275
+ timeout: this.timeout,
276
+ state: this._closed ? "closed" : "active",
277
+ isReconnecting: this.isReconnecting ? "true" : "false"
278
+ };
279
+ }
280
+
281
+
282
+ public [Symbol.for("nodejs.util.inspect.custom")](): string {
283
+ return this.toString();
284
+ }
285
+
271
286
  protected resolveNodeId(nodeId: NodeIdLike): NodeIdLike {
272
287
  return resolveNodeId(nodeId);
273
288
  }
@@ -405,8 +420,8 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
405
420
  if (r.references && r.references.length > this.requestedMaxReferencesPerNode) {
406
421
  warningLog(
407
422
  chalk.yellow("warning") +
408
- " BrowseResponse : the server didn't take into" +
409
- " account our requestedMaxReferencesPerNode "
423
+ " BrowseResponse : the server didn't take into" +
424
+ " account our requestedMaxReferencesPerNode "
410
425
  );
411
426
  warningLog(" this.requestedMaxReferencesPerNode= " + this.requestedMaxReferencesPerNode);
412
427
  warningLog(" got " + r.references.length + "for " + nodesToBrowse[i].nodeId.toString());
@@ -415,7 +430,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
415
430
  }
416
431
  }
417
432
  for (const r of results) {
418
- r.references = r.references || /* c8 ignore next */ [];
433
+ r.references = r.references || /* c8 ignore next */[];
419
434
  }
420
435
  assert(results[0] instanceof BrowseResult);
421
436
  return callback(null, isArray ? results : results[0]);
@@ -710,7 +725,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
710
725
  return callback(new Error(response.responseHeader.serviceResult.toString()));
711
726
  }
712
727
 
713
- response.results = response.results || /* c8 ignore next */ [];
728
+ response.results = response.results || /* c8 ignore next */[];
714
729
 
715
730
  // perform ExtensionObject resolution
716
731
  const promises = response.results.map(async (result) => {
@@ -855,7 +870,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
855
870
  return callback(new Error(response.responseHeader.serviceResult.toString()));
856
871
  }
857
872
 
858
- response.results = response.results || /* c8 ignore next */ [];
873
+ response.results = response.results || /* c8 ignore next */[];
859
874
 
860
875
  assert(nodesToRead.length === response.results.length);
861
876
 
@@ -994,7 +1009,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
994
1009
  if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
995
1010
  return callback(new Error(response.responseHeader.serviceResult.toString()));
996
1011
  }
997
- response.results = response.results || /* c8 ignore next */ [];
1012
+ response.results = response.results || /* c8 ignore next */[];
998
1013
  assert(nodesToWrite.length === response.results.length);
999
1014
  callback(null, isArray ? response.results : response.results[0]);
1000
1015
  });
@@ -1189,7 +1204,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1189
1204
  warningLog(
1190
1205
  chalk.yellow(
1191
1206
  "please make sure to refactor your code and check that " +
1192
- "the second argument of your callback function is named"
1207
+ "the second argument of your callback function is named"
1193
1208
  ),
1194
1209
  chalk.cyan("dataValue" + (isArray ? "s" : ""))
1195
1210
  );
@@ -1223,7 +1238,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1223
1238
  // perform ExtensionObject resolution
1224
1239
  promoteOpaqueStructure(this, response.results!)
1225
1240
  .then(() => {
1226
- response.results = response.results || /* c8 ignore next */ [];
1241
+ response.results = response.results || /* c8 ignore next */[];
1227
1242
  callback(null, isArray ? response.results : response.results[0]);
1228
1243
  })
1229
1244
  .catch((err) => {
@@ -1401,7 +1416,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1401
1416
  if (!response) {
1402
1417
  return callback(new Error("Internal Error"));
1403
1418
  }
1404
- response.results = response.results || /* c8 ignore next */ [];
1419
+ response.results = response.results || /* c8 ignore next */[];
1405
1420
  callback(err, isArray ? response.results : response.results[0]);
1406
1421
  }
1407
1422
  );
@@ -1437,7 +1452,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1437
1452
  if (!response || !(response instanceof TranslateBrowsePathsToNodeIdsResponse)) {
1438
1453
  return callback(new Error("Internal Error"));
1439
1454
  }
1440
- response.results = response.results || /* c8 ignore next */ [];
1455
+ response.results = response.results || /* c8 ignore next */[];
1441
1456
 
1442
1457
  callback(null, isArray ? response.results : response.results[0]);
1443
1458
  });
@@ -1586,9 +1601,9 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1586
1601
  if (response.responseHeader.serviceResult.isNot(StatusCodes.Good)) {
1587
1602
  err = new Error(
1588
1603
  " ServiceResult is " +
1589
- response.responseHeader.serviceResult.toString() +
1590
- " request was " +
1591
- request.constructor.name
1604
+ response.responseHeader.serviceResult.toString() +
1605
+ " request was " +
1606
+ request.constructor.name
1592
1607
  );
1593
1608
 
1594
1609
  if (response && response.responseHeader.serviceDiagnostics) {
@@ -1837,7 +1852,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession, Re
1837
1852
  return callback(new Error("Internal Error"));
1838
1853
  }
1839
1854
 
1840
- response.registeredNodeIds = response.registeredNodeIds || /* c8 ignore next */ [];
1855
+ response.registeredNodeIds = response.registeredNodeIds || /* c8 ignore next */[];
1841
1856
 
1842
1857
  callback(null, response.registeredNodeIds);
1843
1858
  });