node-opcua-server 2.166.0 → 2.168.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 (111) hide show
  1. package/dist/addressSpace_accessor.d.ts +6 -6
  2. package/dist/addressSpace_accessor.js +2 -2
  3. package/dist/addressSpace_accessor.js.map +1 -1
  4. package/dist/base_server.d.ts +14 -3
  5. package/dist/base_server.js +64 -44
  6. package/dist/base_server.js.map +1 -1
  7. package/dist/extract_password_from_blob.js +1 -3
  8. package/dist/extract_password_from_blob.js.map +1 -1
  9. package/dist/factory.d.ts +2 -3
  10. package/dist/factory.js.map +1 -1
  11. package/dist/filter/check_where_clause_on_address_space.d.ts +2 -2
  12. package/dist/filter/check_where_clause_on_address_space.js +1 -2
  13. package/dist/filter/check_where_clause_on_address_space.js.map +1 -1
  14. package/dist/filter/extract_event_fields.d.ts +3 -3
  15. package/dist/filter/extract_event_fields.js +1 -2
  16. package/dist/filter/extract_event_fields.js.map +1 -1
  17. package/dist/helper.d.ts +3 -3
  18. package/dist/helper.js +4 -8
  19. package/dist/helper.js.map +1 -1
  20. package/dist/i_address_space_accessor.d.ts +4 -4
  21. package/dist/i_channel_data.d.ts +1 -1
  22. package/dist/i_register_server_manager.d.ts +1 -1
  23. package/dist/i_server_side_publish_engine.d.ts +8 -6
  24. package/dist/i_server_side_publish_engine.js +7 -2
  25. package/dist/i_server_side_publish_engine.js.map +1 -1
  26. package/dist/index.d.ts +8 -7
  27. package/dist/index.js +8 -7
  28. package/dist/index.js.map +1 -1
  29. package/dist/invalidate_server_certificate_cache.d.ts +16 -0
  30. package/dist/invalidate_server_certificate_cache.js +28 -0
  31. package/dist/invalidate_server_certificate_cache.js.map +1 -0
  32. package/dist/monitored_item.d.ts +10 -11
  33. package/dist/monitored_item.js +38 -39
  34. package/dist/monitored_item.js.map +1 -1
  35. package/dist/node_sampler.d.ts +1 -1
  36. package/dist/node_sampler.js +2 -4
  37. package/dist/node_sampler.js.map +1 -1
  38. package/dist/opcua_server.d.ts +57 -62
  39. package/dist/opcua_server.js +10 -10
  40. package/dist/opcua_server.js.map +1 -1
  41. package/dist/register_server_manager.d.ts +8 -8
  42. package/dist/register_server_manager.js +40 -40
  43. package/dist/register_server_manager.js.map +1 -1
  44. package/dist/register_server_manager_hidden.d.ts +1 -1
  45. package/dist/register_server_manager_hidden.js +2 -4
  46. package/dist/register_server_manager_hidden.js.map +1 -1
  47. package/dist/register_server_manager_mdns_only.d.ts +1 -1
  48. package/dist/register_server_manager_mdns_only.js.map +1 -1
  49. package/dist/sampling_func.d.ts +2 -2
  50. package/dist/server_capabilities.d.ts +3 -3
  51. package/dist/server_capabilities.js.map +1 -1
  52. package/dist/server_end_point.d.ts +47 -4
  53. package/dist/server_end_point.js +133 -42
  54. package/dist/server_end_point.js.map +1 -1
  55. package/dist/server_engine.js +29 -25
  56. package/dist/server_engine.js.map +1 -1
  57. package/dist/server_publish_engine.d.ts +5 -5
  58. package/dist/server_publish_engine.js +29 -23
  59. package/dist/server_publish_engine.js.map +1 -1
  60. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
  61. package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
  62. package/dist/server_session.d.ts +9 -10
  63. package/dist/server_session.js +11 -12
  64. package/dist/server_session.js.map +1 -1
  65. package/dist/server_subscription.d.ts +13 -13
  66. package/dist/server_subscription.js +100 -79
  67. package/dist/server_subscription.js.map +1 -1
  68. package/dist/sessions_compatible_for_transfer.d.ts +1 -1
  69. package/dist/sessions_compatible_for_transfer.js +1 -1
  70. package/dist/sessions_compatible_for_transfer.js.map +1 -1
  71. package/dist/user_manager.d.ts +4 -4
  72. package/dist/user_manager.js +1 -1
  73. package/dist/user_manager.js.map +1 -1
  74. package/dist/user_manager_ua.d.ts +2 -2
  75. package/dist/user_manager_ua.js +2 -2
  76. package/dist/user_manager_ua.js.map +1 -1
  77. package/dist/validate_filter.d.ts +7 -4
  78. package/dist/validate_filter.js +5 -6
  79. package/dist/validate_filter.js.map +1 -1
  80. package/package.json +51 -50
  81. package/source/addressSpace_accessor.ts +24 -24
  82. package/source/base_server.ts +75 -63
  83. package/source/extract_password_from_blob.ts +3 -11
  84. package/source/factory.ts +2 -4
  85. package/source/filter/check_where_clause_on_address_space.ts +4 -7
  86. package/source/filter/extract_event_fields.ts +4 -5
  87. package/source/helper.ts +9 -13
  88. package/source/i_address_space_accessor.ts +13 -4
  89. package/source/i_channel_data.ts +1 -1
  90. package/source/i_register_server_manager.ts +2 -4
  91. package/source/i_server_side_publish_engine.ts +16 -9
  92. package/source/index.ts +10 -9
  93. package/source/invalidate_server_certificate_cache.ts +26 -0
  94. package/source/monitored_item.ts +44 -42
  95. package/source/node_sampler.ts +9 -11
  96. package/source/opcua_server.ts +86 -99
  97. package/source/register_server_manager.ts +75 -72
  98. package/source/register_server_manager_hidden.ts +3 -5
  99. package/source/register_server_manager_mdns_only.ts +1 -3
  100. package/source/sampling_func.ts +2 -2
  101. package/source/server_capabilities.ts +9 -6
  102. package/source/server_end_point.ts +143 -50
  103. package/source/server_engine.ts +22 -22
  104. package/source/server_publish_engine.ts +35 -30
  105. package/source/server_publish_engine_for_orphan_subscriptions.ts +3 -3
  106. package/source/server_session.ts +36 -33
  107. package/source/server_subscription.ts +182 -184
  108. package/source/sessions_compatible_for_transfer.ts +9 -9
  109. package/source/user_manager.ts +7 -7
  110. package/source/user_manager_ua.ts +3 -5
  111. package/source/validate_filter.ts +9 -11
