node-opcua-server 2.167.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 (107) 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 +63 -41
  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 +7 -7
  40. package/dist/opcua_server.js.map +1 -1
  41. package/dist/register_server_manager_hidden.d.ts +1 -1
  42. package/dist/register_server_manager_hidden.js +2 -4
  43. package/dist/register_server_manager_hidden.js.map +1 -1
  44. package/dist/register_server_manager_mdns_only.d.ts +1 -1
  45. package/dist/register_server_manager_mdns_only.js.map +1 -1
  46. package/dist/sampling_func.d.ts +2 -2
  47. package/dist/server_capabilities.d.ts +3 -3
  48. package/dist/server_capabilities.js.map +1 -1
  49. package/dist/server_end_point.d.ts +45 -2
  50. package/dist/server_end_point.js +130 -32
  51. package/dist/server_end_point.js.map +1 -1
  52. package/dist/server_engine.js +29 -25
  53. package/dist/server_engine.js.map +1 -1
  54. package/dist/server_publish_engine.d.ts +5 -5
  55. package/dist/server_publish_engine.js +29 -23
  56. package/dist/server_publish_engine.js.map +1 -1
  57. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
  58. package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
  59. package/dist/server_session.d.ts +9 -10
  60. package/dist/server_session.js +11 -12
  61. package/dist/server_session.js.map +1 -1
  62. package/dist/server_subscription.d.ts +13 -13
  63. package/dist/server_subscription.js +100 -79
  64. package/dist/server_subscription.js.map +1 -1
  65. package/dist/sessions_compatible_for_transfer.d.ts +1 -1
  66. package/dist/sessions_compatible_for_transfer.js +1 -1
  67. package/dist/sessions_compatible_for_transfer.js.map +1 -1
  68. package/dist/user_manager.d.ts +4 -4
  69. package/dist/user_manager.js +1 -1
  70. package/dist/user_manager.js.map +1 -1
  71. package/dist/user_manager_ua.d.ts +2 -2
  72. package/dist/user_manager_ua.js +2 -2
  73. package/dist/user_manager_ua.js.map +1 -1
  74. package/dist/validate_filter.d.ts +7 -4
  75. package/dist/validate_filter.js +5 -6
  76. package/dist/validate_filter.js.map +1 -1
  77. package/package.json +46 -46
  78. package/source/addressSpace_accessor.ts +24 -24
  79. package/source/base_server.ts +73 -59
  80. package/source/extract_password_from_blob.ts +3 -11
  81. package/source/factory.ts +2 -4
  82. package/source/filter/check_where_clause_on_address_space.ts +4 -7
  83. package/source/filter/extract_event_fields.ts +4 -5
  84. package/source/helper.ts +9 -13
  85. package/source/i_address_space_accessor.ts +13 -4
  86. package/source/i_channel_data.ts +1 -1
  87. package/source/i_register_server_manager.ts +2 -4
  88. package/source/i_server_side_publish_engine.ts +16 -9
  89. package/source/index.ts +10 -9
  90. package/source/invalidate_server_certificate_cache.ts +26 -0
  91. package/source/monitored_item.ts +44 -42
  92. package/source/node_sampler.ts +9 -11
  93. package/source/opcua_server.ts +68 -88
  94. package/source/register_server_manager_hidden.ts +3 -5
  95. package/source/register_server_manager_mdns_only.ts +1 -3
  96. package/source/sampling_func.ts +2 -2
  97. package/source/server_capabilities.ts +9 -6
  98. package/source/server_end_point.ts +142 -42
  99. package/source/server_engine.ts +22 -22
  100. package/source/server_publish_engine.ts +35 -30
  101. package/source/server_publish_engine_for_orphan_subscriptions.ts +3 -3
  102. package/source/server_session.ts +36 -33
  103. package/source/server_subscription.ts +182 -184
  104. package/source/sessions_compatible_for_transfer.ts +9 -9
  105. package/source/user_manager.ts +7 -7
  106. package/source/user_manager_ua.ts +3 -5
  107. package/source/validate_filter.ts +9 -11
@@ -4,11 +4,11 @@
4
4
  // tslint:disable:no-console
5
5
 
6
6
  import fs from "node:fs";
7
+ import { isIP } from "node:net";
7
8
  import os from "node:os";
8
9
  import path from "node:path";
