node-opcua-alias-name-server 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 +361 -0
- package/dist/add_alias.d.ts +73 -0
- package/dist/add_alias.js +262 -0
- package/dist/add_alias.js.map +1 -0
- package/dist/address_space_alias_store.d.ts +130 -0
- package/dist/address_space_alias_store.js +360 -0
- package/dist/address_space_alias_store.js.map +1 -0
- package/dist/alias_hierarchy.d.ts +45 -0
- package/dist/alias_hierarchy.js +135 -0
- package/dist/alias_hierarchy.js.map +1 -0
- package/dist/alias_index.d.ts +60 -0
- package/dist/alias_index.js +119 -0
- package/dist/alias_index.js.map +1 -0
- package/dist/alias_name_archive.d.ts +45 -0
- package/dist/alias_name_archive.js +75 -0
- package/dist/alias_name_archive.js.map +1 -0
- package/dist/bind_alias_category.d.ts +173 -0
- package/dist/bind_alias_category.js +417 -0
- package/dist/bind_alias_category.js.map +1 -0
- package/dist/bind_configuration_methods.d.ts +44 -0
- package/dist/bind_configuration_methods.js +175 -0
- package/dist/bind_configuration_methods.js.map +1 -0
- package/dist/bind_find_alias.d.ts +61 -0
- package/dist/bind_find_alias.js +227 -0
- package/dist/bind_find_alias.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/install_alias_names.d.ts +229 -0
- package/dist/install_alias_names.js +146 -0
- package/dist/install_alias_names.js.map +1 -0
- package/dist/last_change.d.ts +87 -0
- package/dist/last_change.js +174 -0
- package/dist/last_change.js.map +1 -0
- package/dist/well_known.d.ts +88 -0
- package/dist/well_known.js +93 -0
- package/dist/well_known.js.map +1 -0
- package/package.json +54 -0
- package/source/add_alias.ts +318 -0
- package/source/address_space_alias_store.ts +417 -0
- package/source/alias_hierarchy.ts +141 -0
- package/source/alias_index.ts +127 -0
- package/source/alias_name_archive.ts +84 -0
- package/source/bind_alias_category.ts +546 -0
- package/source/bind_configuration_methods.ts +219 -0
- package/source/bind_find_alias.ts +290 -0
- package/source/index.ts +74 -0
- package/source/install_alias_names.ts +342 -0
- package/source/last_change.ts +201 -0
- package/source/well_known.ts +101 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module node-opcua-alias-name-server
|
|
4
|
+
*
|
|
5
|
+
* Binding the Methods of a single `AliasNameCategoryType` instance, and creating
|
|
6
|
+
* new categories at runtime.
|
|
7
|
+
*
|
|
8
|
+
* This is the one binding path. `installAliasNamesOnAddressSpace` calls
|
|
9
|
+
* {@link bindAliasCategory} in its loop rather than doing the work itself, so a
|
|
10
|
+
* category created after installation cannot end up bound differently from one
|
|
11
|
+
* that was there at install time — or, worse, not bound at all. An unbound
|
|
12
|
+
* MANDATORY `FindAlias` is the exact defect this package exists to remove, and
|
|
13
|
+
* it should not be able to reappear at runtime.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.INSTALLED = void 0;
|
|
17
|
+
exports.bindAliasCategory = bindAliasCategory;
|
|
18
|
+
exports.ensureLastChangeProperty = ensureLastChangeProperty;
|
|
19
|
+
exports.addAliasCategory = addAliasCategory;
|
|
20
|
+
exports.removeAliasCategory = removeAliasCategory;
|
|
21
|
+
exports.findMethodByDeclaration = findMethodByDeclaration;
|
|
22
|
+
exports.ensureOptionalMethod = ensureOptionalMethod;
|
|
23
|
+
exports.getInstalledAliasNames = getInstalledAliasNames;
|
|
24
|
+
exports.setInstalledAliasNames = setInstalledAliasNames;
|
|
25
|
+
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
26
|
+
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
|
|
27
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
28
|
+
const bind_configuration_methods_js_1 = require("./bind_configuration_methods.js");
|
|
29
|
+
const bind_find_alias_js_1 = require("./bind_find_alias.js");
|
|
30
|
+
const last_change_js_1 = require("./last_change.js");
|
|
31
|
+
const well_known_js_1 = require("./well_known.js");
|
|
32
|
+
/**
|
|
33
|
+
* Bind `FindAlias` — and, when `verbose`, `FindAliasVerbose` — on one
|
|
34
|
+
* `AliasNameCategoryType` instance.
|
|
35
|
+
*
|
|
36
|
+
* Safe to call on a category that is already bound: `bindMethod` replaces the
|
|
37
|
+
* handler, and the optional Method is only added when it is missing.
|
|
38
|
+
*
|
|
39
|
+
* Use this for a category created after `installAliasNames` has run. The options
|
|
40
|
+
* that installation used are on {@link InstallAliasNamesResult.bindingOptions},
|
|
41
|
+
* so a caller does not have to reassemble them and risk binding a late category
|
|
42
|
+
* with a different store or a different result cap.
|
|
43
|
+
*/
|
|
44
|
+
function bindAliasCategory(addressSpace, category, options) {
|
|
45
|
+
const findAlias = findMethodByDeclaration(category, well_known_js_1.MethodDeclarations.FindAlias, "FindAlias");
|
|
46
|
+
findAlias?.bindMethod((0, bind_find_alias_js_1.makeFindAliasHandler)(options, false));
|
|
47
|
+
if (options.verbose ?? true) {
|
|
48
|
+
const verbose = ensureOptionalMethod(addressSpace, category, "FindAliasVerbose");
|
|
49
|
+
verbose?.bindMethod((0, bind_find_alias_js_1.makeFindAliasHandler)(options, true));
|
|
50
|
+
}
|
|
51
|
+
if (options.lastChangeProperty ?? true) {
|
|
52
|
+
ensureLastChangeProperty(addressSpace, category);
|
|
53
|
+
}
|
|
54
|
+
// The write surface only appears when asked for (clause 6.3.4 / 6.3.5 are
|
|
55
|
+
// both Optional), and even then every call is denied unless isWriteAllowed
|
|
56
|
+
// says otherwise.
|
|
57
|
+
if (options.configurationMethods) {
|
|
58
|
+
const configurationOptions = {
|
|
59
|
+
store: options.store,
|
|
60
|
+
isWriteAllowed: options.isWriteAllowed,
|
|
61
|
+
onChanged: options.onChanged
|
|
62
|
+
};
|
|
63
|
+
const add = ensureOptionalMethod(addressSpace, category, "AddAliasesToCategory");
|
|
64
|
+
add?.bindMethod((0, bind_configuration_methods_js_1.makeAddAliasesToCategoryHandler)(configurationOptions));
|
|
65
|
+
const remove = ensureOptionalMethod(addressSpace, category, "DeleteAliasesFromCategory");
|
|
66
|
+
remove?.bindMethod((0, bind_configuration_methods_js_1.makeDeleteAliasesFromCategoryHandler)(configurationOptions));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The default NodeId for a new category: a **string** NodeId spelling out its
|
|
71
|
+
* path under `Aliases`, for instance `ns=1;s=Aliases/TagVariables/Unit200`.
|
|
72
|
+
*
|
|
73
|
+
* The obvious alternative — letting the namespace assign the next free numeric
|
|
74
|
+
* id — is wrong here for two reasons.
|
|
75
|
+
*
|
|
76
|
+
* It is **not stable across restarts**. The counter depends on how many other
|
|
77
|
+
* Nodes were created first, so adding one unrelated Variable to a Server shifts
|
|
78
|
+
* every category's NodeId. That silently breaks `LastChange` persistence, which
|
|
79
|
+
* keys on the category NodeId: the restored values no longer match any
|
|
80
|
+
* category, `LastChange` reads 0, and clause 6.3.1 then requires every connected
|
|
81
|
+
* Client to clear a cache that was perfectly valid. A Server-side change with a
|
|
82
|
+
* purely remote symptom.
|
|
83
|
+
*
|
|
84
|
+
* It is also **not diagnosable**. `ns=1;i=1010` in a log or a
|
|
85
|
+
* `FindAliasVerbose` result says nothing; `ns=1;s=Aliases/TagVariables/Unit200`
|
|
86
|
+
* says which category it is without a lookup.
|
|
87
|
+
*
|
|
88
|
+
* The path is unique because two categories cannot share a parent and a
|
|
89
|
+
* BrowseName, and it is derived from the same information every run, so it is
|
|
90
|
+
* the same NodeId every run.
|
|
91
|
+
*/
|
|
92
|
+
function defaultCategoryNodeId(parent, browseName, namespaceIndex) {
|
|
93
|
+
const path = [...categoryPathOf(parent), browseName].join("/");
|
|
94
|
+
return new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.STRING, path, namespaceIndex);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The BrowseNames from the `Aliases` root down to `category`, inclusive.
|
|
98
|
+
*
|
|
99
|
+
* Falls back to the category's own BrowseName when it is not under the root,
|
|
100
|
+
* which keeps the id derivable for a category modelled outside the standard
|
|
101
|
+
* hierarchy.
|
|
102
|
+
*/
|
|
103
|
+
function categoryPathOf(category) {
|
|
104
|
+
const segments = [];
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
let current = category;
|
|
107
|
+
while (current) {
|
|
108
|
+
const key = current.nodeId.toString();
|
|
109
|
+
if (seen.has(key)) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
seen.add(key);
|
|
113
|
+
segments.unshift(current.browseName.name ?? key);
|
|
114
|
+
if (key === well_known_js_1.WellKnownCategories.Aliases.toString()) {
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
const parents = current.findReferencesExAsObject("HierarchicalReferences", node_opcua_data_model_1.BrowseDirection.Inverse);
|
|
118
|
+
const next = parents.find((p) => p.nodeClass === node_opcua_data_model_1.NodeClass.Object);
|
|
119
|
+
current = next ? next : null;
|
|
120
|
+
}
|
|
121
|
+
return segments;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Ensure a category has a `LastChange` Property.
|
|
125
|
+
*
|
|
126
|
+
* `LastChange` is Optional on `AliasNameCategoryType` and the shipped nodeset
|
|
127
|
+
* instantiates it only on the `Aliases` root, which clause 9.2 makes mandatory.
|
|
128
|
+
* Adding it to every category is conformant — Optional means may, not must not —
|
|
129
|
+
* and it is what makes the clause 6.3.1 rollup observable: without it, a Client
|
|
130
|
+
* watching one branch has nothing to watch.
|
|
131
|
+
*/
|
|
132
|
+
function ensureLastChangeProperty(addressSpace, category) {
|
|
133
|
+
const existing = category.getPropertyByName(last_change_js_1.LAST_CHANGE_BROWSE_NAME);
|
|
134
|
+
if (existing) {
|
|
135
|
+
return existing;
|
|
136
|
+
}
|
|
137
|
+
const namespace = addressSpace.getNamespace(category.nodeId.namespace === 0 ? addressSpace.getOwnNamespace().index : category.nodeId.namespace);
|
|
138
|
+
return namespace.addVariable({
|
|
139
|
+
propertyOf: category,
|
|
140
|
+
browseName: last_change_js_1.LAST_CHANGE_BROWSE_NAME,
|
|
141
|
+
// VersionTime (i=20998) is a UInt32 subtype, not a DateTime
|
|
142
|
+
dataType: well_known_js_1.VERSION_TIME_DATA_TYPE,
|
|
143
|
+
minimumSamplingInterval: 1000,
|
|
144
|
+
value: { dataType: node_opcua_variant_1.DataType.UInt32, value: 0 }
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Create a vendor `AliasNameCategoryType` instance under `parent` **and bind it**.
|
|
149
|
+
*
|
|
150
|
+
* Creating one by hand means instantiating the type, wiring the `Organizes`
|
|
151
|
+
* reference and then remembering to bind — and a category whose `FindAlias` is
|
|
152
|
+
* unbound fails conformance silently. This does all three.
|
|
153
|
+
*
|
|
154
|
+
* When `installAliasNames` has already run on this address space, the binding
|
|
155
|
+
* options it used are reused unless overridden, so a category added at runtime
|
|
156
|
+
* behaves exactly like one that was present at install time. Pass a `store`
|
|
157
|
+
* explicitly if installation has not run yet.
|
|
158
|
+
*/
|
|
159
|
+
function addAliasCategory(addressSpace, parent, browseName, options) {
|
|
160
|
+
const parentNode = coerceCategoryNode(addressSpace, parent);
|
|
161
|
+
const categoryType = resolveCategoryType(addressSpace, options?.categoryType);
|
|
162
|
+
const namespace = addressSpace.getNamespace(options?.namespaceIndex ?? addressSpace.getOwnNamespace().index);
|
|
163
|
+
const nodeId = options?.nodeId ?? defaultCategoryNodeId(parentNode, browseName, namespace.index);
|
|
164
|
+
if (addressSpace.findNode(nodeId)) {
|
|
165
|
+
throw new Error(`addAliasCategory: ${nodeId.toString()} already exists. A category's default NodeId is derived from its ` +
|
|
166
|
+
"path under Aliases, so this means a category of the same name already exists under the same parent.");
|
|
167
|
+
}
|
|
168
|
+
const category = categoryType.instantiate({
|
|
169
|
+
browseName: { name: browseName, namespaceIndex: namespace.index },
|
|
170
|
+
nodeId,
|
|
171
|
+
organizedBy: parentNode,
|
|
172
|
+
namespace
|
|
173
|
+
});
|
|
174
|
+
if (options?.rolePermissions) {
|
|
175
|
+
// instantiate() does not take them, so they are applied after
|
|
176
|
+
category.setRolePermissions(options.rolePermissions);
|
|
177
|
+
}
|
|
178
|
+
const bindingOptions = resolveBindingOptions(addressSpace, options);
|
|
179
|
+
if (bindingOptions) {
|
|
180
|
+
bindAliasCategory(addressSpace, category, bindingOptions);
|
|
181
|
+
}
|
|
182
|
+
// clause 6.3.1: "The last time an AliasNameCategory was added or deleted"
|
|
183
|
+
notifyCategoryChanged(addressSpace, parentNode.nodeId);
|
|
184
|
+
return category;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Resolve the ObjectType to instantiate, defaulting to `AliasNameCategoryType`.
|
|
188
|
+
*
|
|
189
|
+
* A subtype is accepted: discovery matches on "is this an instance of
|
|
190
|
+
* AliasNameCategoryType *or a subtype*", and binding looks the Methods up by
|
|
191
|
+
* MethodDeclarationId, so neither cares which exact type was used.
|
|
192
|
+
*/
|
|
193
|
+
function resolveCategoryType(addressSpace, categoryType) {
|
|
194
|
+
const base = addressSpace.findObjectType(well_known_js_1.ALIAS_NAME_CATEGORY_TYPE);
|
|
195
|
+
if (!base) {
|
|
196
|
+
throw new Error("addAliasCategory: AliasNameCategoryType (i=23456) is not in the address space");
|
|
197
|
+
}
|
|
198
|
+
if (!categoryType) {
|
|
199
|
+
return base;
|
|
200
|
+
}
|
|
201
|
+
const resolved = categoryType instanceof node_opcua_nodeid_1.NodeId ? addressSpace.findObjectType(categoryType) : categoryType;
|
|
202
|
+
if (!resolved) {
|
|
203
|
+
throw new Error(`addAliasCategory: unknown ObjectType ${String(categoryType)}`);
|
|
204
|
+
}
|
|
205
|
+
if (resolved.nodeId.value !== base.nodeId.value && !resolved.isSubtypeOf(base)) {
|
|
206
|
+
throw new Error(`addAliasCategory: ${resolved.browseName.toString()} is not AliasNameCategoryType or a subtype of it`);
|
|
207
|
+
}
|
|
208
|
+
return resolved;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Remove a category, and decide what happens to what it Organizes.
|
|
212
|
+
*
|
|
213
|
+
* The specification does not say, so the rule is stated here rather than left to
|
|
214
|
+
* whatever `deleteNode` happens to do:
|
|
215
|
+
*
|
|
216
|
+
* - **`reparent`** (the default) moves the category's aliases and subcategories
|
|
217
|
+
* to its parent before deleting it. Nothing disappears, so a Client that had
|
|
218
|
+
* resolved an alias keeps resolving it — the alias Object keeps its NodeId,
|
|
219
|
+
* and clause 6.2 makes a NodeId change mean "this is a different alias".
|
|
220
|
+
* - **`cascade`** deletes them with it. Correct when the category *is* the
|
|
221
|
+
* thing being retired, such as a tenant being removed.
|
|
222
|
+
*
|
|
223
|
+
* Refuses to remove one of the three well-known categories, which clause 9
|
|
224
|
+
* requires a Server to have.
|
|
225
|
+
*
|
|
226
|
+
* @returns the aliases and subcategories that were re-parented, or deleted.
|
|
227
|
+
*/
|
|
228
|
+
function removeAliasCategory(addressSpace, category, options) {
|
|
229
|
+
const node = coerceCategoryNode(addressSpace, category);
|
|
230
|
+
for (const wellKnown of Object.values(well_known_js_1.WellKnownCategories)) {
|
|
231
|
+
if (wellKnown.value === node.nodeId.value && wellKnown.namespace === node.nodeId.namespace) {
|
|
232
|
+
throw new Error(`removeAliasCategory: ${node.browseName.toString()} is a well-known category that ` +
|
|
233
|
+
"OPC 10000-17 clause 9 requires the Server to have");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const parents = node.findReferencesExAsObject("HierarchicalReferences", node_opcua_data_model_1.BrowseDirection.Inverse);
|
|
237
|
+
// Organizes only, not every hierarchical reference. A category's Methods are
|
|
238
|
+
// HasComponent children that belong to it and must go with it; re-parenting
|
|
239
|
+
// those would leave the parent with a second FindAlias.
|
|
240
|
+
const childReferences = node.findReferencesEx("Organizes", node_opcua_data_model_1.BrowseDirection.Forward);
|
|
241
|
+
const orphans = options?.orphans ?? "reparent";
|
|
242
|
+
const moved = [];
|
|
243
|
+
const deleted = [];
|
|
244
|
+
if (orphans === "reparent") {
|
|
245
|
+
const parent = parents[0];
|
|
246
|
+
if (!parent) {
|
|
247
|
+
throw new Error(`removeAliasCategory: ${node.browseName.toString()} has no parent to re-parent its contents to; ` +
|
|
248
|
+
'pass { orphans: "cascade" } to delete them instead');
|
|
249
|
+
}
|
|
250
|
+
for (const reference of childReferences) {
|
|
251
|
+
parent.addReference({ referenceType: reference.referenceType, nodeId: reference.nodeId });
|
|
252
|
+
// Detach before deleting: deleteNode cascades through Organizes, so
|
|
253
|
+
// a child still referenced here would be deleted along with the
|
|
254
|
+
// category despite having just been re-parented.
|
|
255
|
+
node.removeReference({ referenceType: reference.referenceType, nodeId: reference.nodeId });
|
|
256
|
+
moved.push(reference.nodeId);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
for (const reference of childReferences) {
|
|
261
|
+
deleted.push(reference.nodeId);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// whatever is still attached goes with it
|
|
265
|
+
addressSpace.deleteNode(node.nodeId);
|
|
266
|
+
// clause 6.3.1: a category was deleted
|
|
267
|
+
for (const parent of parents) {
|
|
268
|
+
notifyCategoryChanged(addressSpace, parent.nodeId);
|
|
269
|
+
}
|
|
270
|
+
return { moved, deleted };
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Tell the installed `LastChange` tracker that a category's contents changed.
|
|
274
|
+
*
|
|
275
|
+
* Fire and forget: the Property is written synchronously and only the
|
|
276
|
+
* persistence write is async, so a failure to persist must not fail the
|
|
277
|
+
* caller's structural change.
|
|
278
|
+
*/
|
|
279
|
+
function notifyCategoryChanged(addressSpace, categoryNodeId) {
|
|
280
|
+
const installed = getInstalledAliasNames(addressSpace);
|
|
281
|
+
void installed?.lastChange?.touch(categoryNodeId);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Merge explicit options over whatever installation recorded, or return null
|
|
285
|
+
* when there is nothing to bind with.
|
|
286
|
+
*/
|
|
287
|
+
function resolveBindingOptions(addressSpace, options) {
|
|
288
|
+
const installed = getInstalledAliasNames(addressSpace);
|
|
289
|
+
const inherited = installed?.bindingOptions;
|
|
290
|
+
const store = options?.store ?? inherited?.store;
|
|
291
|
+
if (!store) {
|
|
292
|
+
// nothing to bind against yet; installAliasNames will pick this category
|
|
293
|
+
// up when it runs, since it is Organized below its parent
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
// Inherit by spreading rather than by listing fields. Cherry-picking meant
|
|
297
|
+
// every new binding option had to be remembered here too, and forgetting one
|
|
298
|
+
// let a category created at runtime diverge from an installed one - silently,
|
|
299
|
+
// and in whichever direction was least safe.
|
|
300
|
+
const merged = {
|
|
301
|
+
...inherited,
|
|
302
|
+
store,
|
|
303
|
+
maxResults: options?.maxResults ?? inherited?.maxResults ?? well_known_js_1.DEFAULT_MAX_RESULTS
|
|
304
|
+
};
|
|
305
|
+
// Only keys the caller actually supplied override the inherited value; an
|
|
306
|
+
// absent key must not read as "false".
|
|
307
|
+
for (const key of Object.keys(options ?? {})) {
|
|
308
|
+
const value = options?.[key];
|
|
309
|
+
if (value === undefined ||
|
|
310
|
+
key === "namespaceIndex" ||
|
|
311
|
+
key === "nodeId" ||
|
|
312
|
+
key === "categoryType" ||
|
|
313
|
+
key === "rolePermissions") {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
Object.assign(merged, { [key]: value });
|
|
317
|
+
}
|
|
318
|
+
return merged;
|
|
319
|
+
}
|
|
320
|
+
/** Accept a category node or its NodeId. */
|
|
321
|
+
function coerceCategoryNode(addressSpace, node) {
|
|
322
|
+
if (!(node instanceof node_opcua_nodeid_1.NodeId)) {
|
|
323
|
+
return node;
|
|
324
|
+
}
|
|
325
|
+
const found = addressSpace.findNode(node);
|
|
326
|
+
if (!found || found.nodeClass !== node_opcua_data_model_1.NodeClass.Object) {
|
|
327
|
+
throw new Error(`addAliasCategory: ${node.toString()} is not an Object in this address space`);
|
|
328
|
+
}
|
|
329
|
+
return found;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Find a Method on a category by its MethodDeclarationId, falling back to the
|
|
333
|
+
* BrowseName.
|
|
334
|
+
*
|
|
335
|
+
* The declaration id is the reliable key: a Server may publish the Method under
|
|
336
|
+
* a localised DisplayName, and the BrowseName is only unique within the
|
|
337
|
+
* namespace. The fallback covers instances built in code, which do not always
|
|
338
|
+
* carry a `methodDeclarationId`.
|
|
339
|
+
*/
|
|
340
|
+
function findMethodByDeclaration(category, declarationId, browseName) {
|
|
341
|
+
for (const component of category.getComponents()) {
|
|
342
|
+
if (component.nodeClass !== node_opcua_data_model_1.NodeClass.Method) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const method = component;
|
|
346
|
+
if (method.methodDeclarationId && method.methodDeclarationId.value === declarationId.value) {
|
|
347
|
+
return method;
|
|
348
|
+
}
|
|
349
|
+
if (method.browseName.name === browseName) {
|
|
350
|
+
return method;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Ensure an optional Method exists on a category, adding it when the nodeset
|
|
357
|
+
* only declared it on the type.
|
|
358
|
+
*
|
|
359
|
+
* The shipped `Opc.Ua.NodeSet2.xml` declares `FindAliasVerbose`,
|
|
360
|
+
* `AddAliasesToCategory` and `DeleteAliasesFromCategory` on
|
|
361
|
+
* `AliasNameCategoryType` but instantiates none of them on `Aliases`,
|
|
362
|
+
* `TagVariables` or `Topics`. Upstream nonetheless reserves fixed NodeIds for
|
|
363
|
+
* those instances, so where one exists it is used in preference to a
|
|
364
|
+
* server-assigned id; an aggregating Server then sees the NodeId it expects.
|
|
365
|
+
*/
|
|
366
|
+
function ensureOptionalMethod(addressSpace, category, name) {
|
|
367
|
+
const declarationId = well_known_js_1.MethodDeclarations[name];
|
|
368
|
+
const existing = findMethodByDeclaration(category, declarationId, name);
|
|
369
|
+
if (existing) {
|
|
370
|
+
return existing;
|
|
371
|
+
}
|
|
372
|
+
const declaration = addressSpace.findNode(declarationId);
|
|
373
|
+
if (!declaration || declaration.nodeClass !== node_opcua_data_model_1.NodeClass.Method) {
|
|
374
|
+
// an address space whose nodeset predates the optional Methods
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
const reservedNodeId = reservedMethodNodeId(category.nodeId, name);
|
|
378
|
+
// a reserved id already taken by something else means the address space is
|
|
379
|
+
// not what we think it is; fall back to a server-assigned id rather than
|
|
380
|
+
// colliding
|
|
381
|
+
const nodeId = reservedNodeId && !addressSpace.findNode(reservedNodeId) ? reservedNodeId : undefined;
|
|
382
|
+
return declaration.clone({
|
|
383
|
+
namespace: addressSpace.getNamespace(category.nodeId.namespace),
|
|
384
|
+
nodeId,
|
|
385
|
+
componentOf: category,
|
|
386
|
+
methodDeclarationId: declarationId
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/** The NodeId OPC 10000-17 reserves for an optional Method on a well-known category. */
|
|
390
|
+
function reservedMethodNodeId(categoryNodeId, name) {
|
|
391
|
+
for (const [key, wellKnownId] of Object.entries(well_known_js_1.WellKnownCategories)) {
|
|
392
|
+
if (wellKnownId.value === categoryNodeId.value && wellKnownId.namespace === categoryNodeId.namespace) {
|
|
393
|
+
return well_known_js_1.WellKnownOptionalMethods[key][name];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Marks an address space as already carrying AliasName bindings, so a second
|
|
400
|
+
* `installAliasNames` is a no-op rather than a double binding.
|
|
401
|
+
*/
|
|
402
|
+
exports.INSTALLED = Symbol.for("node-opcua-alias-name-server.installed");
|
|
403
|
+
/**
|
|
404
|
+
* What `installAliasNames` recorded on this address space, or undefined if it
|
|
405
|
+
* has not run.
|
|
406
|
+
*
|
|
407
|
+
* Exposed so a caller can rebind a late category with exactly the options
|
|
408
|
+
* installation used, without having to keep the install result around.
|
|
409
|
+
*/
|
|
410
|
+
function getInstalledAliasNames(addressSpace) {
|
|
411
|
+
return addressSpace[exports.INSTALLED];
|
|
412
|
+
}
|
|
413
|
+
/** Record the installation on the address space. */
|
|
414
|
+
function setInstalledAliasNames(addressSpace, value) {
|
|
415
|
+
addressSpace[exports.INSTALLED] = value;
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=bind_alias_category.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind_alias_category.js","sourceRoot":"","sources":["../source/bind_alias_category.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module node-opcua-alias-name-server
|
|
3
|
+
*
|
|
4
|
+
* `AddAliasesToCategory` (clause 6.3.4) and `DeleteAliasesFromCategory`
|
|
5
|
+
* (clause 6.3.5) — the *AliasName Configuration Support* facet, CU 5874.
|
|
6
|
+
*
|
|
7
|
+
* Both report **per item**: the Method itself succeeds and an `ErrorCodes` array
|
|
8
|
+
* parallel to `AliasNames` says what happened to each one. A single bad entry
|
|
9
|
+
* does not fail the call, which is why the store interface returns
|
|
10
|
+
* `StatusCode[]` rather than throwing.
|
|
11
|
+
*/
|
|
12
|
+
import type { ISessionContext, UAMethod } from "node-opcua-address-space-base";
|
|
13
|
+
import type { IAliasStore } from "node-opcua-alias-name-common";
|
|
14
|
+
import { type NodeId } from "node-opcua-nodeid";
|
|
15
|
+
import type { CallMethodResultOptions } from "node-opcua-service-call";
|
|
16
|
+
import { type Variant } from "node-opcua-variant";
|
|
17
|
+
export interface ConfigurationBindingOptions {
|
|
18
|
+
/** The store that performs the mutation. Must implement `add` / `delete`. */
|
|
19
|
+
store: IAliasStore;
|
|
20
|
+
/**
|
|
21
|
+
* Write gate (clause 6.3.4 Table 11 / 6.3.5 Table 15). **Defaults to denying
|
|
22
|
+
* everyone** — the write surface is the one place a permissive default would
|
|
23
|
+
* be a security defect rather than a convenience.
|
|
24
|
+
*/
|
|
25
|
+
isWriteAllowed?: (context: ISessionContext, categoryNodeId: NodeId) => boolean | Promise<boolean>;
|
|
26
|
+
/** Called after a successful mutation so `LastChange` can move. */
|
|
27
|
+
onChanged?: (categoryNodeId: NodeId) => void | Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Handler for `AddAliasesToCategory` (clause 6.3.4).
|
|
31
|
+
*
|
|
32
|
+
* Table 11 governs the *call*: `Bad_InvalidArgument` when an argument is the
|
|
33
|
+
* wrong type, when the arrays other than `TargetServers` differ in length, or
|
|
34
|
+
* when all arrays are empty. Table 10 governs each *item*.
|
|
35
|
+
*/
|
|
36
|
+
export declare function makeAddAliasesToCategoryHandler(options: ConfigurationBindingOptions): (this: UAMethod, inputArguments: Variant[], context: ISessionContext) => Promise<CallMethodResultOptions>;
|
|
37
|
+
/**
|
|
38
|
+
* Handler for `DeleteAliasesFromCategory` (clause 6.3.5).
|
|
39
|
+
*
|
|
40
|
+
* Table 15 governs the call: unlike Add, **every** array must be the same
|
|
41
|
+
* length — "the size of the arrays for all arguments is not the same", with no
|
|
42
|
+
* exception, because there is no `TargetServers` here.
|
|
43
|
+
*/
|
|
44
|
+
export declare function makeDeleteAliasesFromCategoryHandler(options: ConfigurationBindingOptions): (this: UAMethod, inputArguments: Variant[], context: ISessionContext) => Promise<CallMethodResultOptions>;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module node-opcua-alias-name-server
|
|
4
|
+
*
|
|
5
|
+
* `AddAliasesToCategory` (clause 6.3.4) and `DeleteAliasesFromCategory`
|
|
6
|
+
* (clause 6.3.5) — the *AliasName Configuration Support* facet, CU 5874.
|
|
7
|
+
*
|
|
8
|
+
* Both report **per item**: the Method itself succeeds and an `ErrorCodes` array
|
|
9
|
+
* parallel to `AliasNames` says what happened to each one. A single bad entry
|
|
10
|
+
* does not fail the call, which is why the store interface returns
|
|
11
|
+
* `StatusCode[]` rather than throwing.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.makeAddAliasesToCategoryHandler = makeAddAliasesToCategoryHandler;
|
|
15
|
+
exports.makeDeleteAliasesFromCategoryHandler = makeDeleteAliasesFromCategoryHandler;
|
|
16
|
+
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
|
|
17
|
+
const node_opcua_status_code_1 = require("node-opcua-status-code");
|
|
18
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
19
|
+
const well_known_js_1 = require("./well_known.js");
|
|
20
|
+
/** Read a String[] argument, tolerating null for "empty". */
|
|
21
|
+
function readStringArray(inputArguments, index) {
|
|
22
|
+
const value = inputArguments?.[index]?.value;
|
|
23
|
+
if (value === null || value === undefined) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
if (!Array.isArray(value)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return value.map((v) => (typeof v === "string" ? v : String(v)));
|
|
30
|
+
}
|
|
31
|
+
/** Read an ExpandedNodeId[] argument, tolerating null for "empty". */
|
|
32
|
+
function readNodeIdArray(inputArguments, index) {
|
|
33
|
+
const value = inputArguments?.[index]?.value;
|
|
34
|
+
if (value === null || value === undefined) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
if (!Array.isArray(value)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
/** Build the OutputArguments Variant for an ErrorCodes array. */
|
|
43
|
+
function errorCodesResult(codes) {
|
|
44
|
+
return {
|
|
45
|
+
statusCode: node_opcua_status_code_1.StatusCodes.Good,
|
|
46
|
+
outputArguments: [
|
|
47
|
+
{
|
|
48
|
+
dataType: node_opcua_variant_1.DataType.StatusCode,
|
|
49
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
50
|
+
value: codes
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Handler for `AddAliasesToCategory` (clause 6.3.4).
|
|
57
|
+
*
|
|
58
|
+
* Table 11 governs the *call*: `Bad_InvalidArgument` when an argument is the
|
|
59
|
+
* wrong type, when the arrays other than `TargetServers` differ in length, or
|
|
60
|
+
* when all arrays are empty. Table 10 governs each *item*.
|
|
61
|
+
*/
|
|
62
|
+
function makeAddAliasesToCategoryHandler(options) {
|
|
63
|
+
return async function addAliasesToCategoryHandler(inputArguments, context) {
|
|
64
|
+
const category = this.parent;
|
|
65
|
+
if (!category) {
|
|
66
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInternalError };
|
|
67
|
+
}
|
|
68
|
+
// clause 6.3.4 Table 11
|
|
69
|
+
if (!(await isWriteAllowed(options, context, category.nodeId))) {
|
|
70
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadUserAccessDenied };
|
|
71
|
+
}
|
|
72
|
+
const aliasNames = readStringArray(inputArguments, 0);
|
|
73
|
+
const targetNodes = readNodeIdArray(inputArguments, 1);
|
|
74
|
+
const targetServers = readStringArray(inputArguments, 2);
|
|
75
|
+
const targetReferenceTypeRaw = inputArguments?.[3]?.value;
|
|
76
|
+
if (aliasNames === null || targetNodes === null || targetServers === null) {
|
|
77
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
78
|
+
}
|
|
79
|
+
// "the size of the arrays for all arguments except TargetServers is not
|
|
80
|
+
// the same" - TargetServers is excluded because Table 9 lets it be null
|
|
81
|
+
// or empty to mean "all local"
|
|
82
|
+
if (aliasNames.length !== targetNodes.length) {
|
|
83
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
84
|
+
}
|
|
85
|
+
// "or if all arrays are empty"
|
|
86
|
+
if (aliasNames.length === 0) {
|
|
87
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
88
|
+
}
|
|
89
|
+
if (targetServers.length !== 0 && targetServers.length !== aliasNames.length) {
|
|
90
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
91
|
+
}
|
|
92
|
+
// Table 9: "If null, it defaults to AliasFor."
|
|
93
|
+
const referenceTypeId = targetReferenceTypeRaw instanceof node_opcua_nodeid_1.NodeId && !targetReferenceTypeRaw.isEmpty() ? targetReferenceTypeRaw : well_known_js_1.ALIAS_FOR;
|
|
94
|
+
const entries = aliasNames.map((aliasName, i) => {
|
|
95
|
+
// Table 9: "The ServerIndex in the ExpandedNodeId shall be ignored
|
|
96
|
+
// and the TargetServers Uri shall be used."
|
|
97
|
+
const serverUri = targetServers[i] ? targetServers[i] : null;
|
|
98
|
+
return {
|
|
99
|
+
aliasName,
|
|
100
|
+
referencedNodes: [targetNodes[i]],
|
|
101
|
+
serverUris: [serverUri],
|
|
102
|
+
categoryNodeId: category.nodeId,
|
|
103
|
+
referenceTypeIds: [referenceTypeId]
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
if (!options.store.add) {
|
|
107
|
+
// a read-only store: every item is unsupported, but the call itself
|
|
108
|
+
// succeeded in reporting that
|
|
109
|
+
return errorCodesResult(entries.map(() => node_opcua_status_code_1.StatusCodes.BadNotSupported));
|
|
110
|
+
}
|
|
111
|
+
const codes = await options.store.add(category.nodeId, entries);
|
|
112
|
+
if (codes.some((code) => code.isGood())) {
|
|
113
|
+
await options.onChanged?.(category.nodeId);
|
|
114
|
+
}
|
|
115
|
+
return errorCodesResult(codes);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Handler for `DeleteAliasesFromCategory` (clause 6.3.5).
|
|
120
|
+
*
|
|
121
|
+
* Table 15 governs the call: unlike Add, **every** array must be the same
|
|
122
|
+
* length — "the size of the arrays for all arguments is not the same", with no
|
|
123
|
+
* exception, because there is no `TargetServers` here.
|
|
124
|
+
*/
|
|
125
|
+
function makeDeleteAliasesFromCategoryHandler(options) {
|
|
126
|
+
return async function deleteAliasesFromCategoryHandler(inputArguments, context) {
|
|
127
|
+
const category = this.parent;
|
|
128
|
+
if (!category) {
|
|
129
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInternalError };
|
|
130
|
+
}
|
|
131
|
+
if (!(await isWriteAllowed(options, context, category.nodeId))) {
|
|
132
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadUserAccessDenied };
|
|
133
|
+
}
|
|
134
|
+
const aliasNames = readStringArray(inputArguments, 0);
|
|
135
|
+
const targetNodes = readNodeIdArray(inputArguments, 1);
|
|
136
|
+
if (aliasNames === null || targetNodes === null) {
|
|
137
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
138
|
+
}
|
|
139
|
+
if (aliasNames.length === 0) {
|
|
140
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
141
|
+
}
|
|
142
|
+
// Table 13: "The length of each of the arrays shall be the same." A null
|
|
143
|
+
// TargetNodes array is the documented way to say "every target", so an
|
|
144
|
+
// empty array is accepted and expanded.
|
|
145
|
+
if (targetNodes.length !== 0 && targetNodes.length !== aliasNames.length) {
|
|
146
|
+
return { statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument };
|
|
147
|
+
}
|
|
148
|
+
const entries = aliasNames.map((aliasName, i) => {
|
|
149
|
+
// "If the TargetNodes array entry is null or empty, all AliasNames
|
|
150
|
+
// with the provided name are deleted from the AliasNameCategory."
|
|
151
|
+
const target = targetNodes[i];
|
|
152
|
+
const referencedNodes = target && !target.isEmpty() ? [target] : [];
|
|
153
|
+
return { aliasName, referencedNodes };
|
|
154
|
+
});
|
|
155
|
+
if (!options.store.delete) {
|
|
156
|
+
return errorCodesResult(entries.map(() => node_opcua_status_code_1.StatusCodes.BadNotSupported));
|
|
157
|
+
}
|
|
158
|
+
const codes = await options.store.delete(category.nodeId, entries);
|
|
159
|
+
if (codes.some((code) => code.isGood())) {
|
|
160
|
+
await options.onChanged?.(category.nodeId);
|
|
161
|
+
}
|
|
162
|
+
return errorCodesResult(codes);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/** The write gate, defaulting to deny. */
|
|
166
|
+
async function isWriteAllowed(options, context, categoryNodeId) {
|
|
167
|
+
if (!options.isWriteAllowed) {
|
|
168
|
+
// Writing is off unless the Server says who may do it. OPC 10000-17
|
|
169
|
+
// defines no security model at all, so there is no safe default rule to
|
|
170
|
+
// fall back on - only a safe default answer.
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
return await options.isWriteAllowed(context, categoryNodeId);
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=bind_configuration_methods.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind_configuration_methods.js","sourceRoot":"","sources":["../source/bind_configuration_methods.ts"],"names":[],"mappings":"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"}
|