Skip to content

Releases: node-opcua/node-opcua

🚀 Release Notes — v2.170.0

27 Apr 13:30

Choose a tag to compare

v2.170.1

Bug Fixes & Improvements:

  • Secure Channel: Updated the Aes256_Sha256_RsaPss asymmetric signature to use the correct OPC Foundation URI. (#1495)
  • Packages: Improved address-space cloning capabilities and resolved import issues in the client-proxy package.

node-opcua 2.170.0 — release notes

This release covers all changes between v2.169.0 and HEAD.
Highlights: keepalive resilience, faster socket teardown on HEL/ACK
failure, and richer console.log output for address-space nodes.


✨ Features

Address space

  • Optionals on instantiated interfaces
    implementInterface() now accepts an optionals list and an isModellingType hint (auto-detected from nodeClass), so
    interface members can be selectively exposed when an ObjectType implements an interface. A new
    instantiate_interface_children pass is plumbed through initialize_properties_and_components, so when an instance is
    created from a type that has HasInterface references the interface's mandatory members and any requested optionals are
    materialised on the instance.

  • Nicer console.log / inspect for UAObject and UAVariable
    UAObjectImpl and UAVariableImpl now ship a per-class toJSON() and a nodejs.util.inspect.custom hook so that
    console.log(node) produces a compact, colored, type-aware summary instead of dumping the full reference tree from
    BaseNode.toString().

    • UAObject: typeDefinition, displayName, eventNotifier (and description when present)
    • UAVariable: typeDefinition, displayName, dataType, valueRank, accessLevel, arrayDimensions, current value
      (truncated, skipping OpaqueStructure), statusCode (only when not Good), description

    When the inspect depth is 0 (i.e. the node is nested in another object) a one-line UAObject<browseName nodeId> form
    is used; otherwise a multi-line summary is produced. Colors are stripped via a chalk Proxy when the caller passes
    inspectOptions.colors === false. The full verbose toString() (with the reference dump) is unchanged for
    explicit node.toString() calls.

    BaseNodeImpl.toJSON() return type has been widened to Record<string, unknown> so subclasses can include richer
    values.


🐛 Fixes

Client - keepalive

  • Distinguish server-originated faults from transport errors
    (client_session_keepalive_manager.ts)
    A new ServiceFaultAnnotatedError interface types the .response annotation set by the secure-channel layer.
    _ping_server now checks for this annotation before deciding whether to reconnect:

    • Recoverable ServiceFault → emit keepalive_failure, keep the channel up.
    • Transport error or session-gone fault
      (BadSessionIdInvalid, BadSessionClosed) → trigger a full reconnection.
      StatusCode comparisons are now value-based (sc?.equals(...)) rather than reference-based, so faults carrying a freshly
      constructed StatusCode instance are still recognised.
  • Exponential backoff on consecutive ServiceFaults
    Track consecutiveFailures on ClientSessionKeepAliveManager. When _ping_server returns
    an explicit backoff value (greater than checkInterval), ping_server uses it directly as the next scheduling
    interval. Consecutive recoverable ServiceFaults now back off as 2x, 4x, 8x … capped at 60 s, preventing a tight
    reconnect loop against a persistently faulting server.

Transport

  • Release socket immediately on HEL/ACK failure
    (client_tcp_transport.ts)
    _on_ACK_response now uses socket.destroy() instead of socket.end() and nulls out _socket before invoking the
    callback. The file descriptor is freed immediately rather than after the callback chain has completed. New regression test
    TCS-10 in test_client_tcp_transport.

Address space

  • Misc address-space correctness fixes
    • address_space.ts: fix EvenTypeEventType typo; log a warningLog when sourceNode cannot be resolved
      (instead of silently emitting an empty SourceName); align constructEventData signature with IAddressSpace
      (Record<string, unknown>) while keeping internal RaiseEventData typing.
    • base_node_private.ts: _remove now actually removes the reference from _childByNameMap (the previous filter
      result was discarded). Collapses to a single ref or deletes the key when the array becomes empty.
    • _instantiate_helpers.ts:
      instantiate_interface_children now falls back to addressSpace.findObjectType(reference.nodeId) when
      reference.node is unresolved.
    • ua_object_impl.ts: tidy raiseEvent error messages (separators).

🧹 Refactor / chore

  • refactor(event-data): encapsulate event data source
    Drop the public $eventDataSource field on IEventData / EventData and replace it with a getEventDataSource()
    accessor. Internal state (__values, __nodeIdToNode, __pathToNodeId, __nodeIdToFullPath) moves into a private
    #cache field so callers can no longer reach into EventData internals. Tightens constructEventData(...)
    typing from any to Record<string, unknown> and updates every consumer (address_space, condition_snapshot,
    monitored_item, filter context) to use the new accessor.

    ⚠ Breaking change for any downstream code reaching for
    eventData.$eventDataSource — use eventData.getEventDataSource() instead.

  • Biome conformance cleanup (across address-space and beyond)

    • Replace non-null assertions with optional chaining.
    • Switch Object.prototype.hasOwnProperty / isFinite / isNaN to Object.hasOwn /
      Number.isFinite / Number.isNaN.
    • Convert string concatenation to template literals.
    • Switch fs / path imports to the node: protocol in test helpers.
    • Reorder type-only and side-effect imports.
    • Sort exports alphabetically in test_helpers/index.
    • Bump Opc.Ua.Types.xsd model metadata to 1.05.06 / 2025-11-08.
  • Test cleanup

  • Sort imports, drop unused locals, prefix intentionally-unusedvariables with _, and switch modeler/test_promoteToMandatory
    from raw describe to describeWithLeakDetector. Plus minor lint fixes across address-space tests.


📦 Commits

  • dc406fd fix(client,transport): copilot review fixes
  • 481664f fix(client): add exponential backoff for consecutive keepalive ServiceFaults
  • 4d59197 fix(client): distinguish server-originated faults from transport errors in keepalive
  • 1959cbb fix(transport): release socket immediately on HEL/ACK failure
  • 5516ea5 fix(address-space): copilot review fixes
  • 7642815 chore(test): biome cleanup and leak-detector adoption in address-space / modeler tests
  • 5bb4490 feat(address-space): nicer console.log / inspect for UAObject and UAVariable
  • b57cd78 feat(address-space): support optionals on instantiated interfaces
  • 6743834 refactor(event-data): encapsulate event data source via getEventDataSource()
  • b9bbb0f chore: extend biome conformance cleanup beyond address-space src/
  • fa65688 chore(address-space): minor refactoring for biome conformance

🔁 Migration notes

  • If your code reads eventData.$eventDataSource, switch to eventData.getEventDataSource().
  • If you implemented a custom IAddressSpace / constructEventData, the parameter type is now
    Record<string, unknown>.
  • If you call BaseNodeImpl.toJSON() and rely on its previous return type (Record<string, string | undefined | null>),
    the return type is now Record<string, unknown>.

👬🏽 Contributors

  • special thanks to @Velluso for reporting keep alive issues.

v2.169.0

27 Apr 13:12

Choose a tag to compare

node-opcua v2.169.0 — Release Notes

Release date: April 2026
Previous version: v2.168.0

TL&DR : GDS Provisioning Made Robust — Certificate Chain Handling, Secure Diagnostics, and Resilience Fixes

This release focuses on making the GDS (Global Discovery Server) provisioning workflow bulletproof: from the moment a freshly deployed server starts in NoConfiguration state, through the initial GDS handshake, all the way to production operation with full certificate chain validation.

  • 🔐 Certificate Chain Management : full chain persistence, smarter auto-trust, accurate error reporting, and TrustListDataType fixes
  • 🛡️ NoConfiguration Relaxation: documented security rationale + client-side onboarding relaxation
  • 🔧 Server Hardening: RBAC on EnabledFlag, double-shutdown guard, null guards, and CSR error handling
  • 🔍 Observability: JSON serialization & util.inspect for core classes

🔐 Certificate Chain Management — End-to-End Overhaul

Full certificate chain persistence

Previously, the server stored only the leaf certificate on disk after a GDS UpdateCertificate call. If the leaf was CA-signed, connecting clients would see an incomplete chain and fail validation. This release ensures the full chain (leaf + issuer CAs) is persisted to certificate.pem using the standard multi-block PEM format, and the legacy certificate.der file is no longer written.

A new startup precondition check detects when an existing certificate.pem contains only a leaf certificate that should have a chain. When this is found, a prominent [NODE-OPCUA-W60] warning is logged with actionable guidance — but the server does not auto-heal the file, leaving that responsibility to the provisioning tooling.

A new end-to-end test verifies that a server with a chained certificate correctly exposes the full chain in the CreateSession response.
([a72196e], [d6e33a9])

Smarter auto-trust during NoConfiguration

The autoTrustCertificateChain() function has been refined: during NoConfiguration state, only the leaf certificate is placed in the
trusted store. Issuer CA certificates are filed in the issuers/ store for chain-building, but they are no longer granted trust-anchor status. This prevents a single GDS provisioning connection from inadvertently trusting every certificate signed by the same CA.
([add1af8])

Accurate error reporting in certificate checks

#checkCertificate previously conflated BadCertificateRevocationUnknown with BadCertificateUntrusted, always returning "untrusted" when auto-accept was disabled. These are now handled separately, so diagnostic information about the actual issue (missing CRL vs. untrusted leaf) is preserved for logging and client feedback.
([16aeb1e])

TrustListDataType preserves full chains

readAll() now returns the full chain ByteString in trustedCertificates when addTrustedCertificateFromChain previously stored a leaf + issuer CAs in a single PEM. Clients consuming the TrustListDataType can use split_der() to extract individual certificates for thumbprint computation.
([d6e33a9])


🛡️ NoConfiguration Certificate Relaxation — Documented & Hardened

Comprehensive relaxation documentation

The isRelaxableCertificateError() function now carries extensive JSDoc explaining the security rationale for relaxing BadCertificateUntrusted during NoConfiguration state:

  • The trust store is empty by definition, so every client cert — including the GDS itself — would fail validation without relaxation.
  • Relaxation is bounded: it fires only while the server state is NoConfiguration; once the server transitions to Running, strict
    validation applies.
  • Security-critical errors (revoked, expired, invalid signature) are never relaxed, even in NoConfiguration.
    ([07364b5])

Client-side relaxation for GDS onboarding

The certificate manager now extends automaticallyAcceptUnknown to also handle BadCertificateRevocationUnknown on the client side. Per OPC UA Part 12 §7.9, a client connecting to a GDS for the first time cannot possibly have the CRL for a certificate it just discovered. This mirrors the server-side relaxation introduced in v2.168.0.

Also fixed: isGood() is now used instead of reference equality (=== StatusCodes.Good) for cross-module safety when the certificate
manager and client are loaded from different module instances.
([d67df80])

🔧 Server Hardening & Diagnostics

Role-based access control on ServerDiagnostics.EnabledFlag

The ServerDiagnostics.EnabledFlag node was previously protected by a dead-code if (true) block that unconditionally prevented writes. This has been replaced with proper OPC UA Part 5 §12.4 role-based permissions:

Role Permissions
ConfigureAdmin Read, Browse, Write
SecurityAdmin Read, Browse, Write
All other roles Read, Browse

([c20211f])

Guard against double-shutdown crash

setServerState() could crash with "Cannot read properties of null" when called after dispose() had already nulled _serverStatus. This happens in test scenarios where shutdown() is called twice (e.g. once in a finally block and again in afterEach). A null guard now returns early.
([15fc146])

Null guard in resendMonitoredItemInitialValues

publishEngine is set to null during session disposal, but
resendMonitoredItemInitialValues was the only accessor that didn't guard against this. This caused a TypeError during concurrent client reconnects when the session_activated event fired against a session already being disposed.
([29a8805])

CSR generation error handling

CreateSigningRequest now catches errors thrown by createCertificateRequest (e.g. OpenSSL failures due to invalid subject format). Previously, unhandled exceptions propagated as generic BadInternalError with no context. The handler now logs the actual error, the subject name, and the applicationUri, and returns BadInternalError with diagnostic information.
([c07f946])


🔍 Observability & Developer Experience

JSON serialization and util.inspect for core classes

Core OPC UA classes now implement robust toJSON(), toString(), and [nodejs.util.inspect.custom] methods. Logging and debugging tools now produce consistent, human-readable representations of sessions, servers, endpoints, and other internal objects — a significant quality-of-life improvement for developers working with node-opcua at runtime. ([bfd1e47])

Enhanced OPCUAServer.toString()

The server's toString() output has been updated to include richer state information for quick diagnostics during development. ([d77158c])


🧹 Maintenance

  • Test hygiene: dispose() calls in certificate-manager tests are now properly await-ed, eliminating file-watcher cleanup races and spurious setTimeout leak warnings ([d7373c9]).
  • Dependency updates: node-opcua-pki version bumped ([637a759]); general package updates ([4d97f40]).

Affected Packages

Package Change type
node-opcua-server feat, fix, refactor
node-opcua-server-configuration feat, fix, refactor, doc
node-opcua-certificate-manager fix
node-opcua-secure-channel fix
node-opcua-client fix
node-opcua-address-space chore
node-opcua-address-space-base chore
node-opcua-common chore
node-opcua-samples fix
node-opcua-end2end-test test

Upgrading

This release is a non-breaking minor version bump. No API changes are required for existing consumers. The on-disk certificate format change (.pem with full chain instead of .der) is handled transparently by the existing CertificateManager migration logic introduced in the prior node-opcua-pki updates.

Note: If you manually manipulate certificate files on disk, ensure your certificate.pem contains the full chain (leaf + issuer CAs) for CA-signed certificates. The new [NODE-OPCUA-W60] warning at startup will alert you if the chain is incomplete.

v2.168.0

04 Apr 07:43

Choose a tag to compare

Release Notes - v2.168.0

TL;DR:

Version 2.168.0 is a stability and performance release. It fixes a infinite recursion bug in response handling (#1490), fully migrates core packages from async/lodash to native modern JavaScript patterns, and introduces a more robust typed event system and certificate management architecture.


✨Features

  • Server: Added channelSecured event for post-handshake notifications [af7ef34].

🐛Bug Fixes

  • Core: Prevented infinite recursion in send_response when chunking fails (#1490) [51ef025].
  • Secure Channel: Implemented fallback to the latest valid token when a request's token expires [ae65dea].
  • Server: Deferred channel shutdown until after the ApplyChanges response is sent [8484b98].
  • Address Space: Fixed address-space-base imports and applied security hardening [d636f0c].
  • Maintenance: Resolved various TypeScript and Biome violations across the codebase [16302c4, 45a1406, 887a42d, 1372b5c].
  • Tests: Hardened server shutdown tests [c834243], added TokenStack fallback coverage [823f38d], and increased T73 secure channel renewal token lifetime to reduce flakiness [a13bbb0].

🔧 Refactoring & Improvements

  • Performance: Replaced async library [3269940] and lodash [b99520d] with native async/await, Promises, and targeted alternatives.
  • Type Safety: Unified certificate chain providers [49b8736] and implemented typed EventEmitter<T> patterns for server events [1f7040e].
  • Structure: Split conformance testing into focused modules [e4c5eb9] and cleaned up the address space conformance package [168a8f6].
  • Transport: Enhanced type safety and removed unsafe patterns in the transport layer [785d89f].
  • Security: Simplified push certificate management [dab64e9].
  • Debugability: Internal channel callbacks are now hidden from the debugger for a cleaner debugging experience [e0d2b40].
  • Testing Infrastructure: Hardened leak detector for Mocha 12 and tsx [c7170e5].

🧹 Chores

  • Updated Biome formatting [465eb93] and fixed misused Mocha timeout configurations [eac92cc].

👬🏽 Contributors

What's Changed

🚀 Release Notes — v2.167.0

30 Mar 19:49

Choose a tag to compare

node-opcua Release Notes: v2.165.1 → v2.167.0

v2.167.0

✨ Features

  • server-config: Accept certificate chain in TrustListClient.addCertificate — enables full chain trust management via the GDS push model [135902c]
  • core: Thread ISessionContext through ApplyChanges event chain — allows consumers to identify which session triggered a configuration change [4033f97]

🐛 Bug Fixes

  • server: Harden register_server_manager against null/missing values [95b5aa5]
  • server: Use explicit length check for certificate chain instead of truthiness guard — prevents edge cases with empty arrays [ef3f04e]
  • core: Harden certificate validation and fix Certificate[] migration [d276591]
  • core: Resolve tsc --noEmit errors in node-opcua-end2end-test test suite [e34bbb1]

🔧 Refactor

  • server-config: Self-contained test certificates — tests no longer depend on external PKI state [13f310f]

v2.166.1

🐛 Bug Fixes

  • client: Fix "Callback was already called" race condition during connection abort — prevents double-callback crash when a connection is terminated mid-handshake [c487bf5]

🧹 Chores

  • Update node-opcua-pki / node-opcua-crypto dependencies [713f852]

v2.166.0

🐛 Bug Fixes

  • secure-channel: Add TTL eviction to nonce cache — prevents unbounded memory growth on long-lived servers with many reconnections [b82c293]
  • server: Add nonce verification to UserNameIdentityToken password extraction — hardens against replay attacks [c6b0573]

🧹 Chores

⚠️ Security

  • Nonce verification for password tokens [c6b0573]: The server now verifies that the nonce embedded in UserNameIdentityToken matches the nonce issued during CreateSession. This is a security hardening measure that protects against credential replay attacks.

  • Nonce cache TTL eviction [b82c293]: Stale entries in the secure-channel nonce cache are now evicted after a configurable TTL, preventing memory exhaustion on servers handling many short-lived client connections.


v2.165.2

🧹 Chores

  • Update packages — support for OpenSSL > 3.5 [e625c48]

Test Fixes (across versions)

  • Fix hardcoded namespace index in AddIn instantiation test [25ab1b6]
  • Fix chained certificate test to expect success instead of failure [c0f5f35]

Upgrade Notes

Tip

OpenSSL 3.5+ support: v2.165.2+ includes updated node-opcua-pki and node-opcua-crypto packages that are compatible with OpenSSL 3.5+. If you were seeing crypto-related errors on newer Node.js builds, this update resolves them.

Note

Certificate chain support: If you use GDS push certificate management, TrustListClient.addCertificate now correctly handles full certificate chains (not just leaf certificates). No API changes required — existing code continues to work.

v2.165.1 (patch)

23 Mar 09:48

Choose a tag to compare

Full Changelog: v2.165.0...v2.165.1

Bump global-mutex version

see https://github.com/node-opcua/node-opcua/releases/tag/v2.165.0 for latest release notes

🚀 Release Notes — v2.165.0

18 Mar 18:19

Choose a tag to compare

node-opcua v2.165.0 — Release Notes

Release date: 2026-03-18

This release brings advertised-endpoints support (ideal for Docker / NAT / proxy deployments), a global method-call interceptor API, several new server lifecycle helpers, and important bug fixes for extension-object binding and certificate handling.


✨ New Features

1. Advertised Endpoints — Docker / NAT / Proxy support

When a server runs behind Docker port-mapping, a reverse proxy, or a NAT gateway, the internal listen URL differs from the URL that clients actually use. The new advertisedEndpoints option lets you declare external URLs that are returned in GetEndpoints responses, while the server continues to listen on its original port.

Simple string shorthand

import { OPCUAServer } from "node-opcua";

const server = new OPCUAServer({
    port: 4840,
    advertisedEndpoints: "opc.tcp://public.example.com:48401",
});

Multiple URLs

const server = new OPCUAServer({
    port: 4840,
    advertisedEndpoints: [
        "opc.tcp://public.example.com:48401",
        "opc.tcp://vpn.internal:4840",
    ],
});

Per-URL security overrides

Different interfaces can have different security requirements — for example a public endpoint that enforces SignAndEncrypt and disallows anonymous access, while the internal one allows all modes:

import { MessageSecurityMode, OPCUAServer } from "node-opcua";

const server = new OPCUAServer({
    port: 4840,
    securityModes: [
        MessageSecurityMode.None,
        MessageSecurityMode.Sign,
        MessageSecurityMode.SignAndEncrypt,
    ],
    allowAnonymous: true,

    advertisedEndpoints: [
        // Internal — inherits everything from main settings
        "opc.tcp://docker-internal:4840",

        // Public — restricted
        {
            url: "opc.tcp://public.example.com:48401",
            securityModes: [MessageSecurityMode.SignAndEncrypt],
            allowAnonymous: false,
        },
    ],
});
Override field Type Default
url string (required)
securityModes MessageSecurityMode[] inherit from main
securityPolicies SecurityPolicy[] inherit from main
allowAnonymous boolean inherit from main
userTokenTypes UserTokenType[] inherit from main

Automatic certificate SAN management

IP addresses and hostnames declared in alternateHostname or advertisedEndpoints are automatically included in the self-signed certificate's SAN fields (IPs → iPAddress, hostnames → dNSName). A [NODE-OPCUA-W26] warning is logged at startup if the current certificate is missing any configured host.

const server = new OPCUAServer({
    port: 4840,
    alternateHostname: ["my-docker-host", "192.168.1.100"],
    advertisedEndpoints: "opc.tcp://10.0.0.1:4840",
});
// Certificate SAN will include:
//   dNSName:   [hostname, fqdn, "my-docker-host"]
//   iPAddress: [auto-detected IPs, "192.168.1.100", "10.0.0.1"]

To regenerate the certificate at any time:

await server.regenerateSelfSignedCertificate();

See advertised_endpoints.md for a Docker Compose example.

Commits: 1479f84, e199c94, d157e5d, 52b7688, 8d1fa7e, 04dee73, f60fcd4, 8b202b5, d8c2ac9, b539721


2. Global Method Call Interceptors

A new addMethodCallInterceptor() API on IAddressSpace lets you register global interceptors that run before every OPC UA method call. Interceptors can perform authorisation checks, audit logging, or rate-limiting without modifying individual method implementations.

import { StatusCodes } from "node-opcua";

// Register a global interceptor
server.engine.addressSpace!.addMethodCallInterceptor(
    async (context, methodId, inputArguments) => {
        // Example: only allow calls from authenticated sessions
        if (!context.userIdentity) {
            return StatusCodes.BadUserAccessDenied;
        }
        return StatusCodes.Good; // allow the call
    }
);

Interceptors are chainable — multiple interceptors run sequentially and the first non-Good status code short-circuits the chain.

A per-method "afterCall" event is emitted after successful execution, useful for auditing:

const myMethod = addressSpace.findNode("ns=1;s=MyMethod");
myMethod.on("afterCall", (context, callMethodResult) => {
    console.log("Method executed successfully:", callMethodResult);
});

Remove an interceptor when it is no longer needed:

server.engine.addressSpace!.removeMethodCallInterceptor(myInterceptor);

Commits: 5fc3ee6, d8d6aa4


3. OPCUAServer.setServerState() / getServerState()

Change the ServerStatus.State variable at runtime so that OPC UA clients see the updated value via Read or subscriptions:

import { ServerState } from "node-opcua";

// Put the server into a maintenance state
server.setServerState(ServerState.Shutdown);

// Query it back
const state = server.getServerState();

Commits: 98b53a1, df4b5ab


4. OPCUAServer.setRolePolicyOverride()

Dynamically override role resolution logic without replacing the userManager. This is particularly useful during GDS Application Setup, where you may want to grant SecurityAdmin to anonymous sessions temporarily:

import { WellKnownRoles } from "node-opcua";

// Grant SecurityAdmin to all sessions during provisioning
server.setRolePolicyOverride({
    getUserRoles: (username) => {
        return [WellKnownRoles.SecurityAdmin];
    },
});

// Remove override when provisioning is complete
server.setRolePolicyOverride(null);

Commits: 16be8a2


5. OPCUAServer.setInApplicationSetup() / getInApplicationSetup()

Managed getter/setter for the optional ServerConfiguration.InApplicationSetup property, useful for GDS onboarding workflows:

// Mark server as in application setup
server.setInApplicationSetup(true);

// Check status
const isSetup = server.getInApplicationSetup();

// Clear when done
server.setInApplicationSetup(false);

Commits: 9f6db25


6. PushCertificateManager Post-Call Events

Three new typed events on PushCertificateManagerServerImpl let downstream code react to provisioning state changes:

const pcm = server.getPushCertificateManager(); 

pcm.on("applyChangesCompleted", (statusCode, context) => {
    console.log("ApplyChanges completed:", statusCode);
    // 'context' includes the client's certificate and
    //  application URI (via ISessionContext)
});

pcm.on("certificateUpdated", (groupId, certificate) => {
    console.log("Certificate updated for group:", groupId);
});

pcm.on("trustListUpdated", (groupName) => {
    console.log("Trust list updated:", groupName);
});

The ISessionContext is now threaded through the entire ApplyChanges call chain, so event listeners can inspect context.clientCertificate and context.clientApplicationUri.

Commits: a120c71, f6f0e36


7. ISessionContext Enhancements

Two new convenience properties on ISessionContext:

// In a method handler or event listener:
const cert = context.clientCertificate;     // Buffer | null
const uri  = context.clientApplicationUri;  // string | null

These delegate to the underlying secure channel without requiring manual traversal of session.channel.

Commits: c85782e


🐛 Bug Fixes

setValueFromSource corrupts terminal-type fields in bound extension objects

Impact: If you called setValueFromSource() on a UAVariable that had a bound extension object containing Date, NodeId, QualifiedName, LocalizedText, DiagnosticInfo, or array fields, those values were silently corrupted:

  • Date values reverted to 1601-01-01 (OPC UA epoch)
  • OPC UA subscriptions missed value changes on terminal-type fields

Root cause: The internal _update_extension_object() function used instanceof Object to decide whether to recurse into a field. Since all non-primitive types satisfy this check, the function recursed into them instead of assigning directly through the proxy.

Fix: Replaced the instanceof Object check with whitelist functions that use isProxy() for existing sub-structures and constructor-name exclusions for terminal types. 13 new unit tests cover all terminal types.

Commits: b19a68d


Redundant trustCertificate call in performCertificateSanityCheck

Impact: After OPCUAServer.initialize(), isTrustListEmpty() returned false because the server's own certificate was added to its trusted store — preventing correct GDS onboarding detection.

Fix: Removed the self-trust call. The W04 informational warning is now correctly suppressed for the server's own certificate (renamed to W35 to avoid duplicate warning numbers).

Commits: 562f69b, 676028d


Certificate type NodeIds corrected to OPC UA 1.05 spec

All certificate type NodeIds (RSA and ECC) were using pre-1.05 spec values. They now resolve dynamically from the loaded nodeset using resolveNodeId("BrowseName"). Phantom types RSA_Sha256_2048 and RSA_Sha256_4096 (which don't exist in the spec) have been removed.

Commits: cb961b7


StructureField dataType normalized to BaseDataType

When a StructureField's DataType was omitted in XML nodesets or via the programmatic API, dataType became NodeId.nullNodeId (ns=0;i=0) instead of `BaseDa...

Read more

🚀 v2.164.2

07 Mar 14:08

Choose a tag to compare

Release Notes (v2.163.2 -> HEAD)

🚀 Features & Improvements

  • ServerConfiguration: Architectural overhaul of PushCertificateManagerServerImpl, extracting file transaction and certificate validation logic. Refactored to utilize the OPCUACertificateManager API. ([f594e65], [52c4057], [2099377], [09d79f2], [cd7f612])
  • Resource Management: Improved resource leak detection with mem_leak_detector and increased timer proxy robustness. Prevented potential stdio deadlocks, file descriptor leaks, and memory leaks in TCP_transport socket dispose. ([7b96b9d], [ae162d3], [de0e91f], [46eeccf])
  • Address Space: Added missing dispose() to IContinuationPointManager implementations. ([00f0076])
  • Tooling: Replaced deprecated ts-node with tsx across the monorepo to enhance compatibility and performance. ([f137752], [00fee24])

🐛 Bug Fixes

  • Client / Publish Engine: Handled BadSecureChannelIdInvalid correctly within the client publish engine. ([73d9443], [364b86d])
  • Secure Channel & Transport: Resolved TR19 test failure caused by a race condition and forced immediate socket destruction on connection break. ([310f8fc], [73e7b6f])
  • Data Types: Fixed BaseDataType/Variant mismatch, corrected bitfield encoding, and improved subtype validation. ([1ec0a39])
  • Alarms & Conditions: Prevented enabledState missing properties during reconstruction and updated Certificate Expiry to use setTimeout instead of setInterval. ([e350e2e], [e40ef26])
  • Historical Access: Ensured startOfOnlineArchive gracefully handles null dates. ([599f2c8])
  • Certificate Manager: Fixed ENOENT race condition during concurrent certificate trust and addressed related EPERM lock and 0-size certificate checks. ([e9b4ea4], [d9c2f4c], [e85a46d])
  • General: Preserved original error in backoff abort handler and replaced deprecated url.parse() with WHATWG URL API as well as deprecated Buffer() constructor. ([ec1aca8], [4508fc8], [0e01525])

🛠️ Refactoring & Chores

  • Dependencies: Bumped @ster5/global-mutex to ^3.1.2, node-opcua-pki up to 6.7.3, and updated node-opcua-crypto to ^5.0.0. Adapted client and server codebases to the new node-opcua-pki@6 API. ([cdcdf36], [9c22cb9], [d120622], [34939fc], [3c044d6], [2f0fa14], [acc794c])
  • CI/CD: Added Windows CI/CD pipeline matrix testing for Node.js 20, 22, and 24. ([9619bb2], [48c17a0])
  • Cleanup: Removed mkdirp and rimraf dependency usage. Replaced istanbul ignore with c8 ignore. Normalized all Mocha configuration files to .mocharc.yml. ([4c4cd46], [00b9f69], [9860ed2], [7cbef7a], [1daab63])
  • Documentation: Created CONTRIBUTING.md. ([cdbf9d5])

🧪 Testing

  • Resolved various test flakiness issues (e.g., AZAZ-B, SubscriptionDiagnostics-3, test discovery hang). ([e85a46d], [132cc66], [63e1283])
  • Improved test robustness under heavy load and adjusted timings to be resilient to publish cycle timing variations. ([7dd6caf], [035fb8c], [5a47660], [1daa428])
  • Added support for ESM TypeScript test files in Mocha runner. ([90faf56])
  • Resolved OOM errors in server-configuration tests by implementing PKI pooling and cleaned up imports awaiting async parses. ([a24a098], [26d8613], [d1dc69c])

👬🏽 Contributors

🚀 v2.163.0

08 Feb 08:04

Choose a tag to compare

This release is a major step forward for DataType handling performance and OPC UA 1.05 compliance. It introduces a new lazy and parallel DataType extraction pipeline, significantly improving scalability for large and complex information models. In parallel, full support for OPC UA 1.05 subtyped structures and unions has been finalized, alongside multiple performance optimizations, correctness fixes, and test expansions.

✨ TL;DR

  • 🚄 Massive performance improvements for dynamic DataType discovery (lazy + parallel extraction)
  • 🧠 New Lazy DataType extraction strategy (default on client side)
  • 🧬 Full support for OPC UA 1.05 StructureWithSubtypedValues and UnionWithSubtypedValues
  • 🧪 Expanded test coverage for large DataType trees, continuation points, and reconnection edge cases
  • 🧹 Package updates and generated nodeset-type adjustments

🌟 Key Features & Enhancements

🧠 Lazy & Parallel DataType Extraction

  • 3ad017c Introduced a Lazy DataTypeExtractStrategy to efficiently handle very large DataType trees:

    • Pre-creates DataTypeFactory per namespace using readNamespaceArray
    • Avoids eager loading of all DataTypes
    • Adds strategy-aware session handling and extraction helpers
    • Extends tests to validate Auto, Force104, and Lazy strategies (datatype-manager)
  • 984510c Major performance refactor:

    • Parallel resolution of structure fields with Promise.all
    • Lazy on-demand DataType loading
    • Non-reentrancy guard to avoid duplicate network requests
    • Reduced session round-trips and improved batching (datatype-manager / client)
  • 57374f8 Prefetch dependent field DataTypes in parallel during schema extraction:

    • Restores eager extraction for server-side safety
    • Sets Lazy as the new default client strategy
    • Guarantees idempotency during parallel resolution (datatype-manager)

🧬 OPC UA 1.05 — Subtyped Structures & Unions

  • 4e02e64 Added full support for OPC UA 1.05 subtyped fields:

    • StructureWithSubtypedValues
    • UnionWithSubtypedValues
    • Proper parsing of AllowSubTypes
    • Correct encoding/decoding and cloning of ExtensionObjects
    • Comprehensive unit tests and XML fixtures (address-space / dynamic-extension-object)
  • 17ea9bb Fixed client-side creation of ExtensionObjects containing subtyped fields (client)

📌 Summary

Version 2.163.0 delivers substantial scalability gains for complex OPC UA servers and clients, especially those with large DataType graphs or OPC UA 1.05 models. Lazy, parallel extraction dramatically reduces startup time and network load while maintaining strict correctness and backward compatibility.

💙 Support the project

Consider joining the NodeOPCUA Subscription program
for professional support, or help sustain the project by sponsoring us on OpenCollective
.
Full Changelog: v2.162.0...v2.163.0

v2.162.0

03 Feb 19:55

Choose a tag to compare

🚀 Release Notes — v2.162.0

This release focuses on performance improvements, memory optimizations, and protocol robustness, with additional updates to OPC UA 1.05 nodesets, better TypeScript generation, and fixes in client-side extension object handling. Several hot paths (transport, secure channel, chunk manager, variant encoding) have been optimized to reduce allocations and improve throughput under load.

✨ TL;DR

  • Significant performance & memory optimizations in transport, secure channel, chunk manager, and variant encoding
  • Updated OPC UA 1.05 nodesets with smarter fallback for ComplexDataType handling
  • Fixed client-side ExtensionObject creation with subtyped fields
  • Improved TypeScript generator correctness for inherited generic members
  • Added tests and documentation for packet assembly and reconnection scenarios

⚡ Performance Improvements

  • 3ff99c3 — Avoid unnecessary buffer copies in the transport layer (transport)
  • 6347ba6 — Faster buffer encoding/decoding for Variants (variant)
  • 6339b87 — Reduce memory retention by not keeping raw message chunks unless performance monitoring is enabled (transport)
  • e99143f — Zero-copy padding removal and length reduction using Buffer.subarray (secure-channel)
  • 30cf813 — Optimize padding byte writing using Buffer.fill() (~10% throughput gain) (chunk-manager)

🧠 Protocol & Feature Enhancements

  • d1697eb — Detect ComplexDataType2017 profile to automatically force OPC UA 1.04 extraction when required (client / datatype extraction)
  • e62d0e9 — Update nodeset XML files to the latest OPC UA 1.05 revisions (nodesets)
  • 8343203 — Add documentation and tests for packet assembler (packet-assembler)

🐛 Bug Fixes

  • 17ea9bb — Fix client-side creation of ExtensionObjects containing subtyped fields (client)
  • 332fbed — Fix typo in “already used nonce” error message (server)
  • 7149387 — Fix inherited member type compatibility in the TypeScript generator (generator) 👉 Fixes GitHub issue #1472

🧪 Tests & Tooling

  • e230cef — Add end-to-end tests exploring reconnection behavior after keepalive failures (end2end-test)
  • 50c0cf9 — Minor adjustment to run_all_mocha_tests.js (tests)

🧹 Maintenance & Cleanup

  • 4e06dc1 — Dependency updates
  • da12830 — Additional package updates
  • 67da20e — Improved warning messages
  • 415b89e — Version bump to v2.162.0

📌 Note

This release brings measurable gains in performance and memory efficiency, especially for high-throughput clients and servers, while continuing the transition toward OPC UA 1.05 compliance with robust backward-compatibility handling.

New Contributors

Full Changelog: v2.161.0...v2.162.0

historyRead with ExtensionObject

03 Feb 02:36

Choose a tag to compare

47b5982 fix(client): ensure historyRead delegates to promoteOpaqueStructure

- Promote OpaqueStructure to ExtensionObject in historyRead results for
  HistoryData with dataValues.
- Use promoteOpaqueStructure to resolve DataType similar to the read method.
- Add regression test test_e2e_history_read_extension_object.ts.
- Include playground example server_with_historizing_extension_object.ts.