9
- import { isIP } from "node:net";
10
10
  import { withLock } from "@ster5/global-mutex";
11
- import async from "async";
11
+
12
12
  import chalk from "chalk";
13
13
  import { assert } from "node-opcua-assert";
14
14
  import { getDefaultCertificateManager, makeSubject, type OPCUACertificateManager } from "node-opcua-certificate-manager";
@@ -26,7 +26,7 @@ import {
26
26
  ipv4ToHex,
27
27
  resolveFullyQualifiedDomainName
28
28
  } from "node-opcua-hostname";
29
- import type { Message, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
29
+ import type { Message, Request, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
30
30
  import { FindServersRequest, FindServersResponse } from "node-opcua-service-discovery";
31
31
  import { ApplicationDescription, ApplicationType, GetEndpointsResponse } from "node-opcua-service-endpoints";
32
32
  import { ServiceFault } from "node-opcua-service-secure-channel";
@@ -82,6 +82,11 @@ function cleanupEndpoint(endpoint: OPCUAServerEndPoint) {
82
82
  endpoint.removeListener("openSecureChannelFailure", endpoint._on_openSecureChannelFailure);
83
83
  endpoint._on_openSecureChannelFailure = undefined;
84
84
  }
85
+ if (endpoint._on_channel_secured) {
86
+ assert(typeof endpoint._on_channel_secured === "function");
87
+ endpoint.removeListener("channelSecured", endpoint._on_channel_secured);
88
+ endpoint._on_channel_secured = undefined;
89
+ }
85
90
  }
86
91
 
87
92
  /**
@@ -102,7 +107,18 @@ const emptyCallback = () => {
102
107
  /* empty */
103
108
  };
104
109
 
