node-opcua-client 2.177.0 → 2.179.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.
Files changed (83) hide show
  1. package/dist/alarms_and_conditions/client_alarm_tools.js +7 -5
  2. package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
  3. package/dist/alarms_and_conditions/client_tools.js +38 -28
  4. package/dist/alarms_and_conditions/client_tools.js.map +1 -1
  5. package/dist/client_base.d.ts +5 -0
  6. package/dist/client_base.js.map +1 -1
  7. package/dist/client_monitored_item.d.ts +1 -1
  8. package/dist/client_monitored_item.js +4 -2
  9. package/dist/client_monitored_item.js.map +1 -1
  10. package/dist/client_monitored_item_group.d.ts +4 -3
  11. package/dist/client_monitored_item_group.js +8 -5
  12. package/dist/client_monitored_item_group.js.map +1 -1
  13. package/dist/client_monitored_item_toolbox.js +4 -2
  14. package/dist/client_monitored_item_toolbox.js.map +1 -1
  15. package/dist/client_session.d.ts +9 -2
  16. package/dist/client_session_keepalive_manager.d.ts +1 -1
  17. package/dist/client_session_keepalive_manager.js +50 -29
  18. package/dist/client_session_keepalive_manager.js.map +1 -1
  19. package/dist/client_subscription.d.ts +2 -2
  20. package/dist/client_subscription.js +3 -1
  21. package/dist/client_subscription.js.map +1 -1
  22. package/dist/common.d.ts +3 -3
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/opcua_client.js +1 -0
  27. package/dist/opcua_client.js.map +1 -1
  28. package/dist/private/client_base_impl.js +178 -77
  29. package/dist/private/client_base_impl.js.map +1 -1
  30. package/dist/private/client_monitored_item_group_impl.d.ts +1 -0
  31. package/dist/private/client_monitored_item_group_impl.js +6 -8
  32. package/dist/private/client_monitored_item_group_impl.js.map +1 -1
  33. package/dist/private/client_monitored_item_impl.js +0 -4
  34. package/dist/private/client_monitored_item_impl.js.map +1 -1
  35. package/dist/private/client_publish_engine.js +62 -28
  36. package/dist/private/client_publish_engine.js.map +1 -1
  37. package/dist/private/client_session_impl.d.ts +49 -17
  38. package/dist/private/client_session_impl.js +240 -143
  39. package/dist/private/client_session_impl.js.map +1 -1
  40. package/dist/private/client_subscription_impl.js +15 -12
  41. package/dist/private/client_subscription_impl.js.map +1 -1
  42. package/dist/private/i_private_client.d.ts +1 -1
  43. package/dist/private/opcua_client_impl.js +44 -9
  44. package/dist/private/opcua_client_impl.js.map +1 -1
  45. package/dist/private/reconnection/client_publish_engine_reconnection.js +17 -7
  46. package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
  47. package/dist/private/reconnection/client_subscription_reconnection.js +11 -7
  48. package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
  49. package/dist/private/reconnection/reconnection.js +31 -14
  50. package/dist/private/reconnection/reconnection.js.map +1 -1
  51. package/dist/reverse/client_reverse_connect.js.map +1 -1
  52. package/dist/tools/findservers.js.map +1 -1
  53. package/dist/tools/read_history_server_capabilities.d.ts +2 -1
  54. package/dist/tools/read_history_server_capabilities.js +6 -3
  55. package/dist/tools/read_history_server_capabilities.js.map +1 -1
  56. package/package.json +50 -50
  57. package/source/alarms_and_conditions/client_alarm_tools.ts +10 -8
  58. package/source/alarms_and_conditions/client_tools.ts +71 -30
  59. package/source/client_base.ts +5 -1
  60. package/source/client_monitored_item.ts +10 -9
  61. package/source/client_monitored_item_base.ts +2 -8
  62. package/source/client_monitored_item_group.ts +13 -10
  63. package/source/client_monitored_item_toolbox.ts +4 -2
  64. package/source/client_session.ts +10 -3
  65. package/source/client_session_keepalive_manager.ts +72 -55
  66. package/source/client_subscription.ts +6 -3
  67. package/source/common.ts +4 -0
  68. package/source/index.ts +1 -1
  69. package/source/opcua_client.ts +1 -0
  70. package/source/private/client_base_impl.ts +244 -113
  71. package/source/private/client_monitored_item_group_impl.ts +17 -18
  72. package/source/private/client_monitored_item_impl.ts +0 -4
  73. package/source/private/client_publish_engine.ts +78 -40
  74. package/source/private/client_session_impl.ts +393 -236
  75. package/source/private/client_subscription_impl.ts +20 -25
  76. package/source/private/i_private_client.ts +1 -1
  77. package/source/private/opcua_client_impl.ts +51 -9
  78. package/source/private/reconnection/client_publish_engine_reconnection.ts +22 -21
  79. package/source/private/reconnection/client_subscription_reconnection.ts +12 -8
  80. package/source/private/reconnection/reconnection.ts +35 -18
  81. package/source/reverse/client_reverse_connect.ts +11 -3
  82. package/source/tools/findservers.ts +0 -1
  83. package/source/tools/read_history_server_capabilities.ts +9 -7
