node-opcua-address-space 2.181.1 → 2.182.2
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/api/helpers/ensure_secure_access.ts +53 -2
- package/api/index.ts +30 -1
- package/api/loader/generateAddressSpaceRaw.ts +44 -139
- package/api/loader/load_nodeset2.ts +5 -0
- package/api/loader/narrow_instance_datatypes.ts +264 -0
- package/api/loader/nodeset_builtin_formats.ts +143 -0
- package/api/loader/nodeset_format.ts +153 -0
- package/api/loader/nodeset_image.ts +37 -4
- package/api/loader/nodeset_image_codec.ts +153 -34
- package/api/loader/nodeset_record.ts +26 -2
- package/api/loader/nodeset_record_applier.ts +54 -3
- package/api/loader/nodeset_records_to_xml.ts +620 -0
- package/api/loader/nodeset_source.ts +185 -26
- package/api/loader/nodeset_to_image.ts +16 -5
- package/api/loader/nodeset_xml_header.ts +119 -0
- package/api/loader/nodeset_xml_primitives.ts +209 -0
- package/api/loader/nodeset_xml_producer.ts +61 -2
- package/api/loader/parsers/variant_parser.ts +9 -0
- package/bin/nodeset_equivalence.js +750 -0
- package/bin/nodeset_tool_common.js +72 -0
- package/bin/opcua-nodeset-image.js +93 -103
- package/bin/opcua-nodeset-live.js +139 -0
- package/dist/api/helpers/ensure_secure_access.d.ts +20 -0
- package/dist/api/helpers/ensure_secure_access.js +39 -0
- package/dist/api/helpers/ensure_secure_access.js.map +1 -1
- package/dist/api/index.d.ts +7 -2
- package/dist/api/index.js +21 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/loader/generateAddressSpaceRaw.d.ts +1 -7
- package/dist/api/loader/generateAddressSpaceRaw.js +32 -125
- package/dist/api/loader/generateAddressSpaceRaw.js.map +1 -1
- package/dist/api/loader/load_nodeset2.js +4 -0
- package/dist/api/loader/load_nodeset2.js.map +1 -1
- package/dist/api/loader/narrow_instance_datatypes.d.ts +30 -0
- package/dist/api/loader/narrow_instance_datatypes.js +217 -0
- package/dist/api/loader/narrow_instance_datatypes.js.map +1 -0
- package/dist/api/loader/nodeset_builtin_formats.d.ts +27 -0
- package/dist/api/loader/nodeset_builtin_formats.js +133 -0
- package/dist/api/loader/nodeset_builtin_formats.js.map +1 -0
- package/dist/api/loader/nodeset_format.d.ts +123 -0
- package/dist/api/loader/nodeset_format.js +63 -0
- package/dist/api/loader/nodeset_format.js.map +1 -0
- package/dist/api/loader/nodeset_image.d.ts +17 -1
- package/dist/api/loader/nodeset_image.js +32 -4
- package/dist/api/loader/nodeset_image.js.map +1 -1
- package/dist/api/loader/nodeset_image_codec.d.ts +4 -0
- package/dist/api/loader/nodeset_image_codec.js +142 -53
- package/dist/api/loader/nodeset_image_codec.js.map +1 -1
- package/dist/api/loader/nodeset_record.d.ts +26 -2
- package/dist/api/loader/nodeset_record.js +11 -2
- package/dist/api/loader/nodeset_record.js.map +1 -1
- package/dist/api/loader/nodeset_record_applier.js +52 -3
- package/dist/api/loader/nodeset_record_applier.js.map +1 -1
- package/dist/api/loader/nodeset_records_to_xml.d.ts +16 -0
- package/dist/api/loader/nodeset_records_to_xml.js +536 -0
- package/dist/api/loader/nodeset_records_to_xml.js.map +1 -0
- package/dist/api/loader/nodeset_source.d.ts +68 -7
- package/dist/api/loader/nodeset_source.js +157 -20
- package/dist/api/loader/nodeset_source.js.map +1 -1
- package/dist/api/loader/nodeset_to_image.d.ts +4 -4
- package/dist/api/loader/nodeset_to_image.js +14 -4
- package/dist/api/loader/nodeset_to_image.js.map +1 -1
- package/dist/api/loader/nodeset_xml_header.d.ts +22 -0
- package/dist/api/loader/nodeset_xml_header.js +113 -0
- package/dist/api/loader/nodeset_xml_header.js.map +1 -0
- package/dist/api/loader/nodeset_xml_primitives.d.ts +37 -0
- package/dist/api/loader/nodeset_xml_primitives.js +196 -0
- package/dist/api/loader/nodeset_xml_primitives.js.map +1 -0
- package/dist/api/loader/nodeset_xml_producer.js +56 -1
- package/dist/api/loader/nodeset_xml_producer.js.map +1 -1
- package/dist/api/loader/parsers/variant_parser.js +7 -0
- package/dist/api/loader/parsers/variant_parser.js.map +1 -1
- package/dist/impl/_instantiate_helpers.js +1 -0
- package/dist/impl/_instantiate_helpers.js.map +1 -1
- package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js +4 -0
- package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
- package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js +14 -0
- package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js.map +1 -1
- package/dist/impl/base_node_impl.d.ts +9 -0
- package/dist/impl/base_node_impl.js +11 -0
- package/dist/impl/base_node_impl.js.map +1 -1
- package/dist/impl/base_node_private.js +67 -97
- package/dist/impl/base_node_private.js.map +1 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js +5 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/impl/nodeset_tools/nodeset_to_records.js +61 -15
- package/dist/impl/nodeset_tools/nodeset_to_records.js.map +1 -1
- package/dist/impl/nodeset_tools/nodeset_to_xml.d.ts +1 -8
- package/dist/impl/nodeset_tools/nodeset_to_xml.js +174 -190
- package/dist/impl/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/impl/ua_data_type_impl.d.ts +21 -0
- package/dist/impl/ua_data_type_impl.js +27 -2
- package/dist/impl/ua_data_type_impl.js.map +1 -1
- package/dist/impl/ua_object_type_impl.d.ts +9 -0
- package/dist/impl/ua_object_type_impl.js +12 -1
- package/dist/impl/ua_object_type_impl.js.map +1 -1
- package/dist/impl/ua_variable_impl.js +27 -10
- package/dist/impl/ua_variable_impl.js.map +1 -1
- package/dist/impl/ua_variable_impl_ext_obj.js +19 -2
- package/dist/impl/ua_variable_impl_ext_obj.js.map +1 -1
- package/dist/impl/ua_variable_type_impl.d.ts +8 -1
- package/dist/impl/ua_variable_type_impl.js +39 -2
- package/dist/impl/ua_variable_type_impl.js.map +1 -1
- package/dist/tsconfig_base.tsbuildinfo +1 -1
- package/distNodeJS/generate_address_space.js +4 -0
- package/distNodeJS/generate_address_space.js.map +1 -1
- package/impl/_instantiate_helpers.ts +3 -0
- package/impl/alarms_and_conditions/ua_alarm_condition_impl.ts +10 -0
- package/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.ts +17 -0
- package/impl/base_node_impl.ts +15 -0
- package/impl/base_node_private.ts +97 -146
- package/impl/nodeset_tools/construct_namespace_dependency.ts +5 -1
- package/impl/nodeset_tools/nodeset_to_records.ts +66 -16
- package/impl/nodeset_tools/nodeset_to_xml.ts +127 -160
- package/impl/ua_data_type_impl.ts +40 -2
- package/impl/ua_object_type_impl.ts +16 -3
- package/impl/ua_variable_impl.ts +27 -10
- package/impl/ua_variable_impl_ext_obj.ts +20 -2
- package/impl/ua_variable_type_impl.ts +48 -2
- package/package.json +29 -27
- package/source_nodejs/generate_address_space.ts +7 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the nodeset command line tools share: resolving the files a document requires, and the
|
|
3
|
+
* shape of a NodesetSource over a file on disk.
|
|
4
|
+
*/
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const { preLoad } = require("../dist/api/index.js");
|
|
8
|
+
const { readNodeSet2XmlFile } = require("../distNodeJS/index.js");
|
|
9
|
+
|
|
10
|
+
const kb = (n) => `${(n / 1024).toFixed(0)} KB`;
|
|
11
|
+
|
|
12
|
+
/** a NodeSet2 file as the loader takes it: named, and read whole when asked for */
|
|
13
|
+
const asFile = (file) => ({ name: file, source: () => [new Uint8Array(fs.readFileSync(file))] });
|
|
14
|
+
|
|
15
|
+
const imageFileOf = (file, outDir) => {
|
|
16
|
+
const base = path.basename(file).replace(/\.xml$/i, "");
|
|
17
|
+
return path.join(outDir ?? path.dirname(file), `${base}.ndjson.gz`);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** the files `file` requires, in load order, from the node-opcua-nodesets catalog and `requireFiles` */
|
|
21
|
+
async function dependencyChain(file, requireFiles = []) {
|
|
22
|
+
let catalog = [];
|
|
23
|
+
let nodesets = {};
|
|
24
|
+
try {
|
|
25
|
+
({ nodesetCatalog: catalog, nodesets } = require("node-opcua-nodesets"));
|
|
26
|
+
} catch {
|
|
27
|
+
/* the catalog is optional */
|
|
28
|
+
}
|
|
29
|
+
const known = new Map(); // model uri -> file
|
|
30
|
+
for (const meta of catalog) {
|
|
31
|
+
if (nodesets[meta.name] && fs.existsSync(nodesets[meta.name])) known.set(meta.uri, nodesets[meta.name]);
|
|
32
|
+
}
|
|
33
|
+
for (const required of requireFiles) {
|
|
34
|
+
const [desc] = await preLoad([required], readNodeSet2XmlFile);
|
|
35
|
+
for (const model of desc.namespaceModel.models) known.set(model.modelUri, required);
|
|
36
|
+
}
|
|
37
|
+
const order = [];
|
|
38
|
+
const visit = async (f) => {
|
|
39
|
+
const [desc] = await preLoad([f], readNodeSet2XmlFile);
|
|
40
|
+
for (const model of desc.namespaceModel.models) {
|
|
41
|
+
for (const required of model.requiredModel) {
|
|
42
|
+
const dependency = known.get(required.modelUri);
|
|
43
|
+
if (!dependency) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`${path.basename(f)} requires ${required.modelUri}: not in the catalog, pass it with --require`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
if (!order.includes(dependency) && dependency !== f) await visit(dependency);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!order.includes(f)) order.push(f);
|
|
52
|
+
};
|
|
53
|
+
await visit(file);
|
|
54
|
+
return order;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* the record stream of a document, whichever form it is in. A gzip stream starts `1f 8b`, a
|
|
59
|
+
* NodeSet2 XML document `<`, and an uncompressed NodeSet-NDJSON document `{`, so the three are
|
|
60
|
+
* told apart by their first byte with no filename and no metadata to trust.
|
|
61
|
+
*/
|
|
62
|
+
async function recordsOfFile(file) {
|
|
63
|
+
const { imageNodesetRecords } = require("../dist/api/index.js");
|
|
64
|
+
const { nodesetFileToImage } = require("../distNodeJS/index.js");
|
|
65
|
+
const bytes = new Uint8Array(fs.readFileSync(file));
|
|
66
|
+
const image = bytes[0] === 0x1f && bytes[1] === 0x8b ? bytes : await nodesetFileToImage(file);
|
|
67
|
+
const out = [];
|
|
68
|
+
for await (const record of imageNodesetRecords(image)) out.push(record);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { asFile, dependencyChain, imageFileOf, kb, recordsOfFile };
|
|
@@ -1,53 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* opcua-nodeset-image:
|
|
3
|
+
* opcua-nodeset-image: everything you can do to a nodeset document without an information model.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here builds an address space. A NodeSet2 document and its NodeSet-NDJSON form are two
|
|
6
|
+
* spellings of the same thing, so converting between them, reading one, or comparing two is a
|
|
7
|
+
* transcription: no DataType definitions are needed, no dependency chain has to be resolved, and
|
|
8
|
+
* nothing has to be loaded. That is what keeps this tool cheap, and what makes its answers about
|
|
9
|
+
* the document rather than about node-opcua. For the few operations that do need a model, and
|
|
10
|
+
* pay for one, see `opcua-nodeset-live`.
|
|
4
11
|
*
|
|
5
12
|
* opcua-nodeset-image build <file.xml>... [--out <dir>]
|
|
6
13
|
* writes <name>.ndjson.gz next to each source, or into --out; prints source size,
|
|
7
|
-
* image size, node count and elapsed time
|
|
8
|
-
*
|
|
9
|
-
* opcua-nodeset-image
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* image size, node count and elapsed time. Exit 1 if a file fails, the others are
|
|
15
|
+
* still processed
|
|
16
|
+
* opcua-nodeset-image xml <file>... [--out <dir>]
|
|
17
|
+
* the other direction: writes <name>.nodeset2.xml from a document in either form
|
|
18
|
+
* opcua-nodeset-image records <file>
|
|
19
|
+
* the record stream as NDJSON on stdout, one record per line, uncompressed
|
|
20
|
+
* opcua-nodeset-image info <file>
|
|
21
|
+
* the header and the trailer of an image
|
|
22
|
+
* opcua-nodeset-image diff <a> <b>
|
|
23
|
+
* the two documents compared record by record; either may be XML or NDJSON
|
|
17
24
|
*/
|
|
18
25
|
const fs = require("node:fs");
|
|
19
26
|
const path = require("node:path");
|
|
20
27
|
const { performance } = require("node:perf_hooks");
|
|
21
|
-
const {
|
|
22
|
-
const {
|
|
28
|
+
const { readNodesetImageInfo, recordsToNodeset2XML } = require("../dist/api/index.js");
|
|
29
|
+
const { nodesetFileToImage } = require("../distNodeJS/index.js");
|
|
30
|
+
const { imageFileOf, kb, recordsOfFile } = require("./nodeset_tool_common.js");
|
|
23
31
|
|
|
24
32
|
const usage = () => {
|
|
25
|
-
console.error("usage: opcua-nodeset-image build
|
|
26
|
-
console.error(" opcua-nodeset-image
|
|
27
|
-
console.error(" opcua-nodeset-image
|
|
28
|
-
console.error(" opcua-nodeset-image
|
|
33
|
+
console.error("usage: opcua-nodeset-image build <file.xml>... [--out <dir>]");
|
|
34
|
+
console.error(" opcua-nodeset-image xml <file>... [--out <dir>]");
|
|
35
|
+
console.error(" opcua-nodeset-image records <file>");
|
|
36
|
+
console.error(" opcua-nodeset-image info <file>");
|
|
37
|
+
console.error(" opcua-nodeset-image diff <a> <b>");
|
|
29
38
|
process.exit(2);
|
|
30
39
|
};
|
|
31
40
|
|
|
32
41
|
function parseArgs(argv) {
|
|
33
42
|
const files = [];
|
|
34
|
-
const options = { out: undefined
|
|
43
|
+
const options = { out: undefined };
|
|
35
44
|
for (let i = 0; i < argv.length; i++) {
|
|
36
45
|
const arg = argv[i];
|
|
37
46
|
if (arg === "--out") options.out = argv[++i];
|
|
38
|
-
else if (arg === "--require") options.require.push(argv[++i]);
|
|
39
47
|
else if (arg.startsWith("--")) usage();
|
|
40
48
|
else files.push(arg);
|
|
41
49
|
}
|
|
42
50
|
return { files, options };
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
const imageFileOf = (file, outDir) => {
|
|
46
|
-
const base = path.basename(file).replace(/\.xml$/i, "");
|
|
47
|
-
return path.join(outDir ?? path.dirname(file), `${base}.ndjson.gz`);
|
|
48
|
-
};
|
|
49
|
-
const kb = (n) => `${(n / 1024).toFixed(0)} KB`;
|
|
50
|
-
|
|
51
53
|
async function build(files, options) {
|
|
52
54
|
let failed = 0;
|
|
53
55
|
for (const file of files) {
|
|
@@ -70,60 +72,23 @@ async function build(files, options) {
|
|
|
70
72
|
return failed > 0 ? 1 : 0;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
async function dependencyChain(file, requireFiles) {
|
|
75
|
-
let catalog = [];
|
|
76
|
-
let nodesets = {};
|
|
77
|
-
try {
|
|
78
|
-
({ nodesetCatalog: catalog, nodesets } = require("node-opcua-nodesets"));
|
|
79
|
-
} catch {
|
|
80
|
-
/* the catalog is optional */
|
|
81
|
-
}
|
|
82
|
-
const known = new Map(); // model uri -> file
|
|
83
|
-
for (const meta of catalog) {
|
|
84
|
-
if (nodesets[meta.name] && fs.existsSync(nodesets[meta.name])) known.set(meta.uri, nodesets[meta.name]);
|
|
85
|
-
}
|
|
86
|
-
for (const required of requireFiles) {
|
|
87
|
-
const [desc] = await preLoad([required], readNodeSet2XmlFile);
|
|
88
|
-
for (const model of desc.namespaceModel.models) known.set(model.modelUri, required);
|
|
89
|
-
}
|
|
90
|
-
const order = [];
|
|
91
|
-
const visit = async (f) => {
|
|
92
|
-
const [desc] = await preLoad([f], readNodeSet2XmlFile);
|
|
93
|
-
for (const model of desc.namespaceModel.models) {
|
|
94
|
-
for (const required of model.requiredModel) {
|
|
95
|
-
const dependency = known.get(required.modelUri);
|
|
96
|
-
if (!dependency) throw new Error(`${path.basename(f)} requires ${required.modelUri}: not in the catalog, pass it with --require`);
|
|
97
|
-
if (!order.includes(dependency) && dependency !== f) await visit(dependency);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (!order.includes(f)) order.push(f);
|
|
101
|
-
};
|
|
102
|
-
await visit(file);
|
|
103
|
-
return order;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function verify(files, options) {
|
|
75
|
+
async function toXml(files, options) {
|
|
107
76
|
let failed = 0;
|
|
108
77
|
for (const file of files) {
|
|
78
|
+
const t0 = performance.now();
|
|
109
79
|
try {
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const fromXml = await load(chain.map(asFile));
|
|
123
|
-
const fromImage = await load(chain.map((f) => (f === file ? { name: `${f} (image)`, source: image } : asFile(f))));
|
|
124
|
-
const same = fromXml.hash === fromImage.hash && fromXml.nodes === fromImage.nodes && fromXml.references === fromImage.references;
|
|
125
|
-
console.log(`${path.basename(file)}: ${fromXml.nodes} nodes, ${fromXml.references} references, image ${same ? "identical" : "DIFFERS"}`);
|
|
126
|
-
if (!same) failed += 1;
|
|
80
|
+
const records = await recordsOfFile(file);
|
|
81
|
+
const xml = recordsToNodeset2XML(records);
|
|
82
|
+
const base = path
|
|
83
|
+
.basename(file)
|
|
84
|
+
.replace(/\.ndjson\.gz$/i, "")
|
|
85
|
+
.replace(/\.xml$/i, "");
|
|
86
|
+
const target = path.join(options.out ?? path.dirname(file), `${base}.nodeset2.xml`);
|
|
87
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
88
|
+
fs.writeFileSync(target, xml);
|
|
89
|
+
console.log(
|
|
90
|
+
`${path.basename(file)}: ${records.length - 1} nodes -> ${path.basename(target)} ${kb(xml.length)}, ${(performance.now() - t0).toFixed(0)} ms`
|
|
91
|
+
);
|
|
127
92
|
} catch (err) {
|
|
128
93
|
failed += 1;
|
|
129
94
|
console.error(`${file}: ${err.message}`);
|
|
@@ -132,28 +97,13 @@ async function verify(files, options) {
|
|
|
132
97
|
return failed > 0 ? 1 : 0;
|
|
133
98
|
}
|
|
134
99
|
|
|
135
|
-
async function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const asFile = (f) => ({ name: f, source: () => [new Uint8Array(fs.readFileSync(f))] });
|
|
141
|
-
await generateAddressSpaceRaw(addressSpace, chain.map(asFile), {});
|
|
142
|
-
const [desc] = await preLoad([last], readNodeSet2XmlFile);
|
|
143
|
-
const modelUri = desc.namespaceModel.models[0]?.modelUri;
|
|
144
|
-
const namespace = addressSpace.getNamespaceArray().find((n) => n.namespaceUri === modelUri);
|
|
145
|
-
if (!namespace) throw new Error(`${path.basename(last)}: namespace ${modelUri} not found after loading`);
|
|
146
|
-
const t0 = performance.now();
|
|
147
|
-
const image = await namespaceToImage(namespace, { addressSpaceVersion: addressSpacePackageVersion() });
|
|
148
|
-
const target = options.out ?? imageFileOf(last, undefined).replace(/\.ndjson\.gz$/, ".export.ndjson.gz");
|
|
149
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
150
|
-
fs.writeFileSync(target, image);
|
|
151
|
-
const info = await readNodesetImageInfo(image);
|
|
152
|
-
console.log(`${path.basename(last)}: namespace ${modelUri} -> ${path.basename(target)} ${kb(image.length)}, ${info.trailer.nodes} nodes, ${(performance.now() - t0).toFixed(0)} ms`);
|
|
153
|
-
return 0;
|
|
154
|
-
} finally {
|
|
155
|
-
addressSpace.dispose();
|
|
100
|
+
async function records(files) {
|
|
101
|
+
for (const file of files) {
|
|
102
|
+
for (const record of await recordsOfFile(file)) {
|
|
103
|
+
console.log(JSON.stringify(record));
|
|
104
|
+
}
|
|
156
105
|
}
|
|
106
|
+
return 0;
|
|
157
107
|
}
|
|
158
108
|
|
|
159
109
|
async function info(files) {
|
|
@@ -165,6 +115,44 @@ async function info(files) {
|
|
|
165
115
|
return 0;
|
|
166
116
|
}
|
|
167
117
|
|
|
118
|
+
/** the key a record is matched on across two documents; the header is one of a kind */
|
|
119
|
+
const keyOf = (record) => (record.kind === "header" ? "header" : record.nodeId.toString());
|
|
120
|
+
|
|
121
|
+
async function diff(files) {
|
|
122
|
+
if (files.length !== 2) usage();
|
|
123
|
+
const [a, b] = await Promise.all(files.map(recordsOfFile));
|
|
124
|
+
const right = new Map(b.map((r) => [keyOf(r), r]));
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
const differences = [];
|
|
127
|
+
for (const left of a) {
|
|
128
|
+
const key = keyOf(left);
|
|
129
|
+
seen.add(key);
|
|
130
|
+
const other = right.get(key);
|
|
131
|
+
if (!other) {
|
|
132
|
+
differences.push(`${key}: only in ${path.basename(files[0])}`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
for (const field of new Set([...Object.keys(left), ...Object.keys(other)])) {
|
|
136
|
+
const l = JSON.stringify(left[field]);
|
|
137
|
+
const r = JSON.stringify(other[field]);
|
|
138
|
+
if (l !== r) {
|
|
139
|
+
differences.push(`${key}.${field}\n A ${String(l).slice(0, 200)}\n B ${String(r).slice(0, 200)}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const record of b) {
|
|
144
|
+
if (!seen.has(keyOf(record))) differences.push(`${keyOf(record)}: only in ${path.basename(files[1])}`);
|
|
145
|
+
}
|
|
146
|
+
for (const line of differences.slice(0, 40)) console.log(line);
|
|
147
|
+
if (differences.length > 40) console.log(`... and ${differences.length - 40} more`);
|
|
148
|
+
console.log(
|
|
149
|
+
differences.length === 0
|
|
150
|
+
? `${path.basename(files[0])} and ${path.basename(files[1])}: identical, ${a.length} records`
|
|
151
|
+
: `${differences.length} difference(s) over ${a.length} records`
|
|
152
|
+
);
|
|
153
|
+
return differences.length === 0 ? 0 : 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
168
156
|
async function main() {
|
|
169
157
|
const [command, ...rest] = process.argv.slice(2);
|
|
170
158
|
const { files, options } = parseArgs(rest);
|
|
@@ -172,21 +160,23 @@ async function main() {
|
|
|
172
160
|
switch (command) {
|
|
173
161
|
case "build":
|
|
174
162
|
return build(files, options);
|
|
175
|
-
case "
|
|
176
|
-
return
|
|
163
|
+
case "xml":
|
|
164
|
+
return toXml(files, options);
|
|
165
|
+
case "records":
|
|
166
|
+
return records(files);
|
|
177
167
|
case "info":
|
|
178
168
|
return info(files);
|
|
179
|
-
case "
|
|
180
|
-
return
|
|
169
|
+
case "diff":
|
|
170
|
+
return diff(files);
|
|
181
171
|
default:
|
|
182
|
-
usage();
|
|
172
|
+
return usage();
|
|
183
173
|
}
|
|
184
174
|
}
|
|
185
175
|
|
|
186
176
|
main().then(
|
|
187
177
|
(code) => process.exit(code),
|
|
188
178
|
(err) => {
|
|
189
|
-
console.error(err.message);
|
|
179
|
+
console.error(err.stack || err.message);
|
|
190
180
|
process.exit(1);
|
|
191
181
|
}
|
|
192
182
|
);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* opcua-nodeset-live: the nodeset operations that need an information model, and only those.
|
|
4
|
+
*
|
|
5
|
+
* Each of these builds a real address space, which means resolving a dependency chain, loading
|
|
6
|
+
* every namespace a document requires, and paying for the whole of node-opcua. That is the point
|
|
7
|
+
* of keeping them apart from `opcua-nodeset-image`: converting a document between its two
|
|
8
|
+
* spellings needs none of it, and a tool that quietly loaded a model to do a transcription would
|
|
9
|
+
* be answering a different question from the one it was asked.
|
|
10
|
+
*
|
|
11
|
+
* What genuinely needs a model:
|
|
12
|
+
*
|
|
13
|
+
* opcua-nodeset-live verify <file.xml>... [--require <file.xml>]...
|
|
14
|
+
* loads each file from XML and from its image into two address spaces and compares them.
|
|
15
|
+
* The comparison is of models, so there has to be one
|
|
16
|
+
* opcua-nodeset-live export <file.xml>... [--out <image>] [--require <file.xml>]...
|
|
17
|
+
* loads the files and writes the last one's namespace back out as an image, from the live
|
|
18
|
+
* address space. This is how a namespace that was never a document becomes one
|
|
19
|
+
* opcua-nodeset-live equivalence <file.xml>... [--require <file.xml>]... [--dump <dir>] [--quiet]
|
|
20
|
+
* the full round trip of the RFC, section 9.2: what a *given implementation* loses when it
|
|
21
|
+
* loads a document and writes it back. The narrower claim, about the format alone, is
|
|
22
|
+
* checked without an address space and lives in test_nodeset_records_to_xml.ts
|
|
23
|
+
*/
|
|
24
|
+
const fs = require("node:fs");
|
|
25
|
+
const path = require("node:path");
|
|
26
|
+
const { performance } = require("node:perf_hooks");
|
|
27
|
+
const { AddressSpace, generateAddressSpaceRaw, namespaceToImage, preLoad, readNodesetImageInfo } = require("../dist/api/index.js");
|
|
28
|
+
const {
|
|
29
|
+
addressSpacePackageVersion,
|
|
30
|
+
digestAddressSpace,
|
|
31
|
+
nodesetFileToImage,
|
|
32
|
+
readNodeSet2XmlFile
|
|
33
|
+
} = require("../distNodeJS/index.js");
|
|
34
|
+
const { asFile, dependencyChain, imageFileOf, kb } = require("./nodeset_tool_common.js");
|
|
35
|
+
const { equivalence } = require("./nodeset_equivalence.js");
|
|
36
|
+
|
|
37
|
+
const usage = () => {
|
|
38
|
+
console.error("usage: opcua-nodeset-live verify <file.xml>... [--require <file.xml>]...");
|
|
39
|
+
console.error(" opcua-nodeset-live export <file.xml>... [--out <image>] [--require <file.xml>]...");
|
|
40
|
+
console.error(" opcua-nodeset-live equivalence <file.xml>... [--require <file.xml>]... [--dump <dir>] [--quiet]");
|
|
41
|
+
process.exit(2);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function parseArgs(argv) {
|
|
45
|
+
const files = [];
|
|
46
|
+
const options = { out: undefined, require: [] };
|
|
47
|
+
for (let i = 0; i < argv.length; i++) {
|
|
48
|
+
const arg = argv[i];
|
|
49
|
+
if (arg === "--out") options.out = argv[++i];
|
|
50
|
+
else if (arg === "--require") options.require.push(argv[++i]);
|
|
51
|
+
else if (arg.startsWith("--")) usage();
|
|
52
|
+
else files.push(arg);
|
|
53
|
+
}
|
|
54
|
+
return { files, options };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function verify(files, options) {
|
|
58
|
+
let failed = 0;
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
try {
|
|
61
|
+
const chain = await dependencyChain(file, options.require);
|
|
62
|
+
const image = await nodesetFileToImage(file);
|
|
63
|
+
const load = async (sources) => {
|
|
64
|
+
const addressSpace = AddressSpace.create();
|
|
65
|
+
try {
|
|
66
|
+
await generateAddressSpaceRaw(addressSpace, sources, {});
|
|
67
|
+
return digestAddressSpace(addressSpace);
|
|
68
|
+
} finally {
|
|
69
|
+
addressSpace.dispose();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const fromXml = await load(chain.map(asFile));
|
|
73
|
+
const fromImage = await load(chain.map((f) => (f === file ? { name: `${f} (image)`, source: image } : asFile(f))));
|
|
74
|
+
const same =
|
|
75
|
+
fromXml.hash === fromImage.hash &&
|
|
76
|
+
fromXml.nodes === fromImage.nodes &&
|
|
77
|
+
fromXml.references === fromImage.references;
|
|
78
|
+
console.log(
|
|
79
|
+
`${path.basename(file)}: ${fromXml.nodes} nodes, ${fromXml.references} references, image ${same ? "identical" : "DIFFERS"}`
|
|
80
|
+
);
|
|
81
|
+
if (!same) failed += 1;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
failed += 1;
|
|
84
|
+
console.error(`${file}: ${err.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return failed > 0 ? 1 : 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function exportNamespace(files, options) {
|
|
91
|
+
const last = files[files.length - 1];
|
|
92
|
+
const chain = await dependencyChain(last, [...options.require, ...files.slice(0, -1)]);
|
|
93
|
+
const addressSpace = AddressSpace.create();
|
|
94
|
+
try {
|
|
95
|
+
await generateAddressSpaceRaw(addressSpace, chain.map(asFile), {});
|
|
96
|
+
const [desc] = await preLoad([last], readNodeSet2XmlFile);
|
|
97
|
+
const modelUri = desc.namespaceModel.models[0]?.modelUri;
|
|
98
|
+
const namespace = addressSpace.getNamespaceArray().find((n) => n.namespaceUri === modelUri);
|
|
99
|
+
if (!namespace) throw new Error(`${path.basename(last)}: namespace ${modelUri} not found after loading`);
|
|
100
|
+
const t0 = performance.now();
|
|
101
|
+
const image = await namespaceToImage(namespace, { addressSpaceVersion: addressSpacePackageVersion() });
|
|
102
|
+
const target = options.out ?? imageFileOf(last, undefined).replace(/\.ndjson\.gz$/, ".export.ndjson.gz");
|
|
103
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
104
|
+
fs.writeFileSync(target, image);
|
|
105
|
+
const info = await readNodesetImageInfo(image);
|
|
106
|
+
console.log(
|
|
107
|
+
`${path.basename(last)}: namespace ${modelUri} -> ${path.basename(target)} ${kb(image.length)}, ${info.trailer.nodes} nodes, ${(performance.now() - t0).toFixed(0)} ms`
|
|
108
|
+
);
|
|
109
|
+
return 0;
|
|
110
|
+
} finally {
|
|
111
|
+
addressSpace.dispose();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
117
|
+
if (!command) usage();
|
|
118
|
+
if (command === "equivalence") {
|
|
119
|
+
return equivalence(rest);
|
|
120
|
+
}
|
|
121
|
+
const { files, options } = parseArgs(rest);
|
|
122
|
+
if (files.length === 0) usage();
|
|
123
|
+
switch (command) {
|
|
124
|
+
case "verify":
|
|
125
|
+
return verify(files, options);
|
|
126
|
+
case "export":
|
|
127
|
+
return exportNamespace(files, options);
|
|
128
|
+
default:
|
|
129
|
+
return usage();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
main().then(
|
|
134
|
+
(code) => process.exit(code),
|
|
135
|
+
(err) => {
|
|
136
|
+
console.error(err.stack || err.message);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
);
|
|
@@ -17,3 +17,23 @@ export interface EnsureObjectIsSecureOptions {
|
|
|
17
17
|
* @param options `hideStructure` to also hide the nodes from unauthorised sessions
|
|
18
18
|
*/
|
|
19
19
|
export declare function ensureObjectIsSecure(node: BaseNode, options?: EnsureObjectIsSecureOptions): void;
|
|
20
|
+
/**
|
|
21
|
+
* keep the structure of `node` and its aggregates browsable by every session, leaving every
|
|
22
|
+
* other permission as declared.
|
|
23
|
+
*
|
|
24
|
+
* A node whose RolePermissions grant Browse to neither Anonymous nor AuthenticatedUser is
|
|
25
|
+
* hidden from any session that holds none of the roles it names. Where those roles are ones
|
|
26
|
+
* the server never assigns, nobody sees the node, and its parent - browsable by everyone -
|
|
27
|
+
* shows an instance missing the mandatory children of its type. `Opc.Ua.NodeSet2.xml` does
|
|
28
|
+
* this to eleven nodes under Server/PublishSubscribe (the methods of SecurityGroups and
|
|
29
|
+
* KeyPushTargets, with their arguments), reserved to the SecurityKeyServerAdmin role
|
|
30
|
+
* (CTT Base Info Core Structure 002, FEAT-30).
|
|
31
|
+
*
|
|
32
|
+
* Such a node gains Browse for Anonymous and AuthenticatedUser, which every session's
|
|
33
|
+
* permissions are evaluated against; Read, Write and Call stay with the roles it named. A
|
|
34
|
+
* node without RolePermissions, or that already grants Browse to one of the two, is left as
|
|
35
|
+
* it is.
|
|
36
|
+
*
|
|
37
|
+
* @param node the node whose structure, and whose aggregates' structure, must stay visible
|
|
38
|
+
*/
|
|
39
|
+
export declare function ensureStructureIsBrowsable(node: BaseNode): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureObjectIsSecure = ensureObjectIsSecure;
|
|
4
|
+
exports.ensureStructureIsBrowsable = ensureStructureIsBrowsable;
|
|
4
5
|
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
5
6
|
const node_opcua_types_1 = require("node-opcua-types");
|
|
6
7
|
const session_context_js_1 = require("../session_context.js");
|
|
@@ -64,4 +65,42 @@ function ensureObjectIsSecure(node, options = {}) {
|
|
|
64
65
|
ensureObjectIsSecure(child, options);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
/** the two Roles every Session's permissions are evaluated against, granted Browse and nothing else */
|
|
69
|
+
const browseForEverySession = [
|
|
70
|
+
{ roleId: session_context_js_1.WellKnownRoles.Anonymous, permissions: (0, node_opcua_data_model_1.makePermissionFlag)("Browse") },
|
|
71
|
+
{ roleId: session_context_js_1.WellKnownRoles.AuthenticatedUser, permissions: (0, node_opcua_data_model_1.makePermissionFlag)("Browse") }
|
|
72
|
+
];
|
|
73
|
+
function grantsBrowseToEverySession(rolePermissions) {
|
|
74
|
+
return rolePermissions.some(({ roleId, permissions }) => (permissions & node_opcua_data_model_1.PermissionFlag.Browse) !== 0 &&
|
|
75
|
+
roleId.namespace === 0 &&
|
|
76
|
+
(roleId.value === session_context_js_1.WellKnownRoles.Anonymous || roleId.value === session_context_js_1.WellKnownRoles.AuthenticatedUser));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* keep the structure of `node` and its aggregates browsable by every session, leaving every
|
|
80
|
+
* other permission as declared.
|
|
81
|
+
*
|
|
82
|
+
* A node whose RolePermissions grant Browse to neither Anonymous nor AuthenticatedUser is
|
|
83
|
+
* hidden from any session that holds none of the roles it names. Where those roles are ones
|
|
84
|
+
* the server never assigns, nobody sees the node, and its parent - browsable by everyone -
|
|
85
|
+
* shows an instance missing the mandatory children of its type. `Opc.Ua.NodeSet2.xml` does
|
|
86
|
+
* this to eleven nodes under Server/PublishSubscribe (the methods of SecurityGroups and
|
|
87
|
+
* KeyPushTargets, with their arguments), reserved to the SecurityKeyServerAdmin role
|
|
88
|
+
* (CTT Base Info Core Structure 002, FEAT-30).
|
|
89
|
+
*
|
|
90
|
+
* Such a node gains Browse for Anonymous and AuthenticatedUser, which every session's
|
|
91
|
+
* permissions are evaluated against; Read, Write and Call stay with the roles it named. A
|
|
92
|
+
* node without RolePermissions, or that already grants Browse to one of the two, is left as
|
|
93
|
+
* it is.
|
|
94
|
+
*
|
|
95
|
+
* @param node the node whose structure, and whose aggregates' structure, must stay visible
|
|
96
|
+
*/
|
|
97
|
+
function ensureStructureIsBrowsable(node) {
|
|
98
|
+
const rolePermissions = node.rolePermissions;
|
|
99
|
+
if (rolePermissions && !grantsBrowseToEverySession(rolePermissions)) {
|
|
100
|
+
node.setRolePermissions([...rolePermissions, ...browseForEverySession]);
|
|
101
|
+
}
|
|
102
|
+
for (const child of node.findReferencesExAsObject("Aggregates", node_opcua_data_model_1.BrowseDirection.Forward)) {
|
|
103
|
+
ensureStructureIsBrowsable(child);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
67
106
|
//# sourceMappingURL=ensure_secure_access.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure_secure_access.js","sourceRoot":"","sources":["../../../api/helpers/ensure_secure_access.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"ensure_secure_access.js","sourceRoot":"","sources":["../../../api/helpers/ensure_secure_access.ts"],"names":[],"mappings":"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"}
|
package/dist/api/index.d.ts
CHANGED
|
@@ -92,14 +92,19 @@ export * from "./interfaces/state_machine/ua_transition_ex.js";
|
|
|
92
92
|
export * from "./interfaces/ua_subscription_diagnostics_variable_ex.js";
|
|
93
93
|
export { ensureDatatypeExtracted, ensureDatatypeExtractedWithCallback } from "./loader/ensure_datatype_extracted.js";
|
|
94
94
|
export * from "./loader/generateAddressSpaceRaw.js";
|
|
95
|
-
export {
|
|
95
|
+
export { type NarrowedDataType, narrowInstanceDataTypes } from "./loader/narrow_instance_datatypes.js";
|
|
96
|
+
export { isNdjsonHeaderLine, NDJSON_IMAGE_FORMAT, NODESET2_XML_FORMAT, registerBuiltinNodesetFormats } from "./loader/nodeset_builtin_formats.js";
|
|
97
|
+
export { findNodesetFormat, type NodesetDocument, type NodesetFormat, type NodesetHead, type NodesetModel, type NodesetModelInfo, nodesetFormatByName, nodesetFormats, registerNodesetFormat } from "./loader/nodeset_format.js";
|
|
98
|
+
export { type ImageDeflater, imageLinesToRecords, imageNodesetRecords, inflatedImageLines, isNodesetImage, NodesetImageError, type NodesetImageHeader, type NodesetImageTrailer, NodesetImageWriter, type NodesetImageWriterOptions, nodesetImageProblem, type ReadNodesetImageOptions, readNodesetImageInfo, setImageDeflater, setImageInflater } from "./loader/nodeset_image.js";
|
|
96
99
|
export { decodeValue, encodeValue, type JsonNodeId, type JsonQualifiedName, type JsonValue } from "./loader/nodeset_image_codec.js";
|
|
97
100
|
export { MemoryNodesetImageStore, type NodesetImageStore, nodesetImageKey, sharedMemoryNodesetImageStore } from "./loader/nodeset_image_store.js";
|
|
98
101
|
export { NODESET_RECORD_SCHEMA, type NodesetDataTypeDefinitionRecord, type NodesetDefinitionField, type NodesetHeaderRecord, type NodesetModelRecord, type NodesetNodeRecord, type NodesetRecord, type NodesetRecordConsumer, type NodesetRecordProducer, type NodesetReferenceRecord, type NodesetRolePermissionRecord, recordBytes, XmlExtensionObjectFragment } from "./loader/nodeset_record.js";
|
|
99
|
-
export
|
|
102
|
+
export { type RecordsToNodeset2XMLOptions, recordsToNodeset2XML } from "./loader/nodeset_records_to_xml.js";
|
|
103
|
+
export type { NamedNodesetSource, NodesetChunk, NodesetChunkStream, NodesetContainer, NodesetSource, NodesetSourceKind } from "./loader/nodeset_source.js";
|
|
100
104
|
export { sha256Hex } from "./loader/nodeset_source.js";
|
|
101
105
|
export * from "./loader/nodeset_source_helpers.js";
|
|
102
106
|
export { type NodesetToImageOptions, nodesetToImage } from "./loader/nodeset_to_image.js";
|
|
107
|
+
export { headerComplete, parseDependencies, sliceHeader } from "./loader/nodeset_xml_header.js";
|
|
103
108
|
export { makeXmlNodesetRecordReader, type XmlNodesetRecordReader, xmlNodesetRecords } from "./loader/nodeset_xml_producer.js";
|
|
104
109
|
export * from "./loader/register_node_promoter.js";
|
|
105
110
|
export * from "./namespace.js";
|