Releases: node-opcua/node-opcua
🚀 Release Notes — v2.170.0
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 anoptionalslist and anisModellingTypehint (auto-detected fromnodeClass), so
interface members can be selectively exposed when anObjectTypeimplements an interface. A new
instantiate_interface_childrenpass is plumbed throughinitialize_properties_and_components, so when an instance is
created from a type that hasHasInterfacereferences the interface's mandatory members and any requested optionals are
materialised on the instance. -
Nicer
console.log/inspectforUAObjectandUAVariable
UAObjectImplandUAVariableImplnow ship a per-classtoJSON()and anodejs.util.inspect.customhook 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(anddescriptionwhen present)UAVariable:typeDefinition,displayName,dataType,valueRank,accessLevel,arrayDimensions, current value
(truncated, skippingOpaqueStructure),statusCode(only when notGood),description
When the inspect depth is
0(i.e. the node is nested in another object) a one-lineUAObject<browseName nodeId>form
is used; otherwise a multi-line summary is produced. Colors are stripped via a chalkProxywhen the caller passes
inspectOptions.colors === false. The full verbosetoString()(with the reference dump) is unchanged for
explicitnode.toString()calls.BaseNodeImpl.toJSON()return type has been widened toRecord<string, unknown>so subclasses can include richer
values.
🐛 Fixes
Client - keepalive
-
Distinguish server-originated faults from transport errors
(client_session_keepalive_manager.ts)
A newServiceFaultAnnotatedErrorinterface types the.responseannotation set by the secure-channel layer.
_ping_servernow checks for this annotation before deciding whether to reconnect:- Recoverable
ServiceFault→ emitkeepalive_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
constructedStatusCodeinstance are still recognised.
- Recoverable
-
Exponential backoff on consecutive ServiceFaults
TrackconsecutiveFailuresonClientSessionKeepAliveManager. When_ping_serverreturns
an explicit backoff value (greater thancheckInterval),ping_serveruses it directly as the next scheduling
interval. Consecutive recoverableServiceFaults now back off as2x, 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_responsenow usessocket.destroy()instead ofsocket.end()and nulls out_socketbefore invoking the
callback. The file descriptor is freed immediately rather than after the callback chain has completed. New regression test
TCS-10intest_client_tcp_transport.
Address space
- Misc address-space correctness fixes
address_space.ts: fixEvenType→EventTypetypo; log awarningLogwhensourceNodecannot be resolved
(instead of silently emitting an emptySourceName); alignconstructEventDatasignature withIAddressSpace
(Record<string, unknown>) while keeping internalRaiseEventDatatyping.base_node_private.ts:_removenow 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_childrennow falls back toaddressSpace.findObjectType(reference.nodeId)when
reference.nodeis unresolved.ua_object_impl.ts: tidyraiseEventerror messages (separators).
🧹 Refactor / chore
-
refactor(event-data): encapsulate event data source
Drop the public$eventDataSourcefield onIEventData/EventDataand replace it with agetEventDataSource()
accessor. Internal state (__values,__nodeIdToNode,__pathToNodeId,__nodeIdToFullPath) moves into a private
#cachefield so callers can no longer reach intoEventDatainternals. TightensconstructEventData(...)
typing fromanytoRecord<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— useeventData.getEventDataSource()instead. -
Biome conformance cleanup (across
address-spaceand beyond)- Replace non-null assertions with optional chaining.
- Switch
Object.prototype.hasOwnProperty/isFinite/isNaNtoObject.hasOwn/
Number.isFinite/Number.isNaN. - Convert string concatenation to template literals.
- Switch
fs/pathimports to thenode:protocol in test helpers. - Reorder type-only and side-effect imports.
- Sort exports alphabetically in
test_helpers/index. - Bump
Opc.Ua.Types.xsdmodel metadata to 1.05.06 / 2025-11-08.
-
Test cleanup
-
Sort imports, drop unused locals, prefix intentionally-unusedvariables with
_, and switchmodeler/test_promoteToMandatory
from rawdescribetodescribeWithLeakDetector. 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 toeventData.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 nowRecord<string, unknown>.
👬🏽 Contributors
- special thanks to @Velluso for reporting keep alive issues.
v2.169.0
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 properlyawait-ed, eliminating file-watcher cleanup races and spurioussetTimeoutleak warnings ([d7373c9]). - Dependency updates:
node-opcua-pkiversion 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.pemcontains 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
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
channelSecuredevent for post-handshake notifications [af7ef34].
🐛Bug Fixes
- Core: Prevented infinite recursion in
send_responsewhen 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
ApplyChangesresponse is sent [8484b98]. - Address Space: Fixed
address-space-baseimports 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
asynclibrary [3269940] andlodash[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
👬🏽 Contributors
- Special thanks to @RatishKashyap of #1490 for their detailed report
What's Changed
- Refactor server by @erossignon in #1491
Full Changelog: v2.167.0...v2.168.0
🚀 Release Notes — v2.167.0
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
ISessionContextthroughApplyChangesevent chain — allows consumers to identify which session triggered a configuration change [4033f97]
🐛 Bug Fixes
- server: Harden
register_server_manageragainst 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 --noEmiterrors 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-cryptodependencies [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
UserNameIdentityTokenpassword extraction — hardens against replay attacks [c6b0573]
🧹 Chores
⚠️ Security
-
Nonce verification for password tokens [c6b0573]: The server now verifies that the nonce embedded in
UserNameIdentityTokenmatches the nonce issued duringCreateSession. 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)
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
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);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();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.
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 | nullThese 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:
Datevalues reverted to1601-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).
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...
🚀 v2.164.2
Release Notes (v2.163.2 -> HEAD)
🚀 Features & Improvements
- ServerConfiguration: Architectural overhaul of
PushCertificateManagerServerImpl, extracting file transaction and certificate validation logic. Refactored to utilize theOPCUACertificateManagerAPI. ([f594e65], [52c4057], [2099377], [09d79f2], [cd7f612]) - Resource Management: Improved resource leak detection with
mem_leak_detectorand increased timer proxy robustness. Prevented potential stdio deadlocks, file descriptor leaks, and memory leaks inTCP_transportsocket dispose. ([7b96b9d], [ae162d3], [de0e91f], [46eeccf]) - Address Space: Added missing
dispose()toIContinuationPointManagerimplementations. ([00f0076]) - Tooling: Replaced deprecated
ts-nodewithtsxacross the monorepo to enhance compatibility and performance. ([f137752], [00fee24])
🐛 Bug Fixes
- Client / Publish Engine: Handled
BadSecureChannelIdInvalidcorrectly 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/Variantmismatch, corrected bitfield encoding, and improved subtype validation. ([1ec0a39]) - Alarms & Conditions: Prevented
enabledStatemissing properties during reconstruction and updated Certificate Expiry to usesetTimeoutinstead ofsetInterval. ([e350e2e], [e40ef26]) - Historical Access: Ensured
startOfOnlineArchivegracefully 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 deprecatedBuffer()constructor. ([ec1aca8], [4508fc8], [0e01525])
🛠️ Refactoring & Chores
- Dependencies: Bumped
@ster5/global-mutexto^3.1.2,node-opcua-pkiup to6.7.3, and updatednode-opcua-cryptoto^5.0.0. Adapted client and server codebases to the newnode-opcua-pki@6API. ([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
mkdirpandrimrafdependency usage. Replacedistanbul ignorewithc8 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
- @AndreasHeine : improvement on push certificate management [2099377] [09d79f2]
🚀 v2.163.0
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
🚀 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
- @AlexanderThees made their first contribution in #1473
Full Changelog: v2.161.0...v2.162.0
historyRead with ExtensionObject
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.