@@ -2,8 +2,8 @@
2
2
  * @module node-opcua-client
3
3
  */
4
4
 
5
+ import { EventEmitter } from "node:events";
5
6
  import chalk from "chalk";
6
- import { EventEmitter } from "events";
7
7
  import { assert } from "node-opcua-assert";
8
8
  import { AttributeIds } from "node-opcua-basic-types";
9
9
  import { ServerState } from "node-opcua-common";
@@ -11,20 +11,11 @@ import { VariableIds } from "node-opcua-constants";
11
11
  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
- import { ClientSecureChannelLayer } from "node-opcua-secure-channel";
15
- import type { StatusCode } from "node-opcua-status-code";
14
+ import { ClientSecureChannelLayer, type ServiceFaultAnnotatedError } from "node-opcua-secure-channel";
16
15
  import { StatusCodes } from "node-opcua-status-code";
17
16
  import type { ClientSessionImpl } from "./private/client_session_impl";
18
17
  import type { IClientBase } from "./private/i_private_client";
19
18
 
20
- interface ServiceFaultAnnotatedError extends Error {
21
- response?: {
22
- responseHeader?: {
23
- serviceResult?: StatusCode;
24
- };
25
- };
26
- }
27
-
28
19
  const serverStatusStateNodeId = coerceNodeId(VariableIds.Server_ServerStatus_State);
29
20
 
30
21
  const debugLog = make_debugLog(__filename);
@@ -86,26 +77,40 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
86
77
 
87
78
  public stop(): void {
88
79
  if (this.timerId) {
89
- debugLog("ClientSessionKeepAliveManager#stop");
80
+ // c8 ignore next
81
+ doDebug && debugLog("ClientSessionKeepAliveManager#stop");
90
82
  clearTimeout(this.timerId);
91
83
  this.timerId = undefined;
92
84
  } else {
93
- debugLog("warning ClientSessionKeepAliveManager#stop ignore (already stopped)");
85
+ // c8 ignore next
86
+ doDebug && debugLog("warning ClientSessionKeepAliveManager#stop ignore (already stopped)");
94
87
  }
95
88
  }
96
89
 