105
- export class OPCUABaseServer extends OPCUASecureObject {
110
+ export interface OPCUABaseServerEvents {
111
+ request: [request: Request, channel: ServerSecureChannelLayer];
112
+ response: [response: Response, channel: ServerSecureChannelLayer];
113
+ newChannel: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
114
+ channelSecured: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
115
+ closeChannel: [channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint];
116
+ connectionRefused: [socketData: ISocketData, endpoint: OPCUAServerEndPoint];
117
+ openSecureChannelFailure: [socketData: ISocketData, channelData: IChannelData, endpoint: OPCUAServerEndPoint];
118
+ }
119
+
120
+ // biome-ignore lint/suspicious/noExplicitAny: must propagate EventEmitter generic
121
+ export class OPCUABaseServer<T extends OPCUABaseServerEvents = any> extends OPCUASecureObject<T> {
106
122
  public static makeServiceFault = makeServiceFault;
107
123
 
108
124
  /**
@@ -208,7 +224,7 @@ export class OPCUABaseServer extends OPCUASecureObject {
208
224
  return [];
209
225
  }
210
226
 
211
- protected async createDefaultCertificate(): Promise<void> {
227
+ public async createDefaultCertificate(): Promise<void> {
212
228
  if (fs.existsSync(this.certificateFile)) {
213
229
  return;
214
230
  }
@@ -391,11 +407,23 @@ export class OPCUABaseServer extends OPCUASecureObject {
391
407
 
392
408
  installPeriodicClockAdjustment();
393
409
  // eslint-disable-next-line @typescript-eslint/no-this-alias
394
- const server = this;
410
+ const server: OPCUABaseServer<OPCUABaseServerEvents> = this;
395
411
  const _on_new_channel = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
396
412
  server.emit("newChannel", channel, this);
397
413
  };
398
414
 
415
+ const _on_channel_secured = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
416
+ // Install a response interceptor once per channel so the
417
+ // server can emit "response" events for diagnostics.
418
+ // Done here (after OpenSecureChannel) rather than at
419
+ // newChannel time, so the interceptor can rely on
420
+ // securityPolicy/securityMode being populated.
421
+ channel.setResponseInterceptor((_msg, response1) => {
422
+ server.emit("response", response1, channel);
423
+ });
424
+ server.emit("channelSecured", channel, this);
425
+ };
426
+
399
427
  const _on_close_channel = function (this: OPCUAServerEndPoint, channel: ServerSecureChannelLayer) {
400
428
  server.emit("closeChannel", channel, this);
401
429
  };
@@ -420,6 +448,9 @@ export class OPCUABaseServer extends OPCUASecureObject {
420
448
  endpoint._on_new_channel = _on_new_channel;
421
449
  endpoint.on("newChannel", endpoint._on_new_channel);
422
450
 
451
+ endpoint._on_channel_secured = _on_channel_secured;
452
+ endpoint.on("channelSecured", endpoint._on_channel_secured);
453
+
423
454
  endpoint._on_close_channel = _on_close_channel;
424
455
  endpoint.on("closeChannel", endpoint._on_close_channel);
425
456
 
@@ -442,17 +473,18 @@ export class OPCUABaseServer extends OPCUASecureObject {
442
473
  uninstallPeriodicClockAdjustment();
443
474
  this.serverCertificateManager.dispose().then(() => {
444
475
  debugLog("OPCUABaseServer#shutdown starting");
445
- async.forEach(
446
- this.endpoints,
447
- (endpoint: OPCUAServerEndPoint, callback: (err?: Error) => void) => {
476
+ const promises = this.endpoints.map((endpoint) => {
477
+ return new Promise<void>((resolve, reject) => {
448
478
  cleanupEndpoint(endpoint);
449
- endpoint.shutdown(callback);
450
- },
451
- (err?: Error | null) => {
479
+ endpoint.shutdown((err) => (err ? reject(err) : resolve()));
480
+ });
481
+ });
482
+ Promise.all(promises)
483
+ .then(() => {
452
484
  debugLog("shutdown completed");
453
- done(err);
454
- }
455
- );
485
+ done();
486
+ })
487
+ .catch((err) => done(err));
456
488
  });
457
489
  }
458
490
 
@@ -463,28 +495,16 @@ export class OPCUABaseServer extends OPCUASecureObject {
463
495
  // c8 ignore next
464
496
  if (!callback) throw new Error("thenify is not available");
465
497
  debugLog("OPCUABaseServer#shutdownChannels");
466
- async.forEach(
467
- this.endpoints,
468
- (endpoint: OPCUAServerEndPoint, inner_callback: (err?: Error | null) => void) => {
498
+ const promises = this.endpoints.map((endpoint) => {
499
+ return new Promise<void>((resolve, reject) => {
469
500
  debugLog(" shutting down endpoint ", endpoint.endpointDescriptions()[0].endpointUrl);
470
- async.series(
471
- [
472
- // xx (callback2: (err?: Error| null) => void) => {
473
- // xx endpoint.suspendConnection(callback2);
474
- // xx },
475
- (callback2: (err?: Error | null) => void) => {
476
- endpoint.abruptlyInterruptChannels();
477
- endpoint.shutdown(callback2);
478
- }
479
- // xx (callback2: (err?: Error| null) => void) => {
480
- // xx endpoint.restoreConnection(callback2);
481
- // xx }
482
- ],
483
- inner_callback
484
- );
485
- },
486
- callback
487
- );
501
+ endpoint.abruptlyInterruptChannels();
502
+ endpoint.shutdown((err) => (err ? reject(err) : resolve()));
503
+ });
504
+ });
505
+ Promise.all(promises)
506
+ .then(() => callback())
507
+ .catch((err) => callback?.(err));
488
508
  }
489
509
 
490
510
  /**
@@ -495,13 +515,6 @@ export class OPCUABaseServer extends OPCUASecureObject {
495
515
  assert(message.requestId !== 0);
496
516
  const request = message.request;
497
517
 
498
- // install channel._on_response so we can intercept its call and emit the "response" event.
499
- if (!channel._on_response) {
500
- channel._on_response = (_msg: string, response1: Response /*, inner_message: Message*/) => {
501
- this.emit("response", response1, channel);
502
- };
503
- }
504
-
505
518
  // prepare request
506
519
  this.prepare(message, channel);
507
520
 
