node-opcua-alias-name-client 2.176.0
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/LICENSE +22 -0
- package/README.md +137 -0
- package/dist/client_alias_set.d.ts +144 -0
- package/dist/client_alias_set.js +223 -0
- package/dist/client_alias_set.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.js +54 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/server_index_resolver.d.ts +54 -0
- package/dist/server_index_resolver.js +82 -0
- package/dist/server_index_resolver.js.map +1 -0
- package/package.json +54 -0
- package/source/client_alias_set.ts +312 -0
- package/source/errors.ts +57 -0
- package/source/index.ts +23 -0
- package/source/server_index_resolver.ts +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2024 Sterfive SAS - 833264583 RCS ORLEANS - France (https://www.sterfive.com)
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2014-2022 Etienne Rossignon
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
8
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
9
|
+
the Software without restriction, including without limitation the rights to
|
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
11
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
12
|
+
subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
19
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
20
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
21
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
22
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# node-opcua-alias-name-client
|
|
2
|
+
|
|
3
|
+
Client-side OPC UA **AliasNames** (OPC 10000-17).
|
|
4
|
+
|
|
5
|
+
These packages let a Server publish **its own** AliasNames and let a Client resolve
|
|
6
|
+
them. They do **not** aggregate AliasNames collected from other Servers: Annex B
|
|
7
|
+
(aggregating Server) and Annex C (GDS) of OPC 10000-17, and the Annex D PubSub change
|
|
8
|
+
notification, are out of scope. Anything that requires knowing about more than one
|
|
9
|
+
Server is not implemented here.
|
|
10
|
+
|
|
11
|
+
see http://node-opcua.github.io/
|
|
12
|
+
|
|
13
|
+
## What it is for
|
|
14
|
+
|
|
15
|
+
Part 17 is, in effect, DNS for an address space. Instead of configuring a Client with a
|
|
16
|
+
raw NodeId that changes whenever the Server is re-engineered, ask for the plant tag:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { ClientAliasSet } from "node-opcua-alias-name-client";
|
|
20
|
+
|
|
21
|
+
const aliases = new ClientAliasSet(session);
|
|
22
|
+
const [entry] = await aliases.findAlias("TI101");
|
|
23
|
+
const nodeId = entry.referencedNodes[0];
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install node-opcua-alias-name-client
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Works with any session
|
|
33
|
+
|
|
34
|
+
`ClientAliasSet` takes an `IBasicSessionAsync2`, so the same code drives a remote
|
|
35
|
+
`ClientSession` and an in-process `PseudoSession`:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const aliases = new ClientAliasSet(new PseudoSession(addressSpace));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
That is what lets this package be tested without a transport, and what lets a
|
|
42
|
+
Server-side tool resolve its own aliases through the API a Client uses.
|
|
43
|
+
|
|
44
|
+
## Searching
|
|
45
|
+
|
|
46
|
+
The argument is an OPC 10000-4 `Like` pattern — `%` is any run of characters, `_` exactly
|
|
47
|
+
one, `[abc]` and `[^abc]` are lists, `\` escapes. An exact name is a pattern with no
|
|
48
|
+
wildcards.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
await aliases.findAlias("TI101"); // exact
|
|
52
|
+
await aliases.findAlias("TI%"); // prefix
|
|
53
|
+
await aliases.findAlias("%", { categoryNodeId: TAG_VARIABLES }); // one branch
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The search is recursive from the category given, defaulting to the `Aliases` root, so one
|
|
57
|
+
call covers everything the Server publishes.
|
|
58
|
+
|
|
59
|
+
Results are **typed**, never raw Variants: `aliasName` is a string, `referencedNodes` is
|
|
60
|
+
`ExpandedNodeId[]`, ordered best match first (clause 6.3.2).
|
|
61
|
+
|
|
62
|
+
No match is an empty array, not an error — clause 6.3.2 Table 3 makes that a `Good`
|
|
63
|
+
response. A Server-side failure raises `AliasNameCallError`, which carries the StatusCode
|
|
64
|
+
so the cases of Table 4 stay distinguishable:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
try {
|
|
68
|
+
await aliases.findAlias(userSuppliedPattern);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (err instanceof AliasNameCallError && err.statusCode.equals(StatusCodes.BadResponseTooLarge)) {
|
|
71
|
+
// ask the user to narrow the pattern
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## `FindAliasVerbose` is optional — handle its absence
|
|
77
|
+
|
|
78
|
+
Only `FindAlias` is MANDATORY (clause 6.3). A Server exposing nothing else is perfectly
|
|
79
|
+
conformant, so its absence is an outcome to handle rather than a fault:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
if (await aliases.supportsVerbose()) {
|
|
83
|
+
const entries = await aliases.findAliasVerbose("TI101");
|
|
84
|
+
entries[0].aliasNameCategoryId; // which category held it
|
|
85
|
+
entries[0].serverUris; // parallel to referencedNodes; null = this Server
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Calling it anyway raises `AliasNameMethodNotSupportedError`, naming the Method and the
|
|
90
|
+
category, **before any call is made** — the absence is discovered while resolving NodeIds,
|
|
91
|
+
so it never arrives as an unhandled `Bad_NotImplemented` from the wire.
|
|
92
|
+
|
|
93
|
+
`supportsConfiguration()` does the same for `AddAliasesToCategory` /
|
|
94
|
+
`DeleteAliasesFromCategory`.
|
|
95
|
+
|
|
96
|
+
## Method NodeIds are resolved once
|
|
97
|
+
|
|
98
|
+
All four Methods of a category are resolved in a **single** `translateBrowsePath` round
|
|
99
|
+
trip and cached for the life of the instance — asking for four costs no more than asking
|
|
100
|
+
for one, so a later `findAliasVerbose` after a `findAlias` makes no further round trip.
|
|
101
|
+
Construct one `ClientAliasSet` per session; call `invalidate()` if the Server's address
|
|
102
|
+
space changes underneath it.
|
|
103
|
+
|
|
104
|
+
## Nodes on another Server (Annex A)
|
|
105
|
+
|
|
106
|
+
A returned `ExpandedNodeId` may carry a non-zero `ServerIndex`, which says only "this Node
|
|
107
|
+
is somewhere else" — the index means nothing without the Server's `ServerArray`. That
|
|
108
|
+
lookup is the step every Client has to perform, so it is here rather than in each caller:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const located = await aliases.serverIndexResolver.locate(entry.referencedNodes[0]);
|
|
112
|
+
if (!located.local) {
|
|
113
|
+
connectTo(located.serverUri);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The `ServerArray` is read once and cached. Every Node these packages publish is local, so
|
|
118
|
+
`local` is always true against a Server built with `node-opcua-alias-name-server`; this
|
|
119
|
+
matters when talking to a Server that does aggregate.
|
|
120
|
+
|
|
121
|
+
## Browsing the hierarchy
|
|
122
|
+
|
|
123
|
+
Resolving an alias needs no browsing — `findAlias` on the root searches recursively — but
|
|
124
|
+
a Client that wants to show the tree, or search one branch, can walk it:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
for (const category of await aliases.browseSubCategories()) {
|
|
128
|
+
console.log(category.browseName, category.nodeId.toString());
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Only `AliasNameCategoryType` instances are returned; the `AliasNameType` instances a
|
|
133
|
+
category also Organizes are not categories and are filtered out.
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-alias-name-client
|
|
3
|
+
*
|
|
4
|
+
* Client-side API for OPC UA AliasNames (OPC 10000-17).
|
|
5
|
+
*
|
|
6
|
+
* All navigation goes through {@link IBasicSessionAsync2} — browse, read, call,
|
|
7
|
+
* translateBrowsePath — so the same code drives a remote `ClientSession` and an
|
|
8
|
+
* in-process `PseudoSession`. That is what lets these be tested without a
|
|
9
|
+
* transport, and what lets a Server-side tool resolve its own aliases through
|
|
10
|
+
* the same API a Client uses.
|
|
11
|
+
*/
|
|
12
|
+
import { type ExpandedNodeId, type NodeId } from "node-opcua-nodeid";
|
|
13
|
+
import type { IBasicSessionAsync2 } from "node-opcua-pseudo-session";
|
|
14
|
+
import { ServerIndexResolver } from "./server_index_resolver.js";
|
|
15
|
+
/** `Aliases`, the root of the hierarchy (OPC 10000-17 clause 9.2). */
|
|
16
|
+
export declare const ALIASES_ROOT: NodeId;
|
|
17
|
+
/** `TagVariables` (clause 9.3). */
|
|
18
|
+
export declare const TAG_VARIABLES: NodeId;
|
|
19
|
+
/** `Topics` (clause 9.4). */
|
|
20
|
+
export declare const TOPICS: NodeId;
|
|
21
|
+
/** One resolved AliasName, as `FindAlias` reports it (clause 7.2). */
|
|
22
|
+
export interface ClientAliasEntry {
|
|
23
|
+
/** The string part of the AliasName. */
|
|
24
|
+
aliasName: string;
|
|
25
|
+
/**
|
|
26
|
+
* The namespace the AliasName was published in.
|
|
27
|
+
*
|
|
28
|
+
* Clause 6.2 requires a Client to **ignore this when comparing** AliasNames.
|
|
29
|
+
* It is reported for completeness, not for matching.
|
|
30
|
+
*/
|
|
31
|
+
namespaceIndex: number;
|
|
32
|
+
/** The Nodes the alias names, best match first (clause 6.3.2). */
|
|
33
|
+
referencedNodes: ExpandedNodeId[];
|
|
34
|
+
}
|
|
35
|
+
/** One resolved AliasName, as `FindAliasVerbose` reports it (clause 7.3). */
|
|
36
|
+
export interface ClientAliasVerboseEntry extends ClientAliasEntry {
|
|
37
|
+
/**
|
|
38
|
+
* Parallel to {@link referencedNodes}: the ServerUri of each Node, `null`
|
|
39
|
+
* for one on the Server that answered.
|
|
40
|
+
*/
|
|
41
|
+
serverUris: (string | null)[];
|
|
42
|
+
/**
|
|
43
|
+
* The category that actually held the alias, which for a recursive search is
|
|
44
|
+
* the nested one rather than the one that was called.
|
|
45
|
+
*/
|
|
46
|
+
aliasNameCategoryId: NodeId;
|
|
47
|
+
}
|
|
48
|
+
export interface FindAliasOptions {
|
|
49
|
+
/**
|
|
50
|
+
* The category to search, recursively. Defaults to {@link ALIASES_ROOT},
|
|
51
|
+
* which covers everything the Server publishes.
|
|
52
|
+
*/
|
|
53
|
+
categoryNodeId?: NodeId;
|
|
54
|
+
/**
|
|
55
|
+
* Restrict to this ReferenceType and its subtypes (clause 6.3.2 Table 3).
|
|
56
|
+
* Omit for any.
|
|
57
|
+
*/
|
|
58
|
+
referenceTypeFilter?: NodeId;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Client-side entry point for a Server's AliasNames.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* const aliases = new ClientAliasSet(session);
|
|
65
|
+
* const [entry] = await aliases.findAlias("TI101");
|
|
66
|
+
* const nodeId = entry.referencedNodes[0];
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* Construct one per session: Method NodeIds are resolved lazily, in a single
|
|
70
|
+
* `translateBrowsePath` round trip per category, and cached for the lifetime of
|
|
71
|
+
* the instance.
|
|
72
|
+
*
|
|
73
|
+
* This resolves the aliases **a Server publishes about itself**. Aggregating
|
|
74
|
+
* across Servers (OPC 10000-17 Annexes B and C) is out of scope; where a Server
|
|
75
|
+
* does aggregate, {@link serverIndexResolver} turns the `ServerIndex` of a
|
|
76
|
+
* returned `ExpandedNodeId` into a URI.
|
|
77
|
+
*/
|
|
78
|
+
export declare class ClientAliasSet {
|
|
79
|
+
readonly session: IBasicSessionAsync2;
|
|
80
|
+
/** Resolves the `ServerIndex` of a returned Node (Annex A). */
|
|
81
|
+
readonly serverIndexResolver: ServerIndexResolver;
|
|
82
|
+
private readonly methodCache;
|
|
83
|
+
constructor(session: IBasicSessionAsync2);
|
|
84
|
+
/**
|
|
85
|
+
* Resolve an AliasName, or a `Like` pattern, to the Nodes it names.
|
|
86
|
+
*
|
|
87
|
+
* The pattern is an OPC 10000-4 `Like` pattern: `%` is any run of
|
|
88
|
+
* characters, `_` is exactly one, `[abc]` and `[^abc]` are lists, and `\`
|
|
89
|
+
* escapes. An exact name is simply a pattern with no wildcards.
|
|
90
|
+
*
|
|
91
|
+
* @throws {@link AliasNameCallError} when the Server answers a bad
|
|
92
|
+
* StatusCode — `Bad_InvalidArgument` for a malformed pattern,
|
|
93
|
+
* `Bad_ResponseTooLarge` when a narrower filter is needed,
|
|
94
|
+
* `Bad_UserAccessDenied` when the session may not read the category.
|
|
95
|
+
*/
|
|
96
|
+
findAlias(pattern: string, options?: FindAliasOptions): Promise<ClientAliasEntry[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Resolve an AliasName and learn which category held it and which Server
|
|
99
|
+
* each Node is on (clause 6.3.3).
|
|
100
|
+
*
|
|
101
|
+
* @throws {@link AliasNameMethodNotSupportedError} when the Server exposes
|
|
102
|
+
* only the mandatory `FindAlias`. That is a conformant Server, so this is
|
|
103
|
+
* an expected outcome to handle, not a fault — use {@link supportsVerbose}
|
|
104
|
+
* to check first.
|
|
105
|
+
*/
|
|
106
|
+
findAliasVerbose(pattern: string, options?: FindAliasOptions): Promise<ClientAliasVerboseEntry[]>;
|
|
107
|
+
/**
|
|
108
|
+
* True when the Server exposes `FindAliasVerbose` on this category.
|
|
109
|
+
*
|
|
110
|
+
* Cheaper than catching {@link AliasNameMethodNotSupportedError}, and reads
|
|
111
|
+
* better when the Client has a fallback path.
|
|
112
|
+
*/
|
|
113
|
+
supportsVerbose(categoryNodeId?: NodeId): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* True when the Server exposes the configuration Methods on this category
|
|
116
|
+
* (clauses 6.3.4 and 6.3.5). They are optional and off by default in most
|
|
117
|
+
* Servers.
|
|
118
|
+
*/
|
|
119
|
+
supportsConfiguration(categoryNodeId?: NodeId): Promise<boolean>;
|
|
120
|
+
/**
|
|
121
|
+
* The `AliasNameCategoryType` instances Organized directly by a category.
|
|
122
|
+
*
|
|
123
|
+
* Browsing is not needed to *resolve* an alias — `FindAlias` on the root
|
|
124
|
+
* searches recursively — but a Client that wants to show the hierarchy, or
|
|
125
|
+
* to search one branch, needs it.
|
|
126
|
+
*/
|
|
127
|
+
browseSubCategories(categoryNodeId?: NodeId): Promise<Array<{
|
|
128
|
+
nodeId: NodeId;
|
|
129
|
+
browseName: string;
|
|
130
|
+
}>>;
|
|
131
|
+
/** Forget every cached Method NodeId. */
|
|
132
|
+
invalidate(): void;
|
|
133
|
+
/**
|
|
134
|
+
* Resolve every Method of a category in **one** `translateBrowsePath` round
|
|
135
|
+
* trip, and cache the result.
|
|
136
|
+
*
|
|
137
|
+
* Asking for all four at once costs no more than asking for one, and means a
|
|
138
|
+
* Client that later calls `findAliasVerbose` after `findAlias` makes no
|
|
139
|
+
* further round trip.
|
|
140
|
+
*/
|
|
141
|
+
private resolveMethods;
|
|
142
|
+
/** Call one of the two find Methods and return its ExtensionObject array. */
|
|
143
|
+
private callFind;
|
|
144
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module node-opcua-alias-name-client
|
|
4
|
+
*
|
|
5
|
+
* Client-side API for OPC UA AliasNames (OPC 10000-17).
|
|
6
|
+
*
|
|
7
|
+
* All navigation goes through {@link IBasicSessionAsync2} — browse, read, call,
|
|
8
|
+
* translateBrowsePath — so the same code drives a remote `ClientSession` and an
|
|
9
|
+
* in-process `PseudoSession`. That is what lets these be tested without a
|
|
10
|
+
* transport, and what lets a Server-side tool resolve its own aliases through
|
|
11
|
+
* the same API a Client uses.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.ClientAliasSet = exports.TOPICS = exports.TAG_VARIABLES = exports.ALIASES_ROOT = void 0;
|
|
15
|
+
const node_opcua_constants_1 = require("node-opcua-constants");
|
|
16
|
+
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
17
|
+
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
|
|
18
|
+
const node_opcua_service_translate_browse_path_1 = require("node-opcua-service-translate-browse-path");
|
|
19
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
20
|
+
const errors_js_1 = require("./errors.js");
|
|
21
|
+
const server_index_resolver_js_1 = require("./server_index_resolver.js");
|
|
22
|
+
/** `Aliases`, the root of the hierarchy (OPC 10000-17 clause 9.2). */
|
|
23
|
+
exports.ALIASES_ROOT = (0, node_opcua_nodeid_1.resolveNodeId)(node_opcua_constants_1.ObjectIds.Aliases);
|
|
24
|
+
/** `TagVariables` (clause 9.3). */
|
|
25
|
+
exports.TAG_VARIABLES = (0, node_opcua_nodeid_1.resolveNodeId)(node_opcua_constants_1.ObjectIds.TagVariables);
|
|
26
|
+
/** `Topics` (clause 9.4). */
|
|
27
|
+
exports.TOPICS = (0, node_opcua_nodeid_1.resolveNodeId)(node_opcua_constants_1.ObjectIds.Topics);
|
|
28
|
+
/** Read a QualifiedName's parts defensively — a Server may send a bare string. */
|
|
29
|
+
function qualifiedName(value) {
|
|
30
|
+
return { name: value?.name ?? "", namespaceIndex: value?.namespaceIndex ?? 0 };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Client-side entry point for a Server's AliasNames.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* const aliases = new ClientAliasSet(session);
|
|
37
|
+
* const [entry] = await aliases.findAlias("TI101");
|
|
38
|
+
* const nodeId = entry.referencedNodes[0];
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Construct one per session: Method NodeIds are resolved lazily, in a single
|
|
42
|
+
* `translateBrowsePath` round trip per category, and cached for the lifetime of
|
|
43
|
+
* the instance.
|
|
44
|
+
*
|
|
45
|
+
* This resolves the aliases **a Server publishes about itself**. Aggregating
|
|
46
|
+
* across Servers (OPC 10000-17 Annexes B and C) is out of scope; where a Server
|
|
47
|
+
* does aggregate, {@link serverIndexResolver} turns the `ServerIndex` of a
|
|
48
|
+
* returned `ExpandedNodeId` into a URI.
|
|
49
|
+
*/
|
|
50
|
+
class ClientAliasSet {
|
|
51
|
+
session;
|
|
52
|
+
/** Resolves the `ServerIndex` of a returned Node (Annex A). */
|
|
53
|
+
serverIndexResolver;
|
|
54
|
+
methodCache = new Map();
|
|
55
|
+
constructor(session) {
|
|
56
|
+
this.session = session;
|
|
57
|
+
this.serverIndexResolver = new server_index_resolver_js_1.ServerIndexResolver(session);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolve an AliasName, or a `Like` pattern, to the Nodes it names.
|
|
61
|
+
*
|
|
62
|
+
* The pattern is an OPC 10000-4 `Like` pattern: `%` is any run of
|
|
63
|
+
* characters, `_` is exactly one, `[abc]` and `[^abc]` are lists, and `\`
|
|
64
|
+
* escapes. An exact name is simply a pattern with no wildcards.
|
|
65
|
+
*
|
|
66
|
+
* @throws {@link AliasNameCallError} when the Server answers a bad
|
|
67
|
+
* StatusCode — `Bad_InvalidArgument` for a malformed pattern,
|
|
68
|
+
* `Bad_ResponseTooLarge` when a narrower filter is needed,
|
|
69
|
+
* `Bad_UserAccessDenied` when the session may not read the category.
|
|
70
|
+
*/
|
|
71
|
+
async findAlias(pattern, options) {
|
|
72
|
+
const categoryNodeId = options?.categoryNodeId ?? exports.ALIASES_ROOT;
|
|
73
|
+
const methods = await this.resolveMethods(categoryNodeId);
|
|
74
|
+
if (!methods.findAlias) {
|
|
75
|
+
// FindAlias is MANDATORY, so this means the Node is not an
|
|
76
|
+
// AliasNameCategoryType instance, or the Server is non-conformant
|
|
77
|
+
throw new errors_js_1.AliasNameMethodNotSupportedError("FindAlias", categoryNodeId);
|
|
78
|
+
}
|
|
79
|
+
const extensionObjects = await this.callFind("FindAlias", categoryNodeId, methods.findAlias, pattern, options?.referenceTypeFilter);
|
|
80
|
+
return extensionObjects.map((raw) => {
|
|
81
|
+
const value = raw;
|
|
82
|
+
const { name, namespaceIndex } = qualifiedName(value.aliasName);
|
|
83
|
+
return {
|
|
84
|
+
aliasName: name,
|
|
85
|
+
namespaceIndex,
|
|
86
|
+
referencedNodes: value.referencedNodes ?? []
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve an AliasName and learn which category held it and which Server
|
|
92
|
+
* each Node is on (clause 6.3.3).
|
|
93
|
+
*
|
|
94
|
+
* @throws {@link AliasNameMethodNotSupportedError} when the Server exposes
|
|
95
|
+
* only the mandatory `FindAlias`. That is a conformant Server, so this is
|
|
96
|
+
* an expected outcome to handle, not a fault — use {@link supportsVerbose}
|
|
97
|
+
* to check first.
|
|
98
|
+
*/
|
|
99
|
+
async findAliasVerbose(pattern, options) {
|
|
100
|
+
const categoryNodeId = options?.categoryNodeId ?? exports.ALIASES_ROOT;
|
|
101
|
+
const methods = await this.resolveMethods(categoryNodeId);
|
|
102
|
+
if (!methods.findAliasVerbose) {
|
|
103
|
+
throw new errors_js_1.AliasNameMethodNotSupportedError("FindAliasVerbose", categoryNodeId);
|
|
104
|
+
}
|
|
105
|
+
const extensionObjects = await this.callFind("FindAliasVerbose", categoryNodeId, methods.findAliasVerbose, pattern, options?.referenceTypeFilter);
|
|
106
|
+
return extensionObjects.map((raw) => {
|
|
107
|
+
const value = raw;
|
|
108
|
+
const { name, namespaceIndex } = qualifiedName(value.aliasName);
|
|
109
|
+
return {
|
|
110
|
+
aliasName: name,
|
|
111
|
+
namespaceIndex,
|
|
112
|
+
referencedNodes: value.referencedNodes ?? [],
|
|
113
|
+
serverUris: value.serverUris ?? [],
|
|
114
|
+
aliasNameCategoryId: value.aliasNameCategoryId
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* True when the Server exposes `FindAliasVerbose` on this category.
|
|
120
|
+
*
|
|
121
|
+
* Cheaper than catching {@link AliasNameMethodNotSupportedError}, and reads
|
|
122
|
+
* better when the Client has a fallback path.
|
|
123
|
+
*/
|
|
124
|
+
async supportsVerbose(categoryNodeId = exports.ALIASES_ROOT) {
|
|
125
|
+
return (await this.resolveMethods(categoryNodeId)).findAliasVerbose !== null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* True when the Server exposes the configuration Methods on this category
|
|
129
|
+
* (clauses 6.3.4 and 6.3.5). They are optional and off by default in most
|
|
130
|
+
* Servers.
|
|
131
|
+
*/
|
|
132
|
+
async supportsConfiguration(categoryNodeId = exports.ALIASES_ROOT) {
|
|
133
|
+
const methods = await this.resolveMethods(categoryNodeId);
|
|
134
|
+
return methods.addAliasesToCategory !== null && methods.deleteAliasesFromCategory !== null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The `AliasNameCategoryType` instances Organized directly by a category.
|
|
138
|
+
*
|
|
139
|
+
* Browsing is not needed to *resolve* an alias — `FindAlias` on the root
|
|
140
|
+
* searches recursively — but a Client that wants to show the hierarchy, or
|
|
141
|
+
* to search one branch, needs it.
|
|
142
|
+
*/
|
|
143
|
+
async browseSubCategories(categoryNodeId = exports.ALIASES_ROOT) {
|
|
144
|
+
const result = await this.session.browse({
|
|
145
|
+
nodeId: categoryNodeId,
|
|
146
|
+
browseDirection: node_opcua_data_model_1.BrowseDirection.Forward,
|
|
147
|
+
referenceTypeId: (0, node_opcua_nodeid_1.resolveNodeId)("Organizes"),
|
|
148
|
+
includeSubtypes: true,
|
|
149
|
+
nodeClassMask: node_opcua_data_model_1.NodeClass.Object,
|
|
150
|
+
resultMask: 0x3f
|
|
151
|
+
});
|
|
152
|
+
const references = result.references ?? [];
|
|
153
|
+
const out = [];
|
|
154
|
+
for (const reference of references) {
|
|
155
|
+
// an AliasNameCategoryType instance carries FindAlias; an
|
|
156
|
+
// AliasNameType instance does not, which is how they are told apart
|
|
157
|
+
// without reading TypeDefinition for each
|
|
158
|
+
const methods = await this.resolveMethods(reference.nodeId);
|
|
159
|
+
if (methods.findAlias) {
|
|
160
|
+
out.push({ nodeId: reference.nodeId, browseName: reference.browseName.name ?? "" });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/** Forget every cached Method NodeId. */
|
|
166
|
+
invalidate() {
|
|
167
|
+
this.methodCache.clear();
|
|
168
|
+
this.serverIndexResolver.invalidate();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Resolve every Method of a category in **one** `translateBrowsePath` round
|
|
172
|
+
* trip, and cache the result.
|
|
173
|
+
*
|
|
174
|
+
* Asking for all four at once costs no more than asking for one, and means a
|
|
175
|
+
* Client that later calls `findAliasVerbose` after `findAlias` makes no
|
|
176
|
+
* further round trip.
|
|
177
|
+
*/
|
|
178
|
+
async resolveMethods(categoryNodeId) {
|
|
179
|
+
const key = categoryNodeId.toString();
|
|
180
|
+
const cached = this.methodCache.get(key);
|
|
181
|
+
if (cached) {
|
|
182
|
+
return cached;
|
|
183
|
+
}
|
|
184
|
+
const names = ["FindAlias", "FindAliasVerbose", "AddAliasesToCategory", "DeleteAliasesFromCategory"];
|
|
185
|
+
const results = await this.session.translateBrowsePath(names.map((name) => (0, node_opcua_service_translate_browse_path_1.makeBrowsePath)(categoryNodeId, `/${name}`)));
|
|
186
|
+
const pick = (index) => {
|
|
187
|
+
const result = results[index];
|
|
188
|
+
return result?.statusCode.isGood() && result.targets?.length ? result.targets[0].targetId : null;
|
|
189
|
+
};
|
|
190
|
+
const methods = {
|
|
191
|
+
findAlias: pick(0),
|
|
192
|
+
findAliasVerbose: pick(1),
|
|
193
|
+
addAliasesToCategory: pick(2),
|
|
194
|
+
deleteAliasesFromCategory: pick(3)
|
|
195
|
+
};
|
|
196
|
+
this.methodCache.set(key, methods);
|
|
197
|
+
return methods;
|
|
198
|
+
}
|
|
199
|
+
/** Call one of the two find Methods and return its ExtensionObject array. */
|
|
200
|
+
async callFind(methodName, categoryNodeId, methodId, pattern, referenceTypeFilter) {
|
|
201
|
+
const result = await this.session.call({
|
|
202
|
+
objectId: categoryNodeId,
|
|
203
|
+
methodId,
|
|
204
|
+
inputArguments: [
|
|
205
|
+
{ dataType: node_opcua_variant_1.DataType.String, value: pattern },
|
|
206
|
+
// an omitted filter is the null NodeId, not a null value
|
|
207
|
+
{ dataType: node_opcua_variant_1.DataType.NodeId, value: referenceTypeFilter ?? node_opcua_nodeid_1.NodeId.nullNodeId }
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
if (!result.statusCode.isGood()) {
|
|
211
|
+
throw new errors_js_1.AliasNameCallError(methodName, categoryNodeId, result.statusCode);
|
|
212
|
+
}
|
|
213
|
+
const output = result.outputArguments?.[0];
|
|
214
|
+
const value = output?.value;
|
|
215
|
+
// no match is Good with an empty list (clause 6.3.2 Table 3)
|
|
216
|
+
if (value === null || value === undefined) {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
return Array.isArray(value) ? value : [value];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
exports.ClientAliasSet = ClientAliasSet;
|
|
223
|
+
//# sourceMappingURL=client_alias_set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client_alias_set.js","sourceRoot":"","sources":["../source/client_alias_set.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-alias-name-client
|
|
3
|
+
*/
|
|
4
|
+
import type { NodeId } from "node-opcua-nodeid";
|
|
5
|
+
import type { StatusCode } from "node-opcua-status-code";
|
|
6
|
+
/**
|
|
7
|
+
* The Server does not expose the Method that was asked for.
|
|
8
|
+
*
|
|
9
|
+
* `FindAlias` is MANDATORY on every `AliasNameCategoryType` instance, but
|
|
10
|
+
* `FindAliasVerbose`, `AddAliasesToCategory` and `DeleteAliasesFromCategory` are
|
|
11
|
+
* all optional (OPC 10000-17 clause 6.3). A Server that implements only the
|
|
12
|
+
* mandatory Method is perfectly conformant, so a Client that wants the verbose
|
|
13
|
+
* form must be able to tell "this Server does not offer it" apart from "the call
|
|
14
|
+
* failed".
|
|
15
|
+
*
|
|
16
|
+
* Raised before any call is made — the Method's absence is discovered while
|
|
17
|
+
* resolving NodeIds — so it never surfaces as an unhandled `Bad_NotImplemented`
|
|
18
|
+
* from the wire.
|
|
19
|
+
*/
|
|
20
|
+
export declare class AliasNameMethodNotSupportedError extends Error {
|
|
21
|
+
/** The Method that is missing, by BrowseName. */
|
|
22
|
+
readonly methodName: string;
|
|
23
|
+
/** The category it was looked for on. */
|
|
24
|
+
readonly categoryNodeId: NodeId;
|
|
25
|
+
constructor(methodName: string, categoryNodeId: NodeId);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The Server answered a `FindAlias` call with a bad StatusCode.
|
|
29
|
+
*
|
|
30
|
+
* Carries the code so a caller can distinguish the cases clause 6.3.2 Table 4
|
|
31
|
+
* defines — `Bad_InvalidArgument` for a malformed search pattern,
|
|
32
|
+
* `Bad_ResponseTooLarge` for a result set that needs a narrower filter,
|
|
33
|
+
* `Bad_UserAccessDenied` for a category the session may not read.
|
|
34
|
+
*/
|
|
35
|
+
export declare class AliasNameCallError extends Error {
|
|
36
|
+
readonly statusCode: StatusCode;
|
|
37
|
+
readonly categoryNodeId: NodeId;
|
|
38
|
+
constructor(methodName: string, categoryNodeId: NodeId, statusCode: StatusCode);
|
|
39
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module node-opcua-alias-name-client
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AliasNameCallError = exports.AliasNameMethodNotSupportedError = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* The Server does not expose the Method that was asked for.
|
|
9
|
+
*
|
|
10
|
+
* `FindAlias` is MANDATORY on every `AliasNameCategoryType` instance, but
|
|
11
|
+
* `FindAliasVerbose`, `AddAliasesToCategory` and `DeleteAliasesFromCategory` are
|
|
12
|
+
* all optional (OPC 10000-17 clause 6.3). A Server that implements only the
|
|
13
|
+
* mandatory Method is perfectly conformant, so a Client that wants the verbose
|
|
14
|
+
* form must be able to tell "this Server does not offer it" apart from "the call
|
|
15
|
+
* failed".
|
|
16
|
+
*
|
|
17
|
+
* Raised before any call is made — the Method's absence is discovered while
|
|
18
|
+
* resolving NodeIds — so it never surfaces as an unhandled `Bad_NotImplemented`
|
|
19
|
+
* from the wire.
|
|
20
|
+
*/
|
|
21
|
+
class AliasNameMethodNotSupportedError extends Error {
|
|
22
|
+
/** The Method that is missing, by BrowseName. */
|
|
23
|
+
methodName;
|
|
24
|
+
/** The category it was looked for on. */
|
|
25
|
+
categoryNodeId;
|
|
26
|
+
constructor(methodName, categoryNodeId) {
|
|
27
|
+
super(`the Server does not expose ${methodName} on ${categoryNodeId.toString()}. ` +
|
|
28
|
+
"Only FindAlias is mandatory in OPC 10000-17 clause 6.3; the rest are optional.");
|
|
29
|
+
this.name = "AliasNameMethodNotSupportedError";
|
|
30
|
+
this.methodName = methodName;
|
|
31
|
+
this.categoryNodeId = categoryNodeId;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.AliasNameMethodNotSupportedError = AliasNameMethodNotSupportedError;
|
|
35
|
+
/**
|
|
36
|
+
* The Server answered a `FindAlias` call with a bad StatusCode.
|
|
37
|
+
*
|
|
38
|
+
* Carries the code so a caller can distinguish the cases clause 6.3.2 Table 4
|
|
39
|
+
* defines — `Bad_InvalidArgument` for a malformed search pattern,
|
|
40
|
+
* `Bad_ResponseTooLarge` for a result set that needs a narrower filter,
|
|
41
|
+
* `Bad_UserAccessDenied` for a category the session may not read.
|
|
42
|
+
*/
|
|
43
|
+
class AliasNameCallError extends Error {
|
|
44
|
+
statusCode;
|
|
45
|
+
categoryNodeId;
|
|
46
|
+
constructor(methodName, categoryNodeId, statusCode) {
|
|
47
|
+
super(`${methodName} on ${categoryNodeId.toString()} failed with ${statusCode.toString()}`);
|
|
48
|
+
this.name = "AliasNameCallError";
|
|
49
|
+
this.statusCode = statusCode;
|
|
50
|
+
this.categoryNodeId = categoryNodeId;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.AliasNameCallError = AliasNameCallError;
|
|
54
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../source/errors.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAKH;;;;;;;;;;;;;GAaG;AACH,MAAa,gCAAiC,SAAQ,KAAK;IACvD,iDAAiD;IACjC,UAAU,CAAS;IACnC,yCAAyC;IACzB,cAAc,CAAS;IAEvC,YAAY,UAAkB,EAAE,cAAsB;QAClD,KAAK,CACD,8BAA8B,UAAU,OAAO,cAAc,CAAC,QAAQ,EAAE,IAAI;YACxE,gFAAgF,CACvF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;CACJ;AAfD,4EAeC;AAED;;;;;;;GAOG;AACH,MAAa,kBAAmB,SAAQ,KAAK;IACzB,UAAU,CAAa;IACvB,cAAc,CAAS;IAEvC,YAAY,UAAkB,EAAE,cAAsB,EAAE,UAAsB;QAC1E,KAAK,CAAC,GAAG,UAAU,OAAO,cAAc,CAAC,QAAQ,EAAE,gBAAgB,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;CACJ;AAVD,gDAUC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-alias-name-client
|
|
3
|
+
*
|
|
4
|
+
* Client-side OPC 10000-17 (AliasNames).
|
|
5
|
+
*
|
|
6
|
+
* Resolves the AliasNames **a Server publishes about itself**. Aggregating
|
|
7
|
+
* AliasNames collected from other Servers (Annexes B and C) and the Annex D
|
|
8
|
+
* PubSub change notification are out of scope; {@link ServerIndexResolver}
|
|
9
|
+
* covers the one cross-Server step a Client still has to make, turning the
|
|
10
|
+
* `ServerIndex` of a returned `ExpandedNodeId` into a URI (Annex A).
|
|
11
|
+
*/
|
|
12
|
+
export { ALIASES_ROOT, type ClientAliasEntry, ClientAliasSet, type ClientAliasVerboseEntry, type FindAliasOptions, TAG_VARIABLES, TOPICS } from "./client_alias_set.js";
|
|
13
|
+
export { AliasNameCallError, AliasNameMethodNotSupportedError } from "./errors.js";
|
|
14
|
+
export { LOCAL_SERVER_INDEX, ServerIndexResolver } from "./server_index_resolver.js";
|