97
90
  private ping_server() {
98
- this._ping_server().then((delta) => {
99
- if (!this.session || this.session.hasBeenClosed()) {
100
- return; // stop here
101
- }
102
- if (this.timerId) {
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);
106
- this.timerId = setTimeout(() => this.ping_server(), timeout);
107
- }
108
- });
91
+ this._ping_server()
92
+ .catch((err) => {
93
+ // _ping_server must never reject: transactionInProgress would stay latched and the
94
+ // timer chain would stop, silently killing the keep-alive for the life of the
95
+ // session. Recover the cycle instead, and try again at the normal cadence.
96
+ warningLog(
97
+ chalk.cyan("ClientSessionKeepAliveManager#ping_server unexpected error "),
98
+ chalk.yellow(err instanceof Error ? err.message : String(err))
99
+ );
100
+ this.transactionInProgress = false;
101
+ return this.checkInterval;
102
+ })
103
+ .then((nextCheckDelay) => {
104
+ if (!this.session || this.session.hasBeenClosed()) {
105
+ return; // stop here
106
+ }
107
+ if (this.timerId) {
108
+ // _ping_server returns how long to wait before the next check: checkInterval
109
+ // in steady state, the residual wait when it skipped the ping because we heard
110
+ // from the server recently, or an explicit backoff after consecutive faults.
111
+ this.timerId = setTimeout(() => this.ping_server(), Math.max(1, nextCheckDelay));
112
+ }
113
+ });
109
114
  }
