opcjs-client 0.1.40-alpha → 0.1.41-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { ISecureChannel, RequestHeader, NodeId, EndpointDescription, UserIdentityToken, Configuration, UserTokenTypeEnum, MessageSecurityModeEnum, ILoggerFactory, Encoder, Decoder, ExpandedNodeId, QualifiedName, LocalizedText, NodeClassEnum, UaPrimitive, XmlElement, ExtensionObject, DataValue, DiagnosticInfo } from 'opcjs-base';
1
+ import { ISecureChannel, RequestHeader, NodeId, EndpointDescription, UserIdentityToken, Configuration, UserTokenTypeEnum, DiagnosticInfo, MessageSecurityModeEnum, ILoggerFactory, Encoder, Decoder, ExpandedNodeId, QualifiedName, LocalizedText, NodeClassEnum, UaPrimitive, XmlElement, ExtensionObject, DataValue } from 'opcjs-base';
2
2
 
3
3
  declare abstract class ServiceBase {
4
4
  private authToken;
@@ -14,7 +14,14 @@ declare abstract class ServiceBase {
14
14
  * @param context - Short description used in the error message (e.g. "ReadRequest").
15
15
  */
16
16
  protected checkServiceResult(result: number | undefined, context: string): void;
17
- protected createRequestHeader(): RequestHeader;
17
+ /**
18
+ * Builds a RequestHeader for an outgoing service request.
19
+ *
20
+ * @param returnDiagnostics - Bitmask of diagnostic fields to request from the
21
+ * server (OPC UA Part 4, §7.15). Use {@link ReturnDiagnosticsMask} constants
22
+ * to compose the value. Default `0` = no diagnostics.
23
+ */
24
+ protected createRequestHeader(returnDiagnostics?: number, preAllocatedHandle?: number): RequestHeader;
18
25
  constructor(authToken: NodeId, secureChannel: ISecureChannel);
19
26
  }
20
27
 
@@ -23,9 +30,16 @@ declare class SessionService extends ServiceBase {
23
30
  private logger;
24
31
  /**
25
32
  * Creates a new session on the server (OPC UA Part 4, Section 5.7.2).
33
+ *
34
+ * @param clientCertificate - Optional DER-encoded client certificate to include in
35
+ * the request. Pass `null` (default) for SecurityPolicy None without a cert.
36
+ * When the server rejects a `null`-cert request with a certificate-related status
37
+ * code, the caller should retry with a `Uint8Array` certificate (OPC UA 1.0
38
+ * fallback — see `CertificateRequiredError`).
26
39
  * @returns The session ID, authentication token, and selected server endpoint.
40
+ * @throws {CertificateRequiredError} when the server demands a client certificate.
27
41
  */
28
- createSession(): Promise<{
42
+ createSession(clientCertificate?: Uint8Array | null): Promise<{
29
43
  sessionId: number;
30
44
  authToken: NodeId;
31
45
  endpoint: EndpointDescription;
@@ -35,6 +49,20 @@ declare class SessionService extends ServiceBase {
35
49
  * @param identityToken - User identity token (anonymous, username/password, certificate, or issued token).
36
50
  */
37
51
  activateSession(identityToken: UserIdentityToken): Promise<void>;
52
+ /**
53
+ * Sends a CancelRequest to the server asking it to abandon the pending
54
+ * service request identified by `requestHandle` (OPC UA Part 4, Section 5.7.5).
55
+ *
56
+ * The server makes a best-effort attempt to cancel matching requests.
57
+ * Cancelled requests complete with a status of `BadRequestCancelledByClient`.
58
+ *
59
+ * @param requestHandle - The `requestHeader.requestHandle` value of the pending
60
+ * request to cancel. Pass `0` to attempt to cancel all outstanding requests
61
+ * (server behaviour for handle 0 is implementation-specific).
62
+ * @returns The number of pending requests that were actually cancelled
63
+ * (`CancelResponse.cancelCount`).
64
+ */
65
+ cancel(requestHandle: number): Promise<number>;
38
66
  /**
39
67
  * Closes the current session on the server (OPC UA Part 4, Section 5.7.4).
40
68
  * @param deleteSubscriptions - When true the server deletes all Subscriptions
@@ -93,6 +121,20 @@ declare class Session {
93
121
  getAuthToken(): NodeId;
94
122
  getSessionId(): number;
95
123
  getEndpoint(): EndpointDescription;
124
+ /**
125
+ * Switches the active user identity for this session by calling ActivateSession with
126
+ * a new identity token (OPC UA Part 4, Section 5.7.3 — Session Client Impersonate
127
+ * conformance unit).
128
+ *
129
+ * The server re-evaluates authorisation for the session under the new identity.
130
+ * All existing Subscriptions and MonitoredItems are preserved; only the security
131
+ * context changes.
132
+ *
133
+ * @param identity - The new user identity to apply to the session.
134
+ * @throws When the server returns a non-Good ServiceResult (e.g. `BadIdentityTokenRejected`
135
+ * or `BadUserAccessDenied`).
136
+ */
137
+ impersonate(identity: UserIdentity): Promise<void>;
96
138
  /**
97
139
  * Closes the session on the server (OPC UA Part 4, Section 5.7.4).
98
140
  * @param deleteSubscriptions - When true the server deletes all Subscriptions
@@ -105,7 +147,11 @@ declare class Session {
105
147
  declare class ReadValueResult {
106
148
  value: unknown;
107
149
  statusCode: number;
108
- constructor(value: unknown, statusCode: number);
150
+ /** Diagnostic info returned by the server when `returnDiagnostics` was set in the request options. */
151
+ diagnosticInfo?: DiagnosticInfo | undefined;
152
+ constructor(value: unknown, statusCode: number,
153
+ /** Diagnostic info returned by the server when `returnDiagnostics` was set in the request options. */
154
+ diagnosticInfo?: DiagnosticInfo | undefined);
109
155
  }
110
156
 
111
157
  /** Options for creating a subscription. All fields are optional; server will revise requested values. */
@@ -209,6 +255,20 @@ type SecurityConfiguration = {
209
255
  * implemented alongside non-None security policies.
210
256
  */
211
257
  unknownCertificatePolicy?: UnknownCertificatePolicy;
258
+ /**
259
+ * DER-encoded X.509 ApplicationInstanceCertificate for this client.
260
+ *
261
+ * When set, this certificate is used in a OPC UA 1.0 compatibility fallback:
262
+ * if `CreateSession` with no client certificate is rejected by the server with
263
+ * a certificate-related status code (`BadCertificateInvalid`,
264
+ * `BadSecurityChecksFailed`, or `BadNoValidCertificates`), the `CreateSession`
265
+ * is automatically retried with this certificate in the `clientCertificate`
266
+ * field (OPC UA Part 4, SecurityPolicy None – CreateSession/ActivateSession 1.0
267
+ * optional conformance unit).
268
+ *
269
+ * Without this field the fallback is disabled and the error propagates as-is.
270
+ */
271
+ applicationInstanceCertificate?: Uint8Array;
212
272
  };
213
273
 
214
274
  declare class ConfigurationClient extends Configuration {
@@ -220,6 +280,26 @@ declare class ConfigurationClient extends Configuration {
220
280
  * @see SecurityConfiguration
221
281
  */
222
282
  securityConfiguration?: SecurityConfiguration;
283
+ /**
284
+ * How long to wait (ms) before attempting a reconnect after a server-shutdown
285
+ * is detected via `ServerStatus/State = Shutdown` or a subscription
286
+ * `StatusChangeNotification` with `BadShutdown` / `BadServerHalted`.
287
+ *
288
+ * Gives the server process time to exit fully before the client tries to
289
+ * re-connect. Defaults to 5 000 ms.
290
+ */
291
+ shutdownReconnectDelayMs: number;
292
+ /**
293
+ * Minimum reconnect delay in milliseconds used when
294
+ * `Server/ServerStatus/EstimatedReturnTime` is already in the past (the server
295
+ * should already be available again).
296
+ *
297
+ * Also acts as the lower bound for the ERT-derived delay, ensuring the client
298
+ * always waits at least this long before retrying.
299
+ *
300
+ * Defaults to 1 000 ms.
301
+ */
302
+ minReconnectDelayMs: number;
223
303
  static getSimple(name: string, company: string, loggerFactory?: ILoggerFactory): ConfigurationClient;
224
304
  constructor(applicationName: string, applicationUri: string, productName: string, productUri: string, encoder: Encoder, decoder: Decoder, loggerFactory: ILoggerFactory);
225
305
  }
@@ -227,7 +307,11 @@ declare class ConfigurationClient extends Configuration {
227
307
  declare class CallMethodResult {
228
308
  values: unknown[];
229
309
  statusCode: number;
230
- constructor(values: unknown[], statusCode: number);
310
+ /** Diagnostic info returned by the server when `returnDiagnostics` was set in the request options. */
311
+ diagnosticInfo?: DiagnosticInfo | undefined;
312
+ constructor(values: unknown[], statusCode: number,
313
+ /** Diagnostic info returned by the server when `returnDiagnostics` was set in the request options. */
314
+ diagnosticInfo?: DiagnosticInfo | undefined);
231
315
  }
232
316
 
233
317
  declare class BrowseNodeResult {
@@ -259,6 +343,165 @@ type ScalarCallMethodArgument = UaPrimitive | NodeId | ExpandedNodeId | Qualifie
259
343
  */
260
344
  type CallMethodArgument = ScalarCallMethodArgument | ScalarCallMethodArgument[];
261
345
 
346
+ /**
347
+ * Bitmask constants for the `returnDiagnostics` field in the OPC UA RequestHeader
348
+ * (OPC UA Part 4, §7.15 — DiagnosticsMask).
349
+ *
350
+ * Combine values with bitwise OR to request multiple diagnostic fields.
351
+ *
352
+ * @example
353
+ * ```ts
354
+ * import { ReturnDiagnosticsMask, RequestOptions } from 'opcjs-client'
355
+ *
356
+ * const options: RequestOptions = {
357
+ * returnDiagnostics: ReturnDiagnosticsMask.ServiceLevel | ReturnDiagnosticsMask.OperationLevel,
358
+ * }
359
+ * ```
360
+ */
361
+ declare const ReturnDiagnosticsMask: {
362
+ /** All service-level diagnostic fields. */
363
+ readonly ServiceLevel: 31;
364
+ /** All operation-level diagnostic fields. */
365
+ readonly OperationLevel: 992;
366
+ /** All diagnostic fields (service level + operation level). */
367
+ readonly All: 1023;
368
+ /** Service-level: index to SymbolicId in the server string table. */
369
+ readonly ServiceSymbolicId: 1;
370
+ /** Service-level: index to LocalizedText in the server string table. */
371
+ readonly ServiceLocalizedText: 2;
372
+ /** Service-level: additional info string. */
373
+ readonly ServiceAdditionalInfo: 4;
374
+ /** Service-level: inner status code. */
375
+ readonly ServiceInnerStatusCode: 8;
376
+ /** Service-level: inner diagnostic info. */
377
+ readonly ServiceInnerDiagnostics: 16;
378
+ /** Operation-level: index to SymbolicId in the server string table. */
379
+ readonly OperationSymbolicId: 32;
380
+ /** Operation-level: index to LocalizedText in the server string table. */
381
+ readonly OperationLocalizedText: 64;
382
+ /** Operation-level: additional info string. */
383
+ readonly OperationAdditionalInfo: 128;
384
+ /** Operation-level: inner status code. */
385
+ readonly OperationInnerStatusCode: 256;
386
+ /** Operation-level: inner diagnostic info. */
387
+ readonly OperationInnerDiagnostics: 512;
388
+ };
389
+ /**
390
+ * Options accepted by all `Client` service calls.
391
+ *
392
+ * Each field is optional; omitting it keeps the existing default behaviour.
393
+ */
394
+ type RequestOptions = {
395
+ /**
396
+ * Bitmask specifying which diagnostic fields the server should populate in
397
+ * the `diagnosticInfo` fields of the response (OPC UA Part 4, §7.15).
398
+ *
399
+ * Use {@link ReturnDiagnosticsMask} constants to compose the value:
400
+ * ```ts
401
+ * returnDiagnostics: ReturnDiagnosticsMask.All
402
+ * ```
403
+ *
404
+ * Default: `0` — no diagnostics returned.
405
+ */
406
+ returnDiagnostics?: number;
407
+ };
408
+
409
+ /**
410
+ * Tracks the OPC UA NamespaceArray for a session (OPC UA Part 4, Section 5.7.1 —
411
+ * Session Client Renew NodeIds conformance unit).
412
+ *
413
+ * The NamespaceArray maps namespace indices (used inside NodeIds) to stable namespace
414
+ * URIs. Because the server may assign different indices to the same URI across
415
+ * sessions (e.g. after a server restart), clients that cache NodeIds must remap
416
+ * the namespace index whenever the table changes.
417
+ *
418
+ * Namespace index `0` is always the OPC UA base namespace
419
+ * (`http://opcfoundation.org/UA/`) and is guaranteed never to change by the spec.
420
+ *
421
+ * @example
422
+ * ```ts
423
+ * const oldTable = new NamespaceTable(['http://opcfoundation.org/UA/', 'urn:my-server:model'])
424
+ * // After reconnect the server puts the model namespace at index 2:
425
+ * const newTable = new NamespaceTable(['http://opcfoundation.org/UA/', 'urn:unrelated', 'urn:my-server:model'])
426
+ * const remapped = oldTable.remapNodeId(NodeId.newNumeric(1, 1001), newTable)
427
+ * // remapped === NodeId(2, 1001)
428
+ * ```
429
+ */
430
+ declare class NamespaceTable {
431
+ private readonly uris;
432
+ constructor(uris?: string[]);
433
+ /** Returns the namespace URI at the given index, or `undefined` if out of range. */
434
+ getUri(index: number): string | undefined;
435
+ /** Returns the namespace index for the given URI, or `undefined` if not found. */
436
+ getIndex(uri: string): number | undefined;
437
+ /** Returns the full ordered array of namespace URIs. */
438
+ getUris(): readonly string[];
439
+ /** Returns `true` when both tables contain the same URIs in the same order. */
440
+ equals(other: NamespaceTable): boolean;
441
+ /**
442
+ * Remaps the namespace index of `nodeId` from this table to the equivalent
443
+ * index in `newTable` by matching namespace URIs.
444
+ *
445
+ * - Namespace index `0` (OPC UA base namespace) is always returned unchanged.
446
+ * - Returns the **same** `NodeId` instance when the index has not changed.
447
+ * - Returns a **new** `NodeId` instance with the updated index when remapping
448
+ * is required.
449
+ *
450
+ * @throws {Error} When the namespace URI at `nodeId.namespace` is not present
451
+ * in this (old) table or when the URI is not present in `newTable`.
452
+ */
453
+ remapNodeId(nodeId: NodeId, newTable: NamespaceTable): NodeId;
454
+ }
455
+
456
+ /**
457
+ * Result of reading a SelectionListType variable's metadata
458
+ * (OPC UA Part 5, §7.18 — Base Info Selection List conformance unit).
459
+ *
460
+ * Represents the set of permitted values and their human-readable descriptions
461
+ * that the server exposes for a variable with a `SelectionListType` TypeDefinition.
462
+ *
463
+ * @example
464
+ * ```ts
465
+ * const list = await client.getSelectionList(nodeId)
466
+ * if (list) {
467
+ * console.log('Permitted values:', list.selections)
468
+ * list.selectionDescriptions.forEach((desc, i) =>
469
+ * console.log(` [${i}] ${desc.text} →`, list.selections[i])
470
+ * )
471
+ * if (list.restrictToList) {
472
+ * console.log('Value must be one of the listed selections.')
473
+ * }
474
+ * }
475
+ * ```
476
+ */
477
+ type SelectionList = {
478
+ /** The NodeId of the queried variable. */
479
+ readonly nodeId: NodeId;
480
+ /**
481
+ * Array of permitted values for the variable
482
+ * (SelectionListType.Selections mandatory property, OPC 10000-5 §7.18).
483
+ *
484
+ * The DataType is `BaseDataType`; the concrete type of each element depends on
485
+ * the server configuration.
486
+ */
487
+ readonly selections: readonly unknown[];
488
+ /**
489
+ * Human-readable description for each permitted value
490
+ * (SelectionListType.SelectionDescriptions optional property, OPC 10000-5 §7.18).
491
+ *
492
+ * Empty when the property is not present on the node.
493
+ * When present, `selectionDescriptions[i]` describes `selections[i]`.
494
+ */
495
+ readonly selectionDescriptions: readonly LocalizedText[];
496
+ /**
497
+ * When `true`, the variable's value MUST be one of the values in `selections`
498
+ * (SelectionListType.RestrictToList optional property, OPC 10000-5 §7.18).
499
+ *
500
+ * Defaults to `false` when the property is absent on the node.
501
+ */
502
+ readonly restrictToList: boolean;
503
+ };
504
+
262
505
  declare class Client {
263
506
  private configuration;
264
507
  private identity;
@@ -274,12 +517,63 @@ declare class Client {
274
517
  private ws?;
275
518
  private sessionHandler?;
276
519
  private keepAliveTimer?;
520
+ /** Set to true while a shutdown-triggered reconnect is pending to avoid duplicate attempts. */
521
+ private shutdownReconnectPending;
522
+ /** Most recently read NamespaceArray from the server (Session Client Renew NodeIds). */
523
+ private namespaceTable?;
524
+ /**
525
+ * Called whenever the server's NamespaceArray changes after a session (re-)establishment
526
+ * (OPC UA Part 4, Section 5.7.1 — Session Client Renew NodeIds conformance unit).
527
+ *
528
+ * Use `oldTable.remapNodeId(nodeId, newTable)` to recalculate cached NodeIds.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * client.onNamespaceTableChanged = (oldTable, newTable) => {
533
+ * cachedNodeId = oldTable.remapNodeId(cachedNodeId, newTable)
534
+ * }
535
+ * ```
536
+ */
537
+ onNamespaceTableChanged?: (oldTable: NamespaceTable, newTable: NamespaceTable) => void;
538
+ /**
539
+ * Called when the server sends `EstimatedReturnTime = MinDateTime`, indicating it does not
540
+ * expect to restart (OPC UA Part 5, Section 12.6 — Base Info Client Estimated Return Time
541
+ * conformance unit).
542
+ *
543
+ * When this fires the automatic reconnect is suppressed. The application is responsible for
544
+ * deciding whether to keep the `Client` instance or dispose it.
545
+ *
546
+ * @example
547
+ * ```ts
548
+ * client.onPermanentShutdown = () => {
549
+ * console.warn('Server will not restart — closing client.')
550
+ * }
551
+ * ```
552
+ */
553
+ onPermanentShutdown?: () => void;
277
554
  getSession(): Session;
278
555
  /**
279
556
  * (Re-)initialises all session-scoped services from the current `this.session`.
280
557
  * Called both after the initial `connect()` and after a session refresh.
281
558
  */
282
559
  private initServices;
560
+ /**
561
+ * Reads `Server.NamespaceArray` (ns=0, i=2255) and updates the stored
562
+ * `NamespaceTable`. When the table changes compared to the previous read the
563
+ * `onNamespaceTableChanged` callback is fired so the application can remap
564
+ * any cached NodeIds (OPC UA Part 4, Section 5.7.1 — Session Client Renew
565
+ * NodeIds conformance unit).
566
+ *
567
+ * Errors are logged as warnings and do not propagate to the caller.
568
+ */
569
+ private refreshNamespaceTable;
570
+ /**
571
+ * Returns the most recently read `NamespaceTable` for this session.
572
+ *
573
+ * Available after `connect()` completes (the table is read as part of session
574
+ * establishment). Returns `undefined` before the first successful read.
575
+ */
576
+ getNamespaceTable(): NamespaceTable | undefined;
283
577
  /**
284
578
  * Executes `fn` and, if it throws a `SessionInvalidError`, creates a fresh
285
579
  * session and retries the operation exactly once.
@@ -298,9 +592,40 @@ declare class Client {
298
592
  * Starts a periodic keep-alive timer that reads Server_ServerStatus when no subscription is
299
593
  * active. OPC UA Part 4, Section 5.7.1 requires clients to keep the session alive; when no
300
594
  * subscription Publish loop is running this is the only mechanism that does so.
595
+ *
596
+ * The keep-alive read also serves as the **Detect Shutdown** mechanism (Session Client Detect
597
+ * Shutdown conformance unit): when the returned `ServerStatusDataType.state` equals
598
+ * `ServerStateEnum.Shutdown` the client schedules a reconnect after
599
+ * `SHUTDOWN_RECONNECT_DELAY_MS` to let the server finish its shutdown sequence.
301
600
  */
302
601
  private startKeepAlive;
303
602
  private stopKeepAlive;
603
+ /**
604
+ * Called when a server-shutdown announcement is detected — either via the keep-alive read
605
+ * returning `ServerStateEnum.Shutdown` or via a subscription `StatusChangeNotification`
606
+ * with status `BadShutdown` / `BadServerHalted`.
607
+ *
608
+ * Reads `Server/ServerStatus/EstimatedReturnTime` (ns=0, i=2992) to decide how long to
609
+ * wait before reconnecting (Base Info Client Estimated Return Time conformance unit).
610
+ * Falls back to `configuration.shutdownReconnectDelayMs` when the read fails or the
611
+ * attributed service is not yet available. Fires `onPermanentShutdown` and suppresses the
612
+ * reconnect when the server sends `MinDateTime`.
613
+ *
614
+ * Only one reconnect attempt is scheduled at a time; a second detection while one is already
615
+ * pending is silently ignored.
616
+ */
617
+ private handleServerShutdownDetected;
618
+ /**
619
+ * Reads `Server/ServerStatus/EstimatedReturnTime` (ns=0, i=2992) and returns the reconnect
620
+ * delay in milliseconds (Base Info Client Estimated Return Time — OPC UA Part 5, §12.6):
621
+ *
622
+ * - Valid future `DateTime` → delay = `estimatedReturnTime − now`, clamped to at least
623
+ * `MIN_RECONNECT_DELAY_MS`.
624
+ * - Past `DateTime` (server should already be available) → `MIN_RECONNECT_DELAY_MS`.
625
+ * - OPC UA `MinDateTime` (server will not restart) → `null`.
626
+ * - Unreadable / unavailable → falls back to `configuration.shutdownReconnectDelayMs`.
627
+ */
628
+ private computeReconnectDelayMs;
304
629
  connect(): Promise<void>;
305
630
  /**
306
631
  * Builds the full WebSocket → TCP → SecureChannel pipeline and returns the
@@ -342,21 +667,159 @@ declare class Client {
342
667
  * when the session has already expired on the server side.
343
668
  */
344
669
  disconnect(): Promise<void>;
345
- read(ids: NodeId[]): Promise<ReadValueResult[]>;
670
+ /**
671
+ * Reads the Value attribute of one or more Nodes.
672
+ *
673
+ * The returned object is a `Promise` that also exposes `requestHandle` — the
674
+ * OPC UA `requestHandle` assigned to the underlying `ReadRequest`. The handle
675
+ * is available synchronously (before `await`) so it can be passed to
676
+ * `cancel()` to abort the in-flight request.
677
+ *
678
+ * @example
679
+ * ```ts
680
+ * const req = client.read([nodeId])
681
+ * await client.cancel(req.requestHandle) // abort before response
682
+ * const results = await req // ReadValueResult[]
683
+ * ```
684
+ */
685
+ read(ids: NodeId[], options?: RequestOptions): Promise<ReadValueResult[]> & {
686
+ requestHandle: number;
687
+ };
346
688
  /**
347
689
  * Method for calling a single method on the server.
690
+ *
691
+ * The returned object is a `Promise` that also exposes `requestHandle` — the
692
+ * OPC UA `requestHandle` assigned to the underlying `CallRequest`. The handle
693
+ * is available synchronously (before `await`) so it can be passed to
694
+ * `cancel()` to abort the in-flight request.
695
+ *
348
696
  * @param objectId - NodeId of the Object that owns the method.
349
697
  * @param methodId - NodeId of the Method to invoke.
350
698
  * @param inputArguments - Input argument Variants (default: empty).
351
- * @returns The CallMethodResult for the invoked method.
699
+ * @param options - Request options (e.g. `returnDiagnostics`).
700
+ * @returns A promise resolving to the CallMethodResult, with `requestHandle` available synchronously.
701
+ */
702
+ callMethod(objectId: NodeId, methodId: NodeId, inputArguments?: CallMethodArgument[], options?: RequestOptions): Promise<CallMethodResult> & {
703
+ requestHandle: number;
704
+ };
705
+ /**
706
+ * Browses the Address Space starting from `nodeId`.
707
+ *
708
+ * The returned object is a `Promise` that also exposes `requestHandle` — the
709
+ * OPC UA `requestHandle` assigned to the initial `BrowseRequest`. The handle
710
+ * is available synchronously (before `await`) so it can be passed to
711
+ * `cancel()` to abort the in-flight request.
712
+ *
713
+ * @param nodeId - Starting node.
714
+ * @param recursive - When true, recursively follows HierarchicalReferences.
715
+ * @param options - Request options (e.g. `returnDiagnostics`).
716
+ * @returns A promise resolving to the list of referenced nodes, with `requestHandle` available synchronously.
352
717
  */
353
- callMethod(objectId: NodeId, methodId: NodeId, inputArguments?: CallMethodArgument[]): Promise<CallMethodResult>;
354
- browse(nodeId: NodeId, recursive?: boolean): Promise<BrowseNodeResult[]>;
718
+ browse(nodeId: NodeId, recursive?: boolean, options?: RequestOptions): Promise<BrowseNodeResult[]> & {
719
+ requestHandle: number;
720
+ };
355
721
  private browseRecursive;
356
722
  subscribe(ids: NodeId[], callback: (data: {
357
723
  id: NodeId;
358
724
  value: unknown;
359
725
  }[]) => void, options?: SubscriptionOptions): Promise<void>;
726
+ /**
727
+ * Asks the server to cancel a pending service request
728
+ * (OPC UA Part 4, Section 5.7.5 — Session Client Cancel conformance unit).
729
+ *
730
+ * The `requestHandle` uniquely identifies the pending request. It is the value
731
+ * assigned to `RequestHeader.requestHandle` when the request was initially sent.
732
+ * Service calls made through this client automatically assign monotonically
733
+ * increasing handles, so the caller can capture the handle before or after issuing
734
+ * Each method (`read`, `browse`, `callMethod`) returns a `Promise` with a
735
+ * `requestHandle` property that is available synchronously. Pass that handle
736
+ * here to abort the corresponding in-flight request.
737
+ *
738
+ * The server makes a best-effort attempt to cancel the matching request. Cancelled
739
+ * requests complete with status `BadRequestCancelledByClient`. Not all servers
740
+ * guarantee that a request in flight can be cancelled.
741
+ *
742
+ * @param requestHandle - Handle of the pending request to cancel.
743
+ * @returns The number of pending requests the server actually cancelled.
744
+ * @throws If no session is active or the server returns a non-Good status.
745
+ *
746
+ * @example
747
+ * ```ts
748
+ * // Issue a potentially slow operation and immediately cancel it.
749
+ * const req = client.read([nodeId])
750
+ * const cancelled = await client.cancel(req.requestHandle)
751
+ * console.log(`Cancelled ${cancelled} request(s)`)
752
+ * const results = await req // resolves with BadRequestCancelledByClient
753
+ * ```
754
+ */
755
+ cancel(requestHandle: number): Promise<number>;
756
+ /**
757
+ * Switches the active user identity for the current session by calling ActivateSession
758
+ * with a new identity token (OPC UA Part 4, Section 5.7.3 — Session Client Impersonate
759
+ * conformance unit).
760
+ *
761
+ * The server re-evaluates authorisation under the new identity while keeping all existing
762
+ * Subscriptions and MonitoredItems intact. The new identity is also stored so that any
763
+ * subsequent auto-reconnect or session refresh uses it instead of the original identity.
764
+ *
765
+ * @param identity - The new user identity to apply to the session.
766
+ * @throws {Error} When not connected (call `connect()` first).
767
+ * @throws {Error} When the server rejects the identity (e.g. `BadIdentityTokenRejected`
768
+ * or `BadUserAccessDenied`).
769
+ *
770
+ * @example
771
+ * ```ts
772
+ * await client.connect()
773
+ * // ... work as the original user ...
774
+ * await client.impersonate(UserIdentity.newWithUserName('admin', 'secret'))
775
+ * // ... subsequent calls run under the admin identity ...
776
+ * ```
777
+ */
778
+ impersonate(identity: UserIdentity): Promise<void>;
779
+ /**
780
+ * Reads the `SelectionListType` metadata for a Variable
781
+ * (OPC UA Part 5, §7.18 — Base Info Client Selection List conformance unit).
782
+ *
783
+ * The client browses the node's `HasProperty` references for `Selections`,
784
+ * `SelectionDescriptions`, and `RestrictToList`, then reads their values in a
785
+ * single batch Read request.
786
+ *
787
+ * Works transparently for instances of `SelectionListType` (ns=0; i=19726) and
788
+ * any of its subtypes, because all subtypes inherit the `Selections` mandatory
789
+ * property.
790
+ *
791
+ * @param nodeId - NodeId of the Variable to inspect.
792
+ * @returns `SelectionList` when the node has a `Selections` property, `null` otherwise.
793
+ * @throws When not connected or if the server returns a non-Good service status.
794
+ *
795
+ * @example
796
+ * ```ts
797
+ * const list = await client.getSelectionList(nodeId)
798
+ * if (list) {
799
+ * list.selectionDescriptions.forEach((desc, i) =>
800
+ * console.log(`[${i}] ${desc.text}:`, list.selections[i])
801
+ * )
802
+ * }
803
+ * ```
804
+ */
805
+ getSelectionList(nodeId: NodeId): Promise<SelectionList | null>;
806
+ /**
807
+ * Internal implementation of `getSelectionList`. Browses the node's
808
+ * HasProperty references to locate Selections/SelectionDescriptions/RestrictToList,
809
+ * then batch-reads their values.
810
+ */
811
+ private fetchSelectionList;
812
+ /**
813
+ * The `requestHandle` value that was assigned to the most recently issued
814
+ * service request in this session.
815
+ *
816
+ * @deprecated Prefer accessing `requestHandle` directly on the promise returned
817
+ * by `read()`, `browse()`, or `callMethod()`, which is available synchronously
818
+ * before `await` and avoids relying on shared module state.
819
+ *
820
+ * Returns `0` before any request has been sent.
821
+ */
822
+ get lastRequestHandle(): number;
360
823
  constructor(endpointUrl: string, configuration: ConfigurationClient, identity: UserIdentity);
361
824
  }
362
825
 
@@ -376,4 +839,27 @@ declare class SessionInvalidError extends Error {
376
839
  constructor(statusCode: number);
377
840
  }
378
841
 
379
- export { BrowseNodeResult, type CallMethodArgument, CallMethodResult, Client, ConfigurationClient, SECURITY_POLICY_NONE_URI, type ScalarCallMethodArgument, type SecurityConfiguration, SessionInvalidError, type SubscriptionOptions, type UnknownCertificatePolicy, UserIdentity };
842
+ /**
843
+ * Thrown when the server rejects `CreateSession` because no (or an invalid)
844
+ * client certificate was supplied.
845
+ *
846
+ * This signals that the OPC UA 1.0 fallback path should be attempted: retry
847
+ * `CreateSession` with the `applicationInstanceCertificate` from the
848
+ * `SecurityConfiguration`.
849
+ *
850
+ * Relevant OPC UA status codes that trigger this error:
851
+ * - `BadCertificateInvalid` (0x80120000) – null/empty cert was rejected
852
+ * - `BadSecurityChecksFailed` (0x80130000) – security validation failed
853
+ * - `BadNoValidCertificates` (0x80590000) – server found no valid certificate
854
+ */
855
+ declare class CertificateRequiredError extends Error {
856
+ readonly statusCode: number;
857
+ constructor(statusCode: number);
858
+ }
859
+ /**
860
+ * Status codes that indicate the server requires a client certificate even
861
+ * when SecurityPolicy is None (OPC UA 1.0 servers).
862
+ */
863
+ declare const CERTIFICATE_REQUIRED_STATUS_CODES: Set<number>;
864
+
865
+ export { BrowseNodeResult, CERTIFICATE_REQUIRED_STATUS_CODES, type CallMethodArgument, CallMethodResult, CertificateRequiredError, Client, ConfigurationClient, NamespaceTable, type RequestOptions, ReturnDiagnosticsMask, SECURITY_POLICY_NONE_URI, type ScalarCallMethodArgument, type SecurityConfiguration, type SelectionList, SessionInvalidError, type SubscriptionOptions, type UnknownCertificatePolicy, UserIdentity };