@@ -516,7 +529,7 @@ export class OPCUABaseServer extends OPCUASecureObject {
516
529
  let errMessage: string;
517
530
  let response: Response;
518
531
 
519
- this.emit("request", request, channel);
532
+ (this as OPCUABaseServer<OPCUABaseServerEvents>).emit("request", request, channel);
520
533
 
521
534
  try {
522
535
  // handler must be named _on_ActionRequest()
@@ -606,24 +619,24 @@ export class OPCUABaseServer extends OPCUASecureObject {
606
619
  if (!callback) {
607
620
  throw new Error("Internal Error");
608
621
  }
609
- async.forEach(
610
- this.endpoints,
611
- (ep: OPCUAServerEndPoint, _inner_callback) => {
622
+ const promises = this.endpoints.map((ep) => {
623
+ return new Promise<void>((resolve, reject) => {
612
624
  /* c8 ignore next */
613
625
  if (doDebug) {
614
626
  debugLog("Suspending ", ep.endpointDescriptions()[0].endpointUrl);
615
627
  }
616
-
617
628
  ep.suspendConnection((err?: Error | null) => {
618
629
  /* c8 ignore next */
619
630
  if (doDebug) {
620
631
  debugLog("Suspended ", ep.endpointDescriptions()[0].endpointUrl);
621
632
  }
622
- _inner_callback(err);
633
+ err ? reject(err) : resolve();
623
634
  });
624
- },
625
- (err?: Error | null) => callback(err)
626
- );
635
+ });
636
+ });
637
+ Promise.all(promises)
638
+ .then(() => callback())
639
+ .catch((err) => callback(err));
627
640
  }
628
641
 
629
642
  /**
@@ -636,13 +649,14 @@ export class OPCUABaseServer extends OPCUASecureObject {
636
649
  public resumeEndPoints(callback?: (err?: Error | null) => void): void | Promise<void> {
637
650
  // c8 ignore next
638
651
  if (!callback) throw new Error("thenify is not available");
639
- async.forEach(
640
- this.endpoints,
641
- (ep: OPCUAServerEndPoint, _inner_callback) => {
642
- ep.restoreConnection(_inner_callback);
643
- },
644
- (err?: Error | null) => callback(err)
645
- );
652
+ const promises = this.endpoints.map((ep) => {
653
+ return new Promise<void>((resolve, reject) => {
654
+ ep.restoreConnection((err) => (err ? reject(err) : resolve()));
655
+ });
656
+ });
657
+ Promise.all(promises)
658
+ .then(() => callback())
659
+ .catch((err) => callback(err));
646
660
  }
647
661
 
648
662
  protected prepare(_message: Message, _channel: ServerSecureChannelLayer): void {
@@ -28,10 +28,7 @@ export interface ExtractPasswordResult {
28
28
  * @param serverNonce - the nonce that was sent during
29
29
  * CreateSession / last ActivateSession
30
30
  */
31
- export function extractPasswordFromDecryptedBlob(
32
- decryptedBuffer: Buffer,
33
- serverNonce: Nonce
34
- ): ExtractPasswordResult {
31
+ export function extractPasswordFromDecryptedBlob(decryptedBuffer: Buffer, serverNonce: Nonce): ExtractPasswordResult {
35
32
  const invalidResult: ExtractPasswordResult = {
36
33
  valid: false,
37
34
  password: ""
@@ -56,16 +53,11 @@ export function extractPasswordFromDecryptedBlob(
56
53
  return invalidResult;
57
54
  }
58
55
 
59
- const password = decryptedBuffer
60
- .subarray(4, 4 + passwordLength)
61
- .toString("utf-8");
56
+ const password = decryptedBuffer.subarray(4, 4 + passwordLength).toString("utf-8");
62
57
 
63
58
  // verify that the trailing bytes match the server nonce
64
59
  // (nonce binding — ensures session integrity)
65
- const trailingNonce = decryptedBuffer.subarray(
66
- 4 + passwordLength,
67
- 4 + passwordLength + serverNonce.length
68
- );
60
+ const trailingNonce = decryptedBuffer.subarray(4 + passwordLength, 4 + passwordLength + serverNonce.length);
69
61
  if (!trailingNonce.equals(serverNonce)) {
70
62
  return invalidResult;
71
63
  }
package/source/factory.ts CHANGED
@@ -5,11 +5,9 @@
5
5
  import { assert } from "node-opcua-assert";
6
6
  import { ExtensionObject } from "node-opcua-extension-object";
7
7
  import { getStandardDataTypeFactory } from "node-opcua-factory";
8
- import { ExpandedNodeId } from "node-opcua-nodeid";
8
+ import type { ExpandedNodeId } from "node-opcua-nodeid";
9
9
 
10
- export interface EngineForFactory {
11
- /** */
12
- }
10
+ export type EngineForFactory = {};
13
11
  export class Factory {
14
12
  public engine: EngineForFactory;
15
13
 
@@ -1,7 +1,6 @@
1
- import { IAddressSpace, ISessionContext, IEventData } from "node-opcua-address-space-base";
2
- import { checkFilter } from "node-opcua-service-filter";
3
- import { FilterContextOnAddressSpace } from "node-opcua-service-filter";
4
- import { ContentFilter } from "node-opcua-types";
1
+ import type { IAddressSpace, IEventData, ISessionContext } from "node-opcua-address-space-base";
2
+ import { checkFilter, FilterContextOnAddressSpace } from "node-opcua-service-filter";
3
+ import type { ContentFilter } from "node-opcua-types";
5
4
 
6
5
  export function checkWhereClauseOnAdressSpace(
7
6
  addressSpace: IAddressSpace,
@@ -9,8 +8,6 @@ export function checkWhereClauseOnAdressSpace(
9
8
  whereClause: ContentFilter,
10
9
  eventData: IEventData
11
10
  ): boolean {
12
-
13
-
14
11
  // const filterContext: FilterContext = {
15
12
  // addressSpace,
16
13
  // sessionContext,
@@ -24,6 +21,6 @@ export function checkWhereClauseOnAdressSpace(
24
21
  // }
25
22
  // };
26
23
  const filterContext = new FilterContextOnAddressSpace(sessionContext, eventData);
27
-
24
+
28
25
  return checkFilter(filterContext, whereClause);
29
26
  }
@@ -1,8 +1,7 @@
1
- import { IEventData, ISessionContext } from "node-opcua-address-space-base";
2
- import { extractEventFieldsBase } from "node-opcua-service-filter";
3
- import { FilterContextOnAddressSpace } from "node-opcua-service-filter";
4
- import { SimpleAttributeOperand } from "node-opcua-types";
5
- import { Variant } from "node-opcua-variant";
1
+ import type { IEventData, ISessionContext } from "node-opcua-address-space-base";
2
+ import { extractEventFieldsBase, FilterContextOnAddressSpace } from "node-opcua-service-filter";
3
+ import type { SimpleAttributeOperand } from "node-opcua-types";
4
+ import type { Variant } from "node-opcua-variant";
6
5
  //
7
6
 
8
7
  /**
package/source/helper.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import util from "util";
2
- import { OPCUAServer } from "./opcua_server";
3
- import { ServerEngine } from "./server_engine";
4
- import { ServerSession } from "./server_session";
5
- import { Subscription, SubscriptionState } from "./server_subscription";
2
+ import type { OPCUAServer } from "./opcua_server";
3
+ import type { ServerEngine } from "./server_engine";
4
+ import type { ServerSession } from "./server_session";
5
+ import { type Subscription, SubscriptionState } from "./server_subscription";
6
6
 
7
7
  const consolelog = (...args: any) => {
8
8
  const d = new Date();
@@ -25,13 +25,9 @@ const info = (subscription: Subscription) => {
25
25
  SubscriptionState[subscription.state].padEnd(9),
26
26
  subscription.state,
27
27
  "kac=",
28
- subscription.currentKeepAliveCount.toString().padStart(3)+
29
- "/"+
30
- subscription.maxKeepAliveCount.toString().padStart(3),
28
+ subscription.currentKeepAliveCount.toString().padStart(3) + "/" + subscription.maxKeepAliveCount.toString().padStart(3),
31
29
  "ltc=",
32
- subscription.currentLifetimeCount.toString().padStart(3)+
33
- "/"+
34
- subscription.lifeTimeCount.toString().padStart(3),
30
+ subscription.currentLifetimeCount.toString().padStart(3) + "/" + subscription.lifeTimeCount.toString().padStart(3),
35
31
  "prc=",
36
32
  subscription.publishEngine?.pendingPublishRequestCount.toString().padStart(3),
37
33
  "pi=",
@@ -65,14 +61,14 @@ export function installSubscriptionMonitoring(subscription: Subscription) {
65
61
  export function installSessionLoggingOnEngine(serverEngine: ServerEngine) {
66
62
  function on_create_session(session: ServerSession) {
67
63
  try {
68
- session.on("activate_session", function () {
64
+ session.on("activate_session", () => {
69
65
  consolelog("activate_session");
70
66
  });
71
67
 
72
68
  session.on("statusChanged", (status) => {
73
69
  consolelog("session status changed: ", status);
74
70
  });
75
- session.on("new_subscription", function (subscription) {
71
+ session.on("new_subscription", (subscription) => {
76
72
  installSubscriptionMonitoring(subscription);
77
73
  });
78
74
  } catch (err) {
@@ -80,7 +76,7 @@ export function installSessionLoggingOnEngine(serverEngine: ServerEngine) {
80
76
  }
81
77
  }
82
78
  serverEngine.on("create_session", on_create_session);
83
- serverEngine.once("session_closed", function (session) {
79
+ serverEngine.once("session_closed", (session) => {
84
80
  consolelog("session is closed");
85
81
  serverEngine.removeListener("create_session", on_create_session);
86
82
  });
@@ -1,7 +1,16 @@
1
- import { ISessionContext } from "node-opcua-address-space-base";
2
- import { DataValue } from "node-opcua-data-value";
3
- import { StatusCode } from "node-opcua-status-code";
4
- import { BrowseDescriptionOptions, BrowseResult, ReadRequestOptions, WriteValue, CallMethodRequest, CallMethodResultOptions, HistoryReadRequest, HistoryReadResult } from "node-opcua-types";
1
+ import type { ISessionContext } from "node-opcua-address-space-base";
2
+ import type { DataValue } from "node-opcua-data-value";
3
+ import type { StatusCode } from "node-opcua-status-code";
4
+ import type {
5
+ BrowseDescriptionOptions,
6
+ BrowseResult,
7
+ CallMethodRequest,
8
+ CallMethodResultOptions,
9
+ HistoryReadRequest,
10
+ HistoryReadResult,
11
+ ReadRequestOptions,
12
+ WriteValue
13
+ } from "node-opcua-types";
5
14
 
6
15
  export interface IAddressSpaceAccessor {
7
16
  browse(context: ISessionContext, nodesToBrowse: BrowseDescriptionOptions[]): Promise<BrowseResult[]>;
@@ -1,4 +1,4 @@
1
- import { AsymmetricAlgorithmSecurityHeader, MessageSecurityMode, SecurityPolicy } from "node-opcua-secure-channel";
1
+ import type { MessageSecurityMode, SecurityPolicy } from "node-opcua-secure-channel";
2
2
 
3
3
  export interface IChannelData {
4
4
  channelId: number | null;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module node-opcua-server
3
3
  */
4
- import { EventEmitter } from "events";
4
+ import type { EventEmitter } from "events";
5
5
 
6
6
  /**
7
7
  * Finite State Machine for RegisterServerManager.
@@ -46,12 +46,10 @@ export enum RegisterServerManagerStatus {
46
46
  UNREGISTERING = 7,
47
47
  UNREGISTERED = 8,
48
48
  NOT_APPLICABLE = -1,
49
-
49
+
50
50
  DISPOSING = 9
51
51
  }
52
52
 
53
-
54
-
55
53
  export interface IRegisterServerManager extends EventEmitter {
56
54
  /** The URL of the discovery server the manager is configured to connect to. */
57
55
  discoveryServerEndpointUrl: string;
@@ -1,11 +1,13 @@
1
- import { PublishResponseOptions, PublishResponse, StatusChangeNotification } from "node-opcua-types";
2
1
  import assert from "node-opcua-assert";
3
- import { Subscription } from "./server_subscription";
2
+ import type { ExtensionObject } from "node-opcua-extension-object";
3
+ import type { SequenceNumberGenerator } from "node-opcua-secure-channel";
4
+ import { PublishResponse, type PublishResponseOptions, type StatusChangeNotification } from "node-opcua-types";
5
+ import type { Subscription } from "./server_subscription";
4
6
 
5
7
  export interface INotifMsg {
6
8
  subscriptionId: number;
7
9
  sequenceNumber: number;
8
- notificationData: any;
10
+ notificationData: (ExtensionObject | null)[] | null;
9
11
  moreNotifications: boolean;
10
12
  }
11
13
 
@@ -25,10 +27,10 @@ export interface IClosedOrTransferredSubscription {
25
27
  }
26
28
  export class TransferredSubscription implements IClosedOrTransferredSubscription {
27
29
  public id: number;
28
- public publishEngine: any;
30
+ public publishEngine: IServerSidePublishEngine | null;
29
31
  public _pending_notification?: StatusChangeNotification;
30
- private _sequence_number_generator: any;
31
- constructor(options: { id: number; generator: any; publishEngine: any }) {
32
+ private _sequence_number_generator: SequenceNumberGenerator | null;
33
+ constructor(options: { id: number; generator: SequenceNumberGenerator; publishEngine: IServerSidePublishEngine }) {
32
34
  this.id = options.id;
33
35
  this._sequence_number_generator = options.generator;
34
36
  this.publishEngine = options.publishEngine;
@@ -41,8 +43,10 @@ export class TransferredSubscription implements IClosedOrTransferredSubscription
41
43
  this.publishEngine = null;
42
44
  }
43
45
  _publish_pending_notifications(): void {
44
- assert(this._pending_notification);
45
- const notificationMessage = this._pending_notification!;
46
+ if (!this._pending_notification) {
47
+ throw new Error("Internal Error: no pending notification");
48
+ }
49
+ const notificationMessage = this._pending_notification;
46
50
  this._pending_notification = undefined;
47
51
  const moreNotifications = false;
48
52
  const subscriptionId = this.id;
@@ -68,7 +72,10 @@ export class TransferredSubscription implements IClosedOrTransferredSubscription
68
72
  availableSequenceNumbers[availableSequenceNumbers.length - 1] === response.notificationMessage.sequenceNumber
69
73
  );
70
74
  response.availableSequenceNumbers = availableSequenceNumbers;
71
- this.publishEngine._send_response(this, response);
75
+ if (!this.publishEngine) {
76
+ throw new Error("Internal Error: publishEngine is null");
77
+ }
78
+ this.publishEngine._send_response(this as unknown as Subscription, response);
72
79
  }
73
80
  private _get_next_sequence_number(): number {
74
81
  return this._sequence_number_generator ? this._sequence_number_generator.next() : 0;
package/source/index.ts CHANGED
@@ -9,10 +9,10 @@
9
9
  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
10
  * the Software, and to permit persons to whom the Software is furnished to do so,
11
11
  * subject to the following conditions:
12
- *
12
+ *
13
13
  * The above copyright notice and this permission notice shall be included in all
14
14
  * copies or substantial portions of the Software.
15
- *
15
+ *
16
16
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
17
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18
18
  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
@@ -24,15 +24,16 @@
24
24
  * @module node-opcua-server
25
25
  */
26
26
  export * from "./base_server";
27
- export * from "./server_end_point";
27
+ export * from "./helper";
28
+ export * from "./invalidate_server_certificate_cache";
29
+ export * from "./monitored_item";
30
+ export * from "./opcua_server";
28
31
  export * from "./register_server_manager";
29
32
  export * from "./register_server_manager_mdns_only";
30
- export * from "./server_publish_engine";
31
- export * from "./server_subscription";
32
- export * from "./server_session";
33
33
  export * from "./server_capabilities";
34
+ export * from "./server_end_point";
34
35
  export * from "./server_engine";
35
- export * from "./opcua_server";
36
- export * from "./monitored_item";
36
+ export * from "./server_publish_engine";
37
+ export * from "./server_session";
38
+ export * from "./server_subscription";
37
39
  export * from "./user_manager";
38
- export * from "./helper";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @module node-opcua-server
3
+ */
4
+ import { invalidateCachedSecrets } from "node-opcua-common";
5
+ import type { OPCUABaseServer } from "./base_server";
6
+
7
+ /**
8
+ * Invalidate all cached certificates on a running server so that
9
+ * subsequent GetEndpoints / OpenSecureChannel calls reflect the
10
+ * current on-disk certificate.
11
+ *
12
+ * Call this after replacing the server's certificate PEM file.
13
+ * Works with or without push certificate management.
14
+ *
15
+ * ```ts
16
+ * // 1. write new cert to disk (e.g. via CertificateManager)
17
+ * // 2. tell the server to pick it up:
18
+ * invalidateServerCertificateCache(server);
19
+ * ```
20
+ */
21
+ export function invalidateServerCertificateCache(server: OPCUABaseServer): void {
22
+ invalidateCachedSecrets(server);
23
+ for (const ep of server.endpoints) {
24
+ ep.invalidateCertificates();
25
+ }
26
+ }