110
115
  /**
111
116
  * @private
@@ -117,45 +122,52 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
117
122
  private async _ping_server(): Promise<number> {
118
123
  const session = this.session;
119
124
  if (!session || session.isReconnecting) {
120
- debugLog("ClientSessionKeepAliveManager#ping_server => no session available");
121
- return 0;
125
+ // c8 ignore next
126
+ doDebug && debugLog("ClientSessionKeepAliveManager#ping_server => no session available");
127
+ return this.checkInterval;
122
128
  }
123
129
 
124
130
  if (!this.timerId) {
125
- return 0; // keep-alive has been canceled ....
131
+ return this.checkInterval; // keep-alive has been canceled ....
126
132
  }
127
133
  const now = Date.now();
128
134
 
129
135
  const timeSinceLastServerContact = now - session.lastResponseReceivedTime.getTime();
130
136
  if (timeSinceLastServerContact < this.pingTimeout) {
131
- debugLog(
132
- "ClientSessionKeepAliveManager#ping_server skipped because last communication with server was not that long ago ping timeout=",
133
- Math.round(this.pingTimeout),
134
- "timeSinceLastServerContact = ",
135
- timeSinceLastServerContact
136
- );
137
- // no need to send a ping yet
138
- return timeSinceLastServerContact - this.pingTimeout;
137
+ // c8 ignore next
138
+ doDebug &&
139
+ debugLog(
140
+ "ClientSessionKeepAliveManager#ping_server skipped because last communication with server was not that long ago ping timeout=",
141
+ Math.round(this.pingTimeout),
142
+ "timeSinceLastServerContact = ",
143
+ timeSinceLastServerContact
144
+ );
145
+ // no need to send a ping yet: come back when the quiet period is actually over
146
+ return this.pingTimeout - timeSinceLastServerContact;
139
147
  }
140
148
 
141
149
  if (session.isReconnecting) {
142
- debugLog("ClientSessionKeepAliveManager#ping_server skipped because client is reconnecting");
143
- return 0;
150
+ // c8 ignore next
151
+ doDebug && debugLog("ClientSessionKeepAliveManager#ping_server skipped because client is reconnecting");
152
+ return this.checkInterval;
144
153
  }
145
154
  if (session.hasBeenClosed()) {
146
- debugLog("ClientSessionKeepAliveManager#ping_server skipped because client is reconnecting");
147
- return 0;
155
+ // c8 ignore next
156
+ doDebug && debugLog("ClientSessionKeepAliveManager#ping_server skipped because client is reconnecting");
157
+ return this.checkInterval;
148
158
  }
149
- debugLog(
150
- "ClientSessionKeepAliveManager#ping_server timeSinceLastServerContact=",
151
- timeSinceLastServerContact,
152
- "timeout",
153
- this.session.timeout
154
- );
159
+ // c8 ignore next
160
+ doDebug &&
161
+ debugLog(
162
+ "ClientSessionKeepAliveManager#ping_server timeSinceLastServerContact=",
163
+ timeSinceLastServerContact,
164
+ "timeout",
165
+ this.session.timeout
166
+ );
155
167
 
156
168
  if (this.transactionInProgress) {
157
169
  // readVariable already taking place ! Ignore
158
- return 0;
170
+ return this.checkInterval;
159
171
  }
160
172
  this.transactionInProgress = true;
161
173
  // Server_ServerStatus_State
@@ -180,7 +192,7 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
180
192
  "Keep alive has failed, considering a network outage is in place, forcing a reconnection"
181
193
  );
182
194
  terminateConnection(session._client);
183
- resolve(0);
195
+ resolve(this.checkInterval);
184
196
  } else {
185
197
  if (sc?.equals(StatusCodes.BadInvalidTimestamp)) {
186
198
  // BadInvalidTimestamp (OPC UA Part 4 7.38.2, Table 178:
@@ -204,9 +216,13 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
204
216
  // See: https://reference.opcfoundation.org/Core/Part4/v105/docs/7.38.2
205
217
  // https://reference.opcfoundation.org/Core/Part4/v105/docs/7.32
206
218
  this.consecutiveFailures = 0;
207
- debugLog("emit keepalive (BadInvalidTimestamp: session alive, clock skew on request timestamp)");
219
+ // c8 ignore next
220
+ doDebug &&
221
+ debugLog(
222
+ "emit keepalive (BadInvalidTimestamp: session alive, clock skew on request timestamp)"
223
+ );
208
224
  this.emit("keepalive", this.lastKnownState ?? ServerState.Unknown, this.count);
209
- resolve(0);
225
+ resolve(this.checkInterval);
210
226
  return;
211
227
  }
212
228
  this.consecutiveFailures++;
@@ -218,11 +234,11 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
218
234
  this.emit("failure");
219
235
  warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
220
236
  terminateConnection(session._client);
221
- resolve(0);
237
+ resolve(this.checkInterval);
222
238
  }
223
239
  return;
224
240
  }
225
- if (!dataValue || !dataValue.value) {
241
+ if (!dataValue?.value) {
226
242
  /**
227
243
  * @event failure
228
244
  * raised when the server is not responding or is responding with en error to
@@ -231,7 +247,7 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
231
247
  this.emit("failure");
232
248
  warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
233
249
  terminateConnection(session._client);
234
- resolve(0);
250
+ resolve(this.checkInterval);
235
251
  return;
236
252
  }
237
253
 
@@ -250,9 +266,10 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
250
266
  this.count++; // increase successful counter
251
267
  }
252
268
  this.consecutiveFailures = 0;
253
- debugLog("emit keepalive");
269
+ // c8 ignore next
270
+ doDebug && debugLog("emit keepalive");
254
271
  this.emit("keepalive", this.lastKnownState, this.count);
255
- resolve(0);
272
+ resolve(this.checkInterval);
256
273
  }
257
274
  );
258
275
  });
@@ -262,7 +279,7 @@ export class ClientSessionKeepAliveManager extends EventEmitter implements Clien
262
279
  function terminateConnection(client: IClientBase | null) {
263
280
  if (!client) return;
264
281
 
265
- const channel: ClientSecureChannelLayer = (client as any)._secureChannel;
282
+ const channel: ClientSecureChannelLayer | null = client._secureChannel;
266
283
  if (!channel) {
267
284
  return;
268
285
  }
@@ -2,8 +2,7 @@
2
2
  * @module node-opcua-client
3
3
  */
4
4
 
5
- // tslint:disable:unified-signatures
6
- import type { EventEmitter } from "events";
5
+ import type { EventEmitter } from "node:events";
7
6
  import type { Byte, Double, UInt32 } from "node-opcua-basic-types";
8
7
 
9
8
  import type { DiagnosticInfo } from "node-opcua-data-model";