@@ -10,7 +10,8 @@ import chalk from "chalk";
10
10
 
11
11
  import { assert } from "node-opcua-assert";
12
12
  import type { OPCUACertificateManager } from "node-opcua-certificate-manager";
13
- import { type Certificate, makeSHA1Thumbprint, type PrivateKey, split_der } from "node-opcua-crypto/web";
13
+ import { type ICertificateChainProvider, StaticCertificateChainProvider } from "node-opcua-common";
14
+ import { type Certificate, combine_der, makeSHA1Thumbprint, type PrivateKey, split_der } from "node-opcua-crypto/web";
14
15
  import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
15
16
  import { getFullyQualifiedDomainName, resolveFullyQualifiedDomainName } from "node-opcua-hostname";
16
17
  import {
@@ -98,7 +99,8 @@ function dumpChannelInfo(channels: ServerSecureChannelLayer[]): void {
98
99
  console.log("------------------------------------------------------");
99
100
  }
100
101
 
101
- const emptyCertificate = Buffer.alloc(0);
102
+ const emptyCertificateChain: Certificate[] = [];
103
+
102
104
  // biome-ignore lint/suspicious/noExplicitAny: deliberate null→PrivateKey sentinel
103
105
  const emptyPrivateKey = null as any as PrivateKey;
104
106
 
@@ -116,7 +118,7 @@ export interface OPCUAServerEndPointOptions {
116
118
  /**
117
119
  * the DER certificate chain
118
120
  */
119
- certificateChain: Certificate;
121
+ certificateChain: Certificate[];
120
122
 
121
123
  /**
122
124
  * privateKey
@@ -302,9 +304,12 @@ function getUniqueName(name: string, collection: { [key: string]: number }) {
302
304
  }
303
305
  }
304
306
 
305
- interface ServerSecureChannelLayerPriv extends ServerSecureChannelLayer {
306
- _unpreregisterChannelEvent?: () => void;
307
- }
307
+ /**
308
+ * Stores the abort listener for channels in the pre-registration phase.
309
+ * Using a WeakMap instead of monkey-patching the channel object keeps
310
+ * this internal state invisible to debuggers and external code.
311
+ */
312
+ const preregisterAbortListeners = new WeakMap<ServerSecureChannelLayer, () => void>();
308
313
  /**
309
314
  * OPCUAServerEndPoint a Server EndPoint.
310
315
  * A sever end point is listening to one port
@@ -329,12 +334,23 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
329
334
  public objectFactory: unknown;
330
335
 
331
336
  public _on_new_channel?: (channel: ServerSecureChannelLayer) => void;
337
+ public _on_channel_secured?: (channel: ServerSecureChannelLayer) => void;
332
338
  public _on_close_channel?: (channel: ServerSecureChannelLayer) => void;
333
339
  public _on_connectionRefused?: (socketData: ISocketData) => void;
334
340
  public _on_openSecureChannelFailure?: (socketData: ISocketData, channelData: IChannelData) => void;
335
341
 
336
- private _certificateChain: Certificate;
337
- private _privateKey: PrivateKey;
342
+ /**
343
+ * Certificate chain provider — delegates all cert/key access.
344
+ * Stored in a `#` private field so secrets are not visible
345
+ * in the debugger's property list or JSON serialization.
346
+ */
347
+ #certProvider: ICertificateChainProvider;
348
+ /**
349
+ * Combined DER cache — invalidated whenever the cert provider
350
+ * changes so that `EndpointDescription.serverCertificate`
351
+ * getters don't call `combine_der()` on every access.
352
+ */
353
+ #combinedDerCache: Certificate | undefined;
338
354
  private _channels: { [key: string]: ServerSecureChannelLayer };
339
355
  private _server?: Server;
340
356
  private _endpoints: EndpointDescription[];
@@ -347,9 +363,9 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
347
363
  constructor(options: OPCUAServerEndPointOptions) {
348
364
  super();
349
365
 
350
- assert(!Object.prototype.hasOwnProperty.call(options, "certificate"), "expecting a certificateChain instead");
351
- assert(Object.prototype.hasOwnProperty.call(options, "certificateChain"), "expecting a certificateChain");
352
- assert(Object.prototype.hasOwnProperty.call(options, "privateKey"));
366
+ assert(!Object.hasOwn(options, "certificate"), "expecting a certificateChain instead");
367
+ assert(Object.hasOwn(options, "certificateChain"), "expecting a certificateChain");
368
+ assert(Object.hasOwn(options, "privateKey"));
353
369
 
354
370
  this.certificateManager = options.certificateManager;
355
371
 
@@ -359,8 +375,7 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
359
375
  this.host = options.host;
360
376
  assert(typeof this.port === "number");
361
377
 
362
- this._certificateChain = options.certificateChain;
363
- this._privateKey = options.privateKey;
378
+ this.#certProvider = new StaticCertificateChainProvider(options.certificateChain, options.privateKey);
364
379
 
365
380
  this._channels = {};
366
381
 
@@ -390,8 +405,8 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
390
405
  }
391
406
 
392
407
  public dispose(): void {
393
- this._certificateChain = emptyCertificate;
394
- this._privateKey = emptyPrivateKey;
408
+ this.#certProvider = new StaticCertificateChainProvider(emptyCertificateChain, emptyPrivateKey);
409
+ this.#combinedDerCache = undefined;
395
410
 
396
411
  assert(Object.keys(this._channels).length === 0, "OPCUAServerEndPoint channels must have been deleted");
397
412
 
@@ -417,7 +432,7 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
417
432
  " l = " +
418
433
  this._endpoints.length +
419
434
  " " +
420
- makeSHA1Thumbprint(this.getCertificateChain()).toString("hex");
435
+ makeSHA1Thumbprint(this.getCertificate()).toString("hex");
421
436
  return txt;
422
437
  }
423
438
 
@@ -429,21 +444,85 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
429
444
  * Returns the X509 DER form of the server certificate
430
445
  */
431
446
  public getCertificate(): Certificate {
432
- return split_der(this.getCertificateChain())[0];
447
+ return this.getCertificateChain()[0];
433
448
  }
434
449
 
435
450
  /**
436
451
  * Returns the X509 DER form of the server certificate
437
452
  */
438
- public getCertificateChain(): Certificate {
439
- return this._certificateChain;
453
+ public getCertificateChain(): Certificate[] {
454
+ return this.#certProvider.getCertificateChain();
455
+ }
456
+
457
+ /**
458
+ * Replace the certificate chain provider for this endpoint.
459
+ *
460
+ * Used by push certificate management to switch from the
461
+ * default static provider to a disk-based one that re-reads
462
+ * certificates on demand.
463
+ *
464
+ * Invalidates the cached `combine_der` result so that
465
+ * `EndpointDescription.serverCertificate` getters pick up
466
+ * the new chain immediately.
467
+ */
468
+ public setCertificateProvider(provider: ICertificateChainProvider): void {
469
+ this.#certProvider = provider;
470
+ this.#combinedDerCache = undefined;
471
+ }
472
+
473
+ /**
474
+ * Return the current certificate chain provider.
475
+ * Useful for calling `invalidate()` after certificate rotation.
476
+ */
477
+ public getCertificateProvider(): ICertificateChainProvider {
478
+ return this.#certProvider;
479
+ }
480
+
481
+ /**
482
+ * Invalidate the combined DER cache.
483
+ *
484
+ * Called after the underlying provider's chain changes
485
+ * (e.g. after `provider.invalidate()` or `provider.update()`).
486
+ * The next `EndpointDescription.serverCertificate` access
487
+ * will recompute the combined DER from the provider.
488
+ */
489
+ public invalidateCombinedDerCache(): void {
490
+ this.#combinedDerCache = undefined;
491
+ }
492
+
493
+ /**
494
+ * Convenience method: invalidate both the provider's cache
495
+ * (so it re-reads from disk) and the combined DER cache
496
+ * (so endpoint descriptions recompute `serverCertificate`).
497
+ *
498
+ * Prefer this over calling `getCertificateProvider().invalidate()`
499
+ * and `invalidateCombinedDerCache()` separately.
500
+ */
501
+ public invalidateCertificates(): void {
502
+ this.#certProvider.invalidate();
503
+ this.#combinedDerCache = undefined;
504
+ }
505
+
506
+ /**
507
+ * Get the combined DER certificate (all certs concatenated)
508
+ * for use in EndpointDescription.serverCertificate.
509
+ * Cached internally; invalidated by provider changes.
510
+ * @internal
511
+ */
512
+ public getCombinedCertificate(): Certificate | undefined {
513
+ const chain = this.#certProvider.getCertificateChain();
514
+ if (chain.length === 0) return undefined;
515
+ if (!this.#combinedDerCache) {
516
+ this.#combinedDerCache = combine_der(chain);
517
+ }
518
+ return this.#combinedDerCache;
440
519
  }
441
520
 
442
521
  /**
443
522
  * the private key
444
523
  */
445
524
  public getPrivateKey(): PrivateKey {
446
- return this._privateKey;
525
+ return this.#certProvider.getPrivateKey();
447
526
  }
448
527
 
449
528
  /**
@@ -512,7 +591,6 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
512
591
  collection: this._policy_deduplicator,
513
592
  hostname,
514
593
  server: this.serverInfo,
515
- serverCertificateChain: this.getCertificateChain(),
516
594
 
517
595
  securityMode,
518
596
  securityPolicy,
@@ -964,16 +1042,16 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
964
1042
  // as they will need to be interrupted when OPCUAServerEndPoint is closed
965
1043
  assert(this._started, "OPCUAServerEndPoint must be started");
966
1044
 
967
- assert(!Object.prototype.hasOwnProperty.call(this._channels, channel.hashKey), " channel already preregistered!");
1045
+ assert(!Object.hasOwn(this._channels, channel.hashKey), " channel already preregistered!");
968
1046
 
969
- const channelPriv = <ServerSecureChannelLayerPriv>channel;
970
- this._channels[channel.hashKey] = channelPriv;
971
- channelPriv._unpreregisterChannelEvent = () => {
1047
+ this._channels[channel.hashKey] = channel;
1048
+ const onAbort = () => {
972
1049
  debugLog("Channel received an abort event during the preregistration phase");
973
1050
  this._un_pre_registerChannel(channel);
974
1051
  channel.dispose();
975
1052
  };
976
- channel.on("abort", channelPriv._unpreregisterChannelEvent);
1053
+ preregisterAbortListeners.set(channel, onAbort);
1054
+ channel.on("abort", onAbort);
977
1055
  }
978
1056
 
979
1057
  private _un_pre_registerChannel(channel: ServerSecureChannelLayer) {
@@ -982,10 +1060,10 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
982
1060
  return;
983
1061
  }
984
1062
  delete this._channels[channel.hashKey];
985
- const channelPriv = <ServerSecureChannelLayerPriv>channel;
986
- if (typeof channelPriv._unpreregisterChannelEvent === "function") {
987
- channel.removeListener("abort", channelPriv._unpreregisterChannelEvent);
988
- channelPriv._unpreregisterChannelEvent = undefined;
1063
+ const onAbort = preregisterAbortListeners.get(channel);
1064
+ if (onAbort) {
1065
+ channel.removeListener("abort", onAbort);
1066
+ preregisterAbortListeners.delete(channel);
989
1067
  }
990
1068
  }
991
1069
 
@@ -1000,11 +1078,22 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
1000
1078
  this._channels[channel.hashKey] = channel;
1001
1079
 
1002
1080
  /**
1003
- * @event newChannel
1081
+ * @event newChannel — fired after transport init (HEL/ACK).
1082
+ * Note: securityPolicy/securityMode are NOT yet established.
1004
1083
  * @param channel
1005
1084
  */
1006
1085
  this.emit("newChannel", channel);
1007
1086
 
1087
+ channel.once("open", () => {
1088
+ /**
1089
+ * @event channelSecured — fired after OpenSecureChannel
1090
+ * handshake succeeds. securityPolicy, securityMode, and
1091
+ * clientCertificate are available at this point.
1092
+ * @param channel
1093
+ */
1094
+ this.emit("channelSecured", channel);
1095
+ });
1096
+
1008
1097
  channel.on("abort", () => {
1009
1098
  this._unregisterChannel(channel);
1010
1099
  });
@@ -1021,11 +1110,11 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
1021
1110
  */
1022
1111
  private _unregisterChannel(channel: ServerSecureChannelLayer): void {
1023
1112
  debugLog("_un-registerChannel channel.hashKey", channel.hashKey);
1024
- if (!Object.prototype.hasOwnProperty.call(this._channels, channel.hashKey)) {
1113
+ if (!Object.hasOwn(this._channels, channel.hashKey)) {
1025
1114
  return;
1026
1115
  }
1027
1116
 
1028
- assert(Object.prototype.hasOwnProperty.call(this._channels, channel.hashKey), "channel is not registered");
1117
+ assert(Object.hasOwn(this._channels, channel.hashKey), "channel is not registered");
1029
1118
 
1030
1119
  /**
1031
1120
  * @event closeChannel
@@ -1130,7 +1219,6 @@ interface MakeEndpointDescriptionOptions {
1130
1219
  */
1131
1220
  hostname: string;
1132
1221
 
1133
- serverCertificateChain: Certificate;
1134
1222
  /**
1135
1223
  *
1136
1224
  */
@@ -1224,14 +1312,6 @@ function estimateSecurityLevel(securityMode: MessageSecurityMode, securityPolicy
1224
1312
  * @private
1225
1313
  */
1226
1314
  function _makeEndpointDescription(options: MakeEndpointDescriptionOptions, parent: OPCUAServerEndPoint): EndpointDescriptionEx {
1227
- assert(Object.prototype.hasOwnProperty.call(options, "serverCertificateChain"));
1228
- assert(!Object.prototype.hasOwnProperty.call(options, "serverCertificate"));
1229
- assert(!!options.securityMode); // s.MessageSecurityMode
1230
- assert(!!options.securityPolicy);
1231
- assert(options.server !== null && typeof options.server === "object");
1232
- assert(!!options.hostname && typeof options.hostname === "string");
1233
- assert(typeof options.restricted === "boolean");
1234
-
1235
1315
  const u = (n: string) => getUniqueName(n, options.collection);
1236
1316
  options.securityLevel =
1237
1317
  options.securityLevel === undefined
@@ -1353,7 +1433,8 @@ function _makeEndpointDescription(options: MakeEndpointDescriptionOptions, paren
1353
1433
  endpointUrl: "<to be evaluated at run time>", // options.endpointUrl,
1354
1434
 
1355
1435
  server: undefined, // options.server,
1356
- serverCertificate: options.serverCertificateChain,
1436
+ // serverCertificate is set as a dynamic getter below
1437
+ serverCertificate: undefined,
1357
1438
 
1358
1439
  securityMode: options.securityMode,
1359
1440
  securityPolicyUri,
@@ -1364,15 +1445,27 @@ function _makeEndpointDescription(options: MakeEndpointDescriptionOptions, paren
1364
1445
  }) as EndpointDescriptionEx;
1365
1446
  endpoint._parent = parent;
1366
1447
 
1448
+ // serverCertificate — always dynamic.
1449
+ // Delegates to the parent endpoint's combined DER cache
1450
+ // which in turn reads from the current ICertificateChainProvider.
1451
+ // This ensures GetEndpoints always returns the current chain,
1452
+ // whether the provider is static or disk-based.
1453
+ Object.defineProperty(endpoint, "serverCertificate", {
1454
+ get: () => parent.getCombinedCertificate(),
1455
+ configurable: true
1456
+ });
1457
+
1367
1458
  // endpointUrl is dynamic as port number may be adjusted
1368
1459
  // when the tcp socket start listening
1369
- // biome-ignore lint/suspicious/noExplicitAny: __defineGetter__ not in standard typings
1370
- (endpoint as any).__defineGetter__("endpointUrl", () => {
1371
- const port = options.advertisedPort ?? endpoint._parent.port;
1372
- const resourcePath = options.resourcePath || "";
1373
- const hostname = options.hostname;
1374
- const endpointUrl = `opc.tcp://${hostname}:${port}${resourcePath}`;
1375
- return resolveFullyQualifiedDomainName(endpointUrl);
1460
+ Object.defineProperty(endpoint, "endpointUrl", {
1461
+ get: () => {
1462
+ const port = options.advertisedPort ?? endpoint._parent.port;
1463
+ const resourcePath = options.resourcePath || "";
1464
+ const hostname = options.hostname;
1465
+ const endpointUrl = `opc.tcp://${hostname}:${port}${resourcePath}`;
1466
+ return resolveFullyQualifiedDomainName(endpointUrl);
1467
+ },
1468
+ configurable: true
1376
1469
  });
1377
1470
 
1378
1471
  endpoint.server = options.server;
@@ -4,7 +4,7 @@
4
4
  import { EventEmitter } from "node:events";
5
5
  import { types } from "node:util";
6
6
 
7
- import async from "async";
7
+
8
8
  import chalk from "chalk";
9
9
  import {
10
10
  AddressSpace,
@@ -184,7 +184,7 @@ function requestServerStateChange(
184
184
  ) {
185
185
  assert(Array.isArray(inputArguments));
186
186
  assert(typeof callback === "function");
187
- assert(Object.prototype.hasOwnProperty.call(context, "session"), " expecting a session id in the context object");
187
+ assert(Object.hasOwn(context, "session"), " expecting a session id in the context object");
188
188
  const session = context.session as ServerSession;
189
189
  if (!session) {
190
190
  return callback(null, { statusCode: StatusCodes.BadInternalError });
@@ -199,7 +199,7 @@ function _getSubscription(
199
199
  context: ISessionContext
200
200
  ): { subscription: Subscription; statusCode?: never } | { statusCode: StatusCode; subscription?: never } {
201
201
  assert(Array.isArray(inputArguments));
202
- assert(Object.prototype.hasOwnProperty.call(context, "session"), " expecting a session id in the context object");
202
+ assert(Object.hasOwn(context, "session"), " expecting a session id in the context object");
203
203
  const session = context.session as ServerSession;
204
204
  if (!session) {
205
205
  return { statusCode: StatusCodes.BadInternalError };
@@ -466,11 +466,11 @@ export class ServerEngine extends EventEmitter implements IAddressSpaceAccessor
466
466
 
467
467
  // --------------------------------------------------- serverDiagnosticsSummary extension Object
468
468
  this.serverDiagnosticsSummary = new ServerDiagnosticsSummaryDataType();
469
- assert(Object.prototype.hasOwnProperty.call(this.serverDiagnosticsSummary, "currentSessionCount"));
469
+ assert(Object.hasOwn(this.serverDiagnosticsSummary, "currentSessionCount"));
470
470
 
471
471
  // note spelling is different for serverDiagnosticsSummary.currentSubscriptionCount
472
472
  // and sessionDiagnostics.currentSubscriptionsCount ( with an s)
473
- assert(Object.prototype.hasOwnProperty.call(this.serverDiagnosticsSummary, "currentSubscriptionCount"));
473
+ assert(Object.hasOwn(this.serverDiagnosticsSummary, "currentSubscriptionCount"));
474
474
 
475
475
  Object.defineProperty(this.serverDiagnosticsSummary, "currentSubscriptionCount", {
476
476
  get: () => {
@@ -505,7 +505,7 @@ export class ServerEngine extends EventEmitter implements IAddressSpaceAccessor
505
505
  this._applicationUri = options.applicationUri || "<unset _applicationUri>";
506
506
  }
507
507
 
508
- options.serverDiagnosticsEnabled = Object.prototype.hasOwnProperty.call(options, "serverDiagnosticsEnable")
508
+ options.serverDiagnosticsEnabled = Object.hasOwn(options, "serverDiagnosticsEnable")
509
509
  ? options.serverDiagnosticsEnabled
510
510
  : true;
511
511
 
@@ -1899,23 +1899,23 @@ export class ServerEngine extends EventEmitter implements IAddressSpaceAccessor
1899
1899
  return;
1900
1900
  }
1901
1901
  // perform all asyncRefresh in parallel
1902
- async.map(
1903
- uaVariableArray,
1904
- (uaVariable: UAVariable, inner_callback: CallbackT<DataValue>) => {
1902
+ const promises = uaVariableArray.map((uaVariable) => {
1903
+ return new Promise<DataValue>((resolve, reject) => {
1905
1904
  try {
1906
1905
  uaVariable.asyncRefresh(referenceTime, (err, dataValue) => {
1907
- inner_callback(err, dataValue);
1906
+ if (err) return reject(err);
1907
+ resolve(dataValue!);
1908
1908
  });
1909
1909
  } catch (err) {
1910
1910
  const _err = err as Error;
1911
1911
  errorLog("asyncRefresh internal error", _err.message);
1912
- inner_callback(_err);
1912
+ reject(_err);
1913
1913
  }
1914
- },
1915
- (err?: Error | null, arrResult?: (DataValue | undefined)[]) => {
1916
- callback(err || null, arrResult as DataValue[]);
1917
- }
1918
- );
1914
+ });
1915
+ });
1916
+ Promise.all(promises)
1917
+ .then((dataValues) => callback(null, dataValues))
1918
+ .catch((err) => callback(err));
1919
1919
  }
1920
1920
 
1921
1921
  private _exposeSubscriptionDiagnostics(subscription: Subscription): void {
@@ -1954,12 +1954,12 @@ export class ServerEngine extends EventEmitter implements IAddressSpaceAccessor
1954
1954
  * @return {Subscription}
1955
1955
  */
1956
1956
  public _createSubscriptionOnSession(session: ServerSession, request: CreateSubscriptionRequestLike): Subscription {
1957
- assert(Object.prototype.hasOwnProperty.call(request, "requestedPublishingInterval")); // Duration
1958
- assert(Object.prototype.hasOwnProperty.call(request, "requestedLifetimeCount")); // Counter
1959
- assert(Object.prototype.hasOwnProperty.call(request, "requestedMaxKeepAliveCount")); // Counter
1960
- assert(Object.prototype.hasOwnProperty.call(request, "maxNotificationsPerPublish")); // Counter
1961
- assert(Object.prototype.hasOwnProperty.call(request, "publishingEnabled")); // Boolean
1962
- assert(Object.prototype.hasOwnProperty.call(request, "priority")); // Byte
1957
+ assert(Object.hasOwn(request, "requestedPublishingInterval")); // Duration
1958
+ assert(Object.hasOwn(request, "requestedLifetimeCount")); // Counter
1959
+ assert(Object.hasOwn(request, "requestedMaxKeepAliveCount")); // Counter
1960
+ assert(Object.hasOwn(request, "maxNotificationsPerPublish")); // Counter
1961
+ assert(Object.hasOwn(request, "publishingEnabled")); // Boolean
1962
+ assert(Object.hasOwn(request, "priority")); // Byte
1963
1963
 
1964
1964
  // adjust publishing parameters
1965
1965
  const publishingInterval = request.requestedPublishingInterval || 0;
@@ -2,28 +2,29 @@
2
2
  * @module node-opcua-server
3
3
  */
4
4
  // tslint:disable:no-console
5
- import { EventEmitter } from "events";
5
+
6
+ import { EventEmitter } from "node:events";
6
7
  import chalk from "chalk";
7
- import { partition, sortBy } from "lodash";
8
+ import partition from "lodash.partition";
9
+ import sortBy from "lodash.sortby";
8
10
 
9
11
  import { assert } from "node-opcua-assert";
10
12
  import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
11
13
  import { ObjectRegistry } from "node-opcua-object-registry";
12
- import { StatusCode, StatusCodes } from "node-opcua-status-code";
14
+ import { type StatusCode, StatusCodes } from "node-opcua-status-code";
13
15
 
14
- import { PublishRequest, PublishResponse, ServiceFault, SubscriptionAcknowledgement } from "node-opcua-types";
15
- import { Subscription } from "./server_subscription";
16
- import { SubscriptionState } from "./server_subscription";
17
- import { IServerSidePublishEngine, INotifMsg, IClosedOrTransferredSubscription } from "./i_server_side_publish_engine";
16
+ import { PublishRequest, PublishResponse, ServiceFault, type SubscriptionAcknowledgement } from "node-opcua-types";
17
+ import type { IClosedOrTransferredSubscription, IServerSidePublishEngine } from "./i_server_side_publish_engine";
18
+ import { Subscription, SubscriptionState } from "./server_subscription";
18
19
 
19
20
  const debugLog = make_debugLog(__filename);
20
21
  const doDebug = checkDebugFlag(__filename);
21
22
 
22
- function traceLog(...args: [any?, ...any[]]) {
23
+ function traceLog(...args: [unknown?, ...unknown[]]) {
23
24
  if (!doDebug) {
24
25
  return;
25
26
  }
26
- const a: string[] = args.map((x?: any) => x!);
27
+ const a: string[] = args.map((x?: unknown) => String(x));
27
28
  a.unshift(chalk.yellow(" TRACE "));
28
29
  debugLog(...a);
29
30
  }
@@ -56,7 +57,7 @@ function addDate(date: Date, delta: number) {
56
57
 
57
58
  function timeout_filter(publishData: PublishData): boolean {
58
59
  const request = publishData.request;
59
- const results = publishData.results;
60
+ const _results = publishData.results;
60
61
  if (!request.requestHeader.timeoutHint) {
61
62
  // no limits
62
63
  return false;
@@ -87,7 +88,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
87
88
  );
88
89
 
89
90
  for (const subscription of Object.values(srcPublishEngine._subscriptions)) {
90
- assert((subscription.publishEngine as any) === srcPublishEngine);
91
+ assert(subscription.publishEngine === srcPublishEngine);
91
92
 
92
93
  if (subscription.$session) {
93
94
  subscription.$session._unexposeSubscriptionDiagnostics(subscription);
@@ -117,7 +118,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
117
118
  destPublishEngine: ServerSidePublishEngine,
118
119
  sendInitialValues: boolean
119
120
  ): Promise<Subscription> {
120
- const srcPublishEngine = subscription.publishEngine as any as ServerSidePublishEngine;
121
+ const srcPublishEngine = subscription.publishEngine as ServerSidePublishEngine;
121
122
 
122
123
  assert(!destPublishEngine.getSubscriptionById(subscription.id));
123
124
  assert(srcPublishEngine.getSubscriptionById(subscription.id));
@@ -161,8 +162,6 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
161
162
  assert(destPublishEngine.getSubscriptionById(subscription.id));
162
163
  assert(!srcPublishEngine.getSubscriptionById(subscription.id));
163
164
 
164
-
165
-
166
165
  return subscription;
167
166
  }
168
167
 
@@ -252,9 +251,9 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
252
251
  */
253
252
  public add_subscription(subscription: Subscription): Subscription {
254
253
  assert(subscription instanceof Subscription);
255
- assert(isFinite(subscription.id));
256
- subscription.publishEngine = (subscription.publishEngine || this) as any;
257
- assert((subscription.publishEngine as any) === this);
254
+ assert(Number.isFinite(subscription.id));
255
+ subscription.publishEngine = subscription.publishEngine || this;
256
+ assert(subscription.publishEngine === this);
258
257
  assert(!this._subscriptions[subscription.id]);
259
258
 
260
259
  debugLog("ServerSidePublishEngine#add_subscription - adding subscription with Id:", subscription.id);
@@ -265,12 +264,12 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
265
264
 
266
265
  public detach_subscription(subscription: Subscription): Subscription {
267
266
  assert(subscription instanceof Subscription);
268
- assert(isFinite(subscription.id));
269
- assert((subscription.publishEngine as any) === this);
267
+ assert(Number.isFinite(subscription.id));
268
+ assert(subscription.publishEngine === this);
270
269
  assert(this._subscriptions[subscription.id] === subscription);
271
270
 
272
271
  delete this._subscriptions[subscription.id];
273
- subscription.publishEngine = null as any;
272
+ subscription.publishEngine = null as unknown as ServerSidePublishEngine;
274
273
  debugLog("ServerSidePublishEngine#detach_subscription detaching subscription with Id:", subscription.id);
275
274
  return subscription;
276
275
  }
@@ -318,7 +317,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
318
317
  const result = subscriptions.reduce((sum: number, subscription: Subscription) => {
319
318
  return sum + subscription.monitoredItemCount;
320
319
  }, 0);
321
- assert(isFinite(result));
320
+ assert(Number.isFinite(result));
322
321
  return result;
323
322
  }
324
323
 
@@ -405,7 +404,7 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
405
404
  */
406
405
  public _on_PublishRequest(
407
406
  request: PublishRequest,
408
- callback?: (request1: PublishRequest, response: PublishResponse| ServiceFault) => void
407
+ callback?: (request1: PublishRequest, response: PublishResponse | ServiceFault) => void
409
408
  ): void {
410
409
  callback = callback || dummy_function;
411
410
  assert(typeof callback === "function");
@@ -430,11 +429,11 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
430
429
  this._send_error_for_request(publishData, StatusCodes.BadSessionClosed);
431
430
  } else if (this.subscriptionCount === 0) {
432
431
  if (this._closed_subscriptions.length > 0 && this._closed_subscriptions[0].hasPendingNotifications) {
433
- const verif = this._publish_request_queue.length;
432
+ const _verif = this._publish_request_queue.length;
434
433
  // add the publish request to the queue for later processing
435
434
  this._publish_request_queue.push(publishData);
436
435
 
437
- const processed = this.#_feed_closed_subscription();
436
+ const _processed = this.#_feed_closed_subscription();
438
437
  //xx ( may be subscription has expired by themselves) assert(verif === this._publish_request_queue.length);
439
438
  //xx ( may be subscription has expired by themselves) assert(processed);
440
439
  return;
@@ -529,11 +528,11 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
529
528
  return false;
530
529
  }
531
530
  // process closed subscription
532
- const closed_subscription = this._closed_subscriptions[0]!;
531
+ const closed_subscription = this._closed_subscriptions[0];
533
532
  assert(closed_subscription.hasPendingNotifications);
534
533
  debugLog("ServerSidePublishEngine#_feed_closed_subscription for closed_subscription ", closed_subscription.id);
535
- closed_subscription?._publish_pending_notifications();
536
- if (!closed_subscription?.hasPendingNotifications) {
534
+ closed_subscription._publish_pending_notifications();
535
+ if (!closed_subscription.hasPendingNotifications) {
537
536
  closed_subscription.dispose();
538
537
  this._closed_subscriptions.shift();
539
538
  }
@@ -579,7 +578,10 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
579
578
  // request and return a response with the result set to Bad_TooManyPublishRequests.
580
579
 
581
580
  // dequeue oldest request
582
- const publishData = this._publish_request_queue.shift()!;
581
+ const publishData = this._publish_request_queue.shift();
582
+ if (!publishData) {
583
+ return;
584
+ }
583
585
  this._send_error_for_request(publishData, StatusCodes.BadTooManyPublishRequests);
584
586
  }
585
587
  }
@@ -629,10 +631,13 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
629
631
  );
630
632
  return true;
631
633
  }
632
- public _send_response(subscription: Subscription, response: PublishResponse): void {
634
+ public _send_response(_subscription: Subscription, response: PublishResponse): void {
633
635
  assert(this.pendingPublishRequestCount > 0);
634
636
  assert(response.subscriptionId !== 0xffffff);
635
- const publishData = this._publish_request_queue.shift()!;
637
+ const publishData = this._publish_request_queue.shift();
638
+ if (!publishData) {
639
+ return;
640
+ }
636
641
  this._send_valid_response_for_request(publishData, response);
637
642
  }
638
643
 
@@ -7,8 +7,8 @@ import chalk from "chalk";
7
7
  import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
8
8
  import { NodeId } from "node-opcua-nodeid";
9
9
 
10
- import { ServerSidePublishEngine, ServerSidePublishEngineOptions } from "./server_publish_engine";
11
- import { Subscription } from "./server_subscription";
10
+ import { ServerSidePublishEngine, type ServerSidePublishEngineOptions } from "./server_publish_engine";
11
+ import type { Subscription } from "./server_subscription";
12
12
 
13
13
  const debugLog = make_debugLog(__filename);
14
14
  const doDebug = checkDebugFlag(__filename);
@@ -32,7 +32,7 @@ export class ServerSidePublishEngineForOrphanSubscription extends ServerSidePubl
32
32
 
33
33
  // detach subscription from old session
34
34
  subscription.$session = undefined;
35
-
35
+
36
36
  super.add_subscription(subscription);
37
37
  // also add an event handler to detected when the subscription has ended
38
38
  // so we can automatically remove it from the orphan table