npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opcjs-client

v0.1.14

Published

A client for OPC UA communication.

Readme

opcjs-client

An OPC UA client library for TypeScript targeting the browser and Node.js, built on top of opcjs-base.

Installation

npm install opcjs-client opcjs-base

Quick Start

import { Client, ConfigurationClient, UserIdentity } from 'opcjs-client'
import { NodeId } from 'opcjs-base'

const config = ConfigurationClient.getSimple('MyApp', 'MyCompany')
const client = new Client('opc.tcp://localhost:4840', UserIdentity.newAnonymous(), config)

await client.connect()

// Read a node value
const results = await client.read([NodeId.newNumeric(0, 2258)]) // CurrentTime
console.log(results[0].value)

await client.disconnect()

API

new Client(endpointUrl, identity, configuration)

Creates a new client instance. Does not connect until connect() is called.

| Parameter | Type | Description | |-----------|------|-------------| | endpointUrl | string | OPC UA server endpoint (e.g. opc.tcp://host:4840) | | identity | UserIdentity | Credentials used for ActivateSession | | configuration | ConfigurationClient | Application description, encoder/decoder, and security settings |

client.connect(): Promise<void>

Opens the WebSocket transport, establishes a TCP/SecureChannel, creates an OPC UA session, and starts the keep-alive timer.

Reconnects automatically on channel drops (Session Auto Reconnect, OPC UA Part 4 §5.7.1):

  1. Attempts ActivateSession on the new channel to reuse the existing session.
  2. Falls back to a full CreateSession + ActivateSession if reactivation fails.

client.disconnect(): Promise<void>

Sends CloseSession (with deleteSubscriptions=true), closes the SecureChannel, and shuts down the WebSocket transport.

client.read(ids, options?): Promise<ReadValueResult[]>

Reads the Value attribute of one or more nodes.

const [result] = await client.read([NodeId.newNumeric(0, 2258)])
// result.value          — the read value
// result.statusCode     — OPC UA StatusCode
// result.diagnosticInfo — populated when returnDiagnostics > 0

client.getSelectionList(nodeId): Promise<SelectionList | null>

Reads SelectionListType metadata (OPC UA Part 5 §7.18) from a variable and exposes it to application code.

The method reads the variable's HasProperty references for:

  • Selections (mandatory)
  • SelectionDescriptions (optional)
  • RestrictToList (optional)

It returns null when the variable does not expose a Selections property.

const list = await client.getSelectionList(nodeId)
if (list) {
  console.log(list.selections)
  console.log(list.selectionDescriptions.map(d => d.text))
  console.log('restrictToList:', list.restrictToList)
}

client.browse(nodeId, recursive?, options?): Promise<BrowseNodeResult[]>

Browses the HierarchicalReferences of a node. Set recursive to true to traverse the full sub-tree.

Continuation points are handled automatically: all pages are fetched and merged before the promise resolves.

client.callMethod(objectId, methodId, inputArguments?, options?): Promise<CallMethodResult>

Calls an OPC UA method.

import { CallMethodArgument } from 'opcjs-client'

const result = await client.callMethod(
  NodeId.newNumeric(0, 1000),  // Object that owns the method
  NodeId.newNumeric(0, 1001),  // Method node
  [42, 'hello'] as CallMethodArgument[],
)
// result.values         — output argument values
// result.statusCode     — OPC UA StatusCode
// result.diagnosticInfo — populated when returnDiagnostics > 0

client.subscribe(ids, callback, options?): Promise<void>

Creates an OPC UA subscription and monitored items, then starts the Publish loop.

await client.subscribe(
  [NodeId.newNumeric(0, 2258)],
  (notifications) => {
    for (const { id, value } of notifications) {
      console.log(id, value)
    }
  },
  { requestedPublishingInterval: 1000 },
)

SubscriptionOptions (all optional, server may revise):

| Field | Default | Description | |-------|---------|-------------| | requestedPublishingInterval | 2000 ms | Publishing interval | | requestedLifetimeCount | 360000 | Subscription lifetime in publishing intervals | | requestedMaxKeepAliveCount | 60000 | Keep-alive count | | maxNotificationsPerPublish | 200 | 0 = no limit | | priority | 1 | Priority relative to other subscriptions | | samplingInterval | -1 (use publishing interval) | Monitored item sampling interval | | queueSize | server default | Per-item notification queue |

Authentication

// Anonymous (default)
const identity = UserIdentity.newAnonymous()

// Username / password
const identity = UserIdentity.newWithUserName('user', 'pass')

// Issued token (e.g. OAuth / JWT)
const identity = UserIdentity.newWithIssuerToken(async (config) => {
  return { tokenData: new TextEncoder().encode(await fetchJwt(config)) }
})

Security Configuration

Attach a SecurityConfiguration to the ConfigurationClient to restrict which security options are accepted:

import { UserTokenTypeEnum } from 'opcjs-base'

const config = ConfigurationClient.getSimple('MyApp', 'MyCompany')
config.securityConfiguration = {
  // Require authentication — reject anonymous connections
  allowedUserTokenTypes: [UserTokenTypeEnum.UserName],
  // Require an encrypted channel (throws until non-None policies are supported)
  allowSecurityPolicyNone: false,
}

| Field | Default | Description | |-------|---------|-------------| | allowedUserTokenTypes | all types | Token types the client will accept | | allowSecurityPolicyNone | true | Allow unencrypted SecurityPolicy None channels | | messageSecurityMode | any | Required MessageSecurityMode | | trustedCAs | — | DER-encoded trusted CA certificates (reserved for future use) | | unknownCertificatePolicy | — | 'reject' or 'trust' for unverifiable server certificates (reserved for future use) |

Security note: allowSecurityPolicyNone: true (the default) allows cleartext communication. Set it to false once non-None security policies are available in this client implementation.

Request Options

All service methods (read, callMethod, browse) accept an optional RequestOptions object as their last parameter.

| Field | Type | Default | Description | |-------|------|---------|-------------| | returnDiagnostics | number | 0 | Bitmask of diagnostic fields the server should populate (OPC UA Part 4, §7.15). Use ReturnDiagnosticsMask constants to compose the value. |

ReturnDiagnosticsMask constants

import { ReturnDiagnosticsMask } from 'opcjs-client'

| Constant | Value | Description | |----------|-------|-------------| | ServiceLevel | 0x001f | All service-level fields | | OperationLevel | 0x03e0 | All operation-level fields | | All | 0x03ff | All diagnostic fields | | ServiceSymbolicId | 0x0001 | Service symbolic identifier | | ServiceLocalizedText | 0x0002 | Service localised text | | ServiceAdditionalInfo | 0x0004 | Service additional info | | ServiceInnerStatusCode | 0x0008 | Service inner status code | | ServiceInnerDiagnostics | 0x0010 | Service inner diagnostic info | | OperationSymbolicId | 0x0020 | Operation symbolic identifier | | OperationLocalizedText | 0x0040 | Operation localised text | | OperationAdditionalInfo | 0x0080 | Operation additional info | | OperationInnerStatusCode | 0x0100 | Operation inner status code | | OperationInnerDiagnostics | 0x0200 | Operation inner diagnostic info |

Example

import { ReturnDiagnosticsMask } from 'opcjs-client'

const [result] = await client.read(
  [NodeId.newNumeric(0, 2258)],
  { returnDiagnostics: ReturnDiagnosticsMask.All },
)
if (result.diagnosticInfo) {
  console.log('additional info:', result.diagnosticInfo.additionalInfo)
}

const callResult = await client.callMethod(
  objectId,
  methodId,
  [],
  { returnDiagnostics: ReturnDiagnosticsMask.OperationLevel },
)

When returnDiagnostics is 0 (the default) the diagnosticInfo field on each result is undefined.

Core Capacities

This section satisfies the Documentation – Core Capacities conformance unit (OPC UA Core 2022 Client Facet, §A).

| Capacity | Value | Notes | |----------|-------|-------| | SecureChannels per Client instance | 1 | A single channel is opened on connect() and renewed automatically at 75 % of token lifetime | | Sessions per Client instance | 1 | One OPC UA session per Client; create multiple Client instances for multiple sessions | | Subscriptions per session | 1 | More than one subscription per Client is not yet implemented | | Monitored items per subscription | Unlimited (server-limited) | All requested items are batched into a single CreateMonitoredItems call | | Continuation points | Server-determined | browse() follows all continuation points automatically via BrowseNext | | Max message size | Server-determined | Negotiated during Hello/Ack (UA-TCP handshake) | | Request handles | Monotonically increasing uint32 | Managed by serviceBase.ts; wraps at 2³²−1 |

Time Synchronisation

This client relies on the OS system clock for all timestamps.

On Linux this is typically kept accurate by systemd-timesyncd (SNTP) or a full NTP daemon (ntpd, chrony). On Windows, the W32tm service provides equivalent synchronisation. On macOS, timed handles clock sync.

This satisfies the Time Sync – OS based support optional conformance unit, which in turn satisfies the Time Sync – Support required conformance unit from the OPC UA Core 2022 Client Facet.

No application-level time-sync mechanism (IEEE 1588 PTP, IEEE 802.1AS, UA-based time sync) is implemented.

Conformance Status

| Conformance Unit | Status | |-----------------|--------| | Address Space Client NodeId IdTypes | ✅ Done | | Base Info Client Currency | ✅ Done (see below) | | Base Info Client Selection List | ✅ Done (client.getSelectionList) | | Documentation – Core Capacities | ✅ Done (see above) | | Base Services Client Diagnostics | ✅ Done (RequestOptions.returnDiagnostics, ReturnDiagnosticsMask) | | Security Administration | ✅ Done (SecurityConfiguration) | | Session Client Auto Reconnect | ✅ Done | | Session Client Base (CloseSession) | ✅ Done | | Session Client General Service Behaviour | ✅ Done | | Session Client KeepAlive | ✅ Done (dedicated timer + Publish loop) | | Protocol UA TCP | ✅ Done | | UA Binary Encoding | ✅ Done | | UA Secure Conversation | ✅ Done | | SecurityPolicy None | ✅ Done | | Time Sync – Support (via OS) | ✅ Satisfied | | Security User Anonymous Client | ✅ Done |

Currency Values — CurrencyUnitType

DataVariables whose DataType is CurrencyUnitType (ns=0; i=23498, OPC UA Part 5 §12) are automatically decoded to a typed object instead of a raw ExtensionObject.

import { CurrencyUnitType } from 'opcjs-base'
import { NodeId } from 'opcjs-base'

const [result] = await client.read([NodeId.newNumeric(0, /* currency node */ 1234)])
if (result.value instanceof CurrencyUnitType) {
  console.log(result.value.alphabeticCode) // e.g. "EUR"
  console.log(result.value.numericCode)    // e.g. 978
  console.log(result.value.exponent)       // e.g. -2  (cent-denominated)
  console.log(result.value.currency.text)  // e.g. "Euro"
}

The fields follow ISO 4217:

| Field | OPC UA type | Description | |-------|-------------|-------------| | numericCode | Int16 | ISO 4217 numeric code (e.g. 978 = EUR) | | exponent | SByte | Decimal-place shift (e.g. −2 for cent currencies, 0 for JPY) | | alphabeticCode | String | Three-letter ISO 4217 code (e.g. "EUR") | | currency | LocalizedText | Human-readable currency name |

License

MIT