@@ -238,8 +237,10 @@ export interface ClientSubscription extends EventEmitter {
238
237
  }
239
238
 
240
239
  export declare interface ClientSubscription {
240
+ // biome-ignore lint/suspicious/noExplicitAny: matches Node's EventEmitter catch-all signature; narrowing to unknown[] breaks assignability of specifically-typed listener handlers at call sites
241
241
  once(event: string | symbol, listener: (...args: any[]) => void): this;
242
242
 
243
+ // biome-ignore lint/suspicious/noExplicitAny: matches Node's EventEmitter catch-all signature; narrowing to unknown[] breaks assignability of specifically-typed listener handlers at call sites
243
244
  on(event: string | symbol, listener: (...args: any[]) => void): this;
244
245
  /**
245
246
  * notify the observers that the subscription has now started
@@ -298,8 +299,10 @@ export declare interface ClientSubscription {
298
299
  ): ClientMonitoredItem;
299
300
  }
300
301
 
302
+ // biome-ignore lint/suspicious/noUnsafeDeclarationMerging: interface adds typed members/overloads for this class
303
+ // biome-ignore lint/complexity/noStaticOnlyClass: class identity is required for the `implements IBasicSubscription` contract; static factory + static flag can't be expressed as a namespace
301
304
  export class ClientSubscription implements IBasicSubscription {
302
- public static create(clientSession: ClientSession, options: ClientSubscriptionOptions): ClientSubscription {
305
+ public static create(_clientSession: ClientSession, _options: ClientSubscriptionOptions): ClientSubscription {
303
306
  /* c8 ignore next*/
304
307
  throw new Error("Not Implemented");
305
308
  }
package/source/common.ts CHANGED
@@ -49,6 +49,8 @@ import type {
49
49
  SetMonitoringModeResponse,
50
50
  SetPublishingModeRequest,
51
51
  SetPublishingModeResponse,
52
+ SetTriggeringRequest,
53
+ SetTriggeringResponse,
52
54
  TransferSubscriptionsRequest,
53
55
  TransferSubscriptionsResponse
54
56
  } from "node-opcua-service-subscription";
@@ -80,6 +82,7 @@ export type Request =
80
82
  | RepublishRequest
81
83
  | DeleteMonitoredItemsRequest
82
84
  | SetPublishingModeRequest
85
+ | SetTriggeringRequest
83
86
  | FindServersOnNetworkRequest
84
87
  | FindServersRequest
85
88
  | HistoryReadRequest
@@ -110,6 +113,7 @@ export type Response =
110
113
  | RepublishResponse
111
114
  | DeleteMonitoredItemsResponse
112
115
  | SetPublishingModeResponse
116
+ | SetTriggeringResponse
113
117
  | FindServersOnNetworkResponse
114
118
  | FindServersResponse
115
119
  | HistoryReadResponse
package/source/index.ts CHANGED
@@ -37,8 +37,8 @@ export * from "./client_session";
37
37
  export * from "./client_subscription";
38
38
  export * from "./client_utils";
39
39
  export * from "./opcua_client";
40
- export * from "./reverse/client_reverse_connect";
41
40
  export { ClientSidePublishEngine } from "./private/client_publish_engine";
41
+ export * from "./reverse/client_reverse_connect";
42
42
  export * from "./tools/findservers";
43
43
  export * from "./tools/read_history_server_capabilities";
44
44
  export * from "./user_identity_info";
@@ -233,6 +233,7 @@ export interface OPCUAClient<Events extends OPCUAClientBaseEvents = OPCUAClientB
233
233
  * });
234
234
  * ```
235
235
  */
236
+ // biome-ignore lint/complexity/noStaticOnlyClass: interface merges instance-side typings; static factory + static accessors can't be expressed as a namespace (get/set)
236
237
  export class OPCUAClient {
237
238
  /**
238
239
  * Create a new OPC UA client instance.