Skip to content

v2.179.0: Zero Errors, Zero Warnings

Choose a tag to compare

@erossignon erossignon released this 28 Aug 08:00
· 488 commits to master since this release

node-opcua 2.179.0

Compare: v2.178.0...v2.179.0

A robustness and performance release. The client's keep-alive and transaction handling no longer mistake a slow link for a dead server; the encoding path is measurably cheaper; and a family of lifecycle races in the server and address space was found and fixed after the test suite was moved to a parallel runner. Also a full biome pass across the monorepo (0 errors / 0 warnings) and a new CI gate for fixed test ports.

🚀 Features

BinaryStream

  • Optional growable mode: the stream can now extend its own buffer instead of requiring the final size up front, which is what lets the extension-object encoder backpatch rather than pre-size. [3cc5ad7]

🐛 Fixes

Client — connection liveness

A connected client could conclude a healthy server had gone away, or quietly lose a request that was still in flight. These are one theme, fixed together:

  • client: keep-alive must not treat a timed-out transaction as contact with the server — a slow answer was being read as a dead one. [d10f2aa]
  • client: a ServiceFault is genuine server contact; treating it as silence could tear down a working session. [cce2c1a]
  • client: anchor session lifetime on the last answer actually received. [9cbe6e9]
  • client: subscription lifetime must not count unanswered publishes. [1f4fb66]
  • client: hold transactions while the connection is down, and always resolve them — previously a caller could wait forever. [fc69569]
  • client: stop orphaning a transaction that hits BadSessionIdInvalid. [114785c]
  • client: the keep-alive scheduler no longer delays and wedges itself. [910bc68]
  • secure-channel: deliver an abandoned request like any other ServiceFault, so the caller gets an answer rather than nothing. [65d3548]

Encoding / dataTypes

  • dynamic-extension-object: pair each DataType with its own description. The 1.03 loader zipped two arrays by index, but abstract types are skipped, so after the first skip the pairing drifted — encodings were attached to the wrong description and several standard classes (FetchResultDataType, TransferResultErrorDataType, ParameterResultDataType, TransferResultDataDataType) were never registered at all. A client needing one of them failed far from the cause. The assert that would have caught this had been commented out with "in some circumstances like Euromap, this assert fails" — it was right to fail, and is restored. [cc88e24]
  • dynamic-extension-object: report unregistered dataTypes once, by name, instead of scattered log lines that nobody reads. [2ac9951]
  • client-dynamic-extension-object: restore the null-NodeId fallback for enumeration fields. [f1bbad1]
  • variant: Variant.clone is a true deep copy — the shallow copy leaked shared state between values. [66a4f01] plus the follow-up repair of what that exposed. [9e21a60]

Server

  • server: suspendConnection now waits for the listener to be released. It called back while close() was still in flight, so restoreConnection could re-listen on a port the old handle still held — an EADDRINUSE out of resumeEndPoints, hit during certificate rotation. [f3154ec]
  • server: createSession refuses with BadServerHalted once the engine is shutting down. A request already in flight could land after the address space was disposed and surface as Cannot read properties of null (reading 'findDataType') from a promise nobody awaited — taking the process down rather than failing one request. [f3154ec]
  • server: scale a channel's listener ceiling with its session count. [c647f70]
  • server: default writeAttribute statusCode to Good instead of rejecting. [00534f6]
  • server: correct createSubscriptionDiagnosticsArray browseName and options [be070ca], and restore the explicit namespace-0 browseName for SubscriptionDiagnosticsArray. [a459eaf]

Address space

  • address-space: UAVariable.readValueAsync must honour isAccessRestricted. [8f13f6a]
  • address-space: stop asking massively-used types to drop absent references. _propagate_ref never installs back references for HasTypeDefinition / HasModellingRule — "because there are too many" — but removal did not mirror that, so detaching any node produced Cannot find reference to remove. 101 of them in a single CI run. [0f43a1a]
  • role-set: rebind Identities to the store so bindRoleSet cannot shadow it. [08fb5a9]

⚡ Performance

  • secure-channel: encode each message once instead of twice. [31818de]
  • data-value: DataValue.clone no longer copies its payload twice. [194cf15]
  • extension-object: backpatch the body length instead of pre-sizing the buffer. [168f87d]
  • variant: memoise the built-in codec per numeric DataType [83ade33]; index the typed-array helper table numerically [ac06826].
  • data-value, variant: take the cheap constructor branch for undefined. [d6fb939]
  • binary-stream: memcpy in writeArrayBuffer rather than a byte loop. [2255ec3]
  • server: hold the monitored-item registries in Maps [21559ce]; stop the notification path re-cloning the sampled value [f16bfea].

🧹 Chore / CI / internal

Most of the fixes above were found by this work, which is the reason it is worth listing.

  • ci: the test suite now runs in parallel, one worker per file. This removed the idle-machine slack that had been hiding the lifecycle races fixed above. [ci: parallelise the test jobs]
  • test: per-package pnpm -r run test works again — it had been broken (the root .mocharc.js required ts-node, which is not installed anywhere), and no CI job read those config files. Repairing it revealed 22 test files (~172 tests) that no runner had ever collected, plus two dependencies missing from a manifest. [217a89d] [177e3b0] [fd5c4ee] [0dd52a7]
  • test-runner: collect numbered and repro_ specs, not only test_ — 520 → 542 files. [7088422]
  • test(mocharc): every package's mocha configuration on one shape, enforced by a new check-mocharc tool. Mocha does not merge configs, so a package wanting one different setting had to restate the loader list; 24 of them carried a relative path that only worked by accident of directory depth. [ccc6e2a]
  • tools: new check-test-ports scanner, gating CI — collisions, ports pinned inside the ephemeral range, ports derived as port + 1 (bound but written nowhere), and ports belonging to OPC UA itself (4840) or to services a developer is likely running (3000, 5432, macOS AirPlay on 5000). It found two live collisions nobody had hit yet. [45662a0] [397cbb0] [e6e7e11]
  • test(transport): several tests asserted event sequences under a comment admitting the order varies by Node version, gated by fixed setTimeouts. They now assert what is causally guaranteed and wait for the events themselves. [4ecaf82] [da436ed] [8069189] [d4268e2] [cb00093]
  • chore: full biome pass across the monorepo — 0 errors, 0 warnings — plus a CI lint gate. [c02a076] [95bbc44]
  • ci: GitHub Actions moved off the deprecated node20 runtime (checkout v4→v7, setup-node v4→v7, pnpm/action-setup v4→v6, upload-artifact v4→v7). [80c6613] [709042e]
  • leak-detector: stop a reported leak from hanging the worker. [8fd5090]
  • tools: ignore brackets inside strings when bounding a statement [cdb0f0d]; register check-debug-log in the pnpm lockfile [6abc2d7].

🙏 Contributors

Thanks to everyone who contributed to this release.

The Sterfive Team