@vitormnm/node-red-simple-opcua 1.6.3 → 1.7.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.
Files changed (42) hide show
  1. package/README.md +89 -136
  2. package/client/lib/opcua-client-browser.js +238 -10
  3. package/client/lib/opcua-client-method-service.js +1 -1
  4. package/client/lib/opcua-client-subscription-service.js +0 -2
  5. package/client/opcua-client-config.html +118 -1
  6. package/client/opcua-client-config.js +74 -8
  7. package/client/opcua-client-help.html +6 -0
  8. package/client/opcua-client-utils.js +34 -10
  9. package/client/opcua-client.html +7 -0
  10. package/client/opcua-client.js +97 -1
  11. package/examples/flows_simple_opc.json +1 -1
  12. package/package.json +1 -1
  13. package/server/lib/opcua-address-space-alarm.js +11 -5
  14. package/server/lib/opcua-address-space-builder.js +65 -15
  15. package/server/lib/opcua-config.js +81 -23
  16. package/server/lib/opcua-server-events-child.js +1 -1
  17. package/server/lib/opcua-server-runtime-child.js +284 -19
  18. package/server/lib/opcua-server-runtime.js +49 -5
  19. package/server/lib/opcua-server-status-child.js +14 -14
  20. package/server/nodered/simple_opcua/server/certificates/mutex +0 -0
  21. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem +25 -0
  22. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  23. package/server/nodered/simple_opcua/server/certificates/own/openssl.cnf +72 -0
  24. package/server/nodered/simple_opcua/server/certificates/own/private/private_key.pem +28 -0
  25. package/server/nodered/simple_opcua/server/certificates/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  26. package/server/nodered/simple_opcua/server/myServer1/mutex +0 -0
  27. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem +25 -0
  28. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  29. package/server/nodered/simple_opcua/server/myServer1/own/openssl.cnf +72 -0
  30. package/server/nodered/simple_opcua/server/myServer1/own/private/private_key.pem +28 -0
  31. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[91e520c64ff891c67168f08a46dd194071e15dae].pem +25 -0
  32. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[98ae95da627cea4c500753c319161a3554ee38d7].pem +25 -0
  33. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[aef8d7a1cfba13d84189a0bcf1694208fc51a7f9].pem +25 -0
  34. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  35. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[ebdf9acf1d02e347917a14108d3144799c638ea3].pem +25 -0
  36. package/server/opcua-server-io.html +76 -0
  37. package/server/opcua-server-io.js +130 -27
  38. package/server/opcua-server.css +52 -0
  39. package/server/opcua-server.html +166 -44
  40. package/server/opcua-server.js +115 -5
  41. package/server/view/opcua-server.css +89 -6
  42. package/server/view/opcua-server.js +523 -42
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIENTCCAx2gAwIBAgIHAXgjVGSHQzANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxFjAUBgNV
4
+ BAMMDW15U2VydmVyMUB0dWYwHhcNMjYwNjI1MDIzMDQ4WhcNMzYwNjIyMDIzMDQ4
5
+ WjBKMQswCQYDVQQGEwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3Rl
6
+ cmZpdmUxFjAUBgNVBAMMDW15U2VydmVyMUB0dWYwggEiMA0GCSqGSIb3DQEBAQUA
7
+ A4IBDwAwggEKAoIBAQDMu7IcLcSMHB8XwnAXhhsbSwixcERQNxvcFD9Gw5IKKm0W
8
+ MCQBxLfBnKtaM0JwgltKdtPAGuRnzvu0/SzXNN5gYknzeRBkHG576Xvsry3qEikS
9
+ vmF8xGSsXhoIm8oSOcPtrhAGk0C09ihLQ7KrACHWzt6jNfqTP+954lMsmMMgXXUj
10
+ F5Z7oxYFqj0zh483Zl+pOPYLvh5ReCVT873RNO84OsxREVAhE+047+BXJvLciYBc
11
+ 23OvtVmlguzRWVXQ7vqXHRgZv7csP8qPpoh9LzpB268ygiE7GSIr0R5GIRWGTZRG
12
+ Td6cOJGEP0jsKYcXByDAuzd4kzEBB4c9vHCkO76BAgMBAAGjggEeMIIBGjBVBglg
13
+ hkgBhvhCAQ0ESAxGU2VsZi1zaWduZWQgY2VydGlmaWNhdGUgZ2VuZXJhdGVkIGJ5
14
+ IE5vZGUtT1BDVUEgQ2VydGlmaWNhdGUgdXRpbGl0eSBWMjAMBgNVHRMBAf8EAjAA
15
+ MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMC
16
+ AvQwHQYDVR0OBBYEFGdDutMKGJuBWyphlYeXv7kBCk+XMB8GA1UdIwQYMBaAFGdD
17
+ utMKGJuBWyphlYeXv7kBCk+XMEEGA1UdEQQ6MDiCA1RVRoIDdHVmhwTAqGQBhwTA
18
+ qA9khwTAqBEBhhp1cm46dHVmOm5vZGUtcmVkOm15c2VydmVyMTANBgkqhkiG9w0B
19
+ AQsFAAOCAQEAdFE1PbfbR7vGR8mOb2t4g/M4Z1TmFqSLsq1CG1KHthcIDTgT3tvV
20
+ SplsUWwmBr6yvrwkRNuE5MsSbakblr5C/lpNKZbzPQ9Yci7ss+Yl2e9jDP0Wp+CG
21
+ onOmTz1X1S3hMMcrSdC/JvmkbUIM78s06XIXGSCoEKJHTNRLPhAbE9iOagFEcXRC
22
+ JPMphoKmWyIhHwAbmhm05aljax4SanI6szMpk5+tOgeIcQ9nYq4vjTVOxQ+Sc897
23
+ 0HODJS6GmW/i4IhFYcaEB736X31Ssd62lyDddVh2zE5Ug3A6khrbPF3soDCR52+c
24
+ lZ6myJBVO3kSHeKBzXPFNDe1LWcffk4khA==
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,72 @@
1
+ ##################################################################################################
2
+ ## SIMPLE OPENSSL CONFIG FILE FOR SELF-SIGNED CERTIFICATE GENERATION
3
+ ################################################################################################################
4
+
5
+ distinguished_name = req_distinguished_name
6
+ default_md = sha1
7
+
8
+ default_md = sha256 # The default digest algorithm
9
+
10
+ [ v3_ca ]
11
+ subjectKeyIdentifier = hash
12
+ authorityKeyIdentifier = keyid:always,issuer:always
13
+
14
+ # authorityKeyIdentifier = keyid
15
+ basicConstraints = CA:TRUE
16
+ keyUsage = critical, cRLSign, keyCertSign
17
+ nsComment = "Self-signed Certificate for CA generated by Node-OPCUA Certificate utility"
18
+ #nsCertType = sslCA, emailCA
19
+ #subjectAltName = email:copy
20
+ #issuerAltName = issuer:copy
21
+ #obj = DER:02:03
22
+ # crlDistributionPoints = @crl_info
23
+ # [ crl_info ]
24
+ # URI.0 = http://localhost:8900/crl.pem
25
+ subjectAltName = $ENV::ALTNAME
26
+
27
+ [ req ]
28
+ days = 390
29
+ req_extensions = v3_req
30
+ x509_extensions = v3_ca
31
+
32
+ [v3_req]
33
+ basicConstraints = CA:false
34
+ keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
35
+ subjectAltName = $ENV::ALTNAME
36
+
37
+ [ v3_ca_signed]
38
+ subjectKeyIdentifier = hash
39
+ authorityKeyIdentifier = keyid,issuer
40
+ basicConstraints = critical, CA:FALSE
41
+ keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
42
+ extendedKeyUsage = clientAuth,serverAuth
43
+ nsComment = "certificate generated by Node-OPCUA Certificate utility and signed by a CA"
44
+ subjectAltName = $ENV::ALTNAME
45
+ [ v3_selfsigned]
46
+ subjectKeyIdentifier = hash
47
+ authorityKeyIdentifier = keyid,issuer
48
+ basicConstraints = critical, CA:FALSE
49
+ keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
50
+ extendedKeyUsage = clientAuth,serverAuth
51
+ nsComment = "Self-signed certificate generated by Node-OPCUA Certificate utility"
52
+ subjectAltName = $ENV::ALTNAME
53
+ [ req_distinguished_name ]
54
+ countryName = Country Name (2 letter code)
55
+ countryName_default = FR
56
+ countryName_min = 2
57
+ countryName_max = 2
58
+ # stateOrProvinceName = State or Province Name (full name)
59
+ # stateOrProvinceName_default = Ile de France
60
+ # localityName = Locality Name (city, district)
61
+ # localityName_default = Paris
62
+ organizationName = Organization Name (company)
63
+ organizationName_default = NodeOPCUA
64
+ # organizationalUnitName = Organizational Unit Name (department, division)
65
+ # organizationalUnitName_default = R&D
66
+ commonName = Common Name (hostname, FQDN, IP, or your name)
67
+ commonName_max = 256
68
+ commonName_default = NodeOPCUA
69
+ # emailAddress = Email Address
70
+ # emailAddress_max = 40
71
+ # emailAddress_default = node-opcua (at) node-opcua (dot) com
72
+ subjectAltName = $ENV::ALTNAME
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMu7IcLcSMHB8X
3
+ wnAXhhsbSwixcERQNxvcFD9Gw5IKKm0WMCQBxLfBnKtaM0JwgltKdtPAGuRnzvu0
4
+ /SzXNN5gYknzeRBkHG576Xvsry3qEikSvmF8xGSsXhoIm8oSOcPtrhAGk0C09ihL
5
+ Q7KrACHWzt6jNfqTP+954lMsmMMgXXUjF5Z7oxYFqj0zh483Zl+pOPYLvh5ReCVT
6
+ 873RNO84OsxREVAhE+047+BXJvLciYBc23OvtVmlguzRWVXQ7vqXHRgZv7csP8qP
7
+ poh9LzpB268ygiE7GSIr0R5GIRWGTZRGTd6cOJGEP0jsKYcXByDAuzd4kzEBB4c9
8
+ vHCkO76BAgMBAAECggEAOYvEe4EtzsgUwUPo5+PM+LX1gpJw0S88SHb0djqAcRUN
9
+ xn/PjyOxFt2nmFnyIdeyO1L9H/EvJDKcs3m6Qd9dZjAaYzIzNkB7mZ6+M3/l4vYp
10
+ z1ft5Pj65ywoGyVW/hp4hPU5EfAP7w2Fs+oabVBDMrLBB5UjkoIVGOhRwqZJqm25
11
+ e7s8LZVTKYZJeqBW+WlrW2IrXC1eFmLREW1DBta16NVe0FVdJpbfk1fUsrkoiilM
12
+ cEw1LxuPbCwHlmLJe2p3J+9eJiMNUxHEtlTuYwbu9Z2sqXtiw3WG//C4FhnoAHNQ
13
+ dRYZsEx/MTLf7co4GV6sUjVbbYQjEKnKjCsKxrTUFQKBgQD1ly9dGQXrQUaVewnu
14
+ 1H0lCaX24ilFIF/ptwK6wvBzfYhllsw0+grKzJL8/kqHep9BDbwDo+UkRaSjH4k8
15
+ CMhloCvg17fGdec4TIXJUPSC9yeCMPbcVwKQg14mk0MbKjlJ1fdh6H/5NugdRbLh
16
+ QHYT5LBpNh3RmJClVxBZo9bjhwKBgQDVaS6WPByblik3qzw+7ctFFzUuL4iBCA6/
17
+ qSN67nJVaD2ymLEfREZnpGQAu2FQh1emx3oxiECS4OIrJI6FkMj59rn8vmhzJklX
18
+ 0ruCe/6nDWFxJ9gPwBOWrqpADMgvjZq7wDmZFqN9/7zau0sU6P9XspBHgBk57h2X
19
+ ELeHK1BftwKBgQDpglN1eHppQgqDzJYYMI/A7JiR0l4dLPglN25v9zQ7C0vqE+Sc
20
+ Jnamdrb3uC1S/aN4bj+rUmVoBJPSygRpQYyRHCc8RL+nAqnTnObEEKY79BXrsvS1
21
+ ckGs+EtH8FMo/A+2hawOussbQTqXwpKfm/PpXFLj5qGZjS9TFiIkqSSD9wKBgG1O
22
+ PUVHrqNmCuBvfSECLM3LcDqir/jexqcWG40YWkkyZf92w6mvD5yAD5RsZRCY8aUD
23
+ oKuEDQbt1gmg5Lq2iKm23FX+tILeBkzMK6xOlAS+Dr2lWb3fdGkGNz8tDM+GaM1n
24
+ TFkDxmN/vBwQOAmSuU4SsGFe1Aze0BsSvd2mqrkLAoGBAJX8y1oHcN8cZO/fJAR0
25
+ D/ZjTM06hhEBTHwhJ5yZFxZevhUlTo9eoynX1HjGUANotBN7WJ58UnwAt8l95UmU
26
+ ATnfItCQ7LAlMXQrYnXRHdoCKnjuKyDQhQyomB2aYHB4JS9KImKTaSlUk7/aLE6f
27
+ YNpYWLe/mtE+QIHAjXnDIdmD
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXglY3c2ATANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDYyNzEyMzYxM1oXDTM2MDYy
5
+ NDEyMzYxM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIqfwxgDSAPGF2KIO8E7tlQoa90l
8
+ Xw/NsFKOlKhQZtyIAzG6oGjHs0Um2YJbRRFtsV9AR0f+2G3nqgjOWX5QGhmQqZap
9
+ qgJUuYAmI4HBUrZVNmpVNFE+ascIlZwfLH2CG2Gp9zUf1G6I/t19fs+O+Xxi2dpB
10
+ wpofYnvrPyiAxe+UqnWvLVNmA5RI5lVfxSxHxNIB9HnDNmpRfdPAibw+wWm6agzF
11
+ zSaYTWDmG8bTb1YhRZnLuMyiEd7LL/MaMn/o2VOwT3Mq7jvGjoZFrGLOnUDbyaY0
12
+ K6t3dk4BhSqH335d+NLW2YSiDkWTrU/QswGKrt550Qq6vDxLP+th1aqKVJ0CAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQUKbc82JmIG+zs+GMm3IdCd1pRMbIw
17
+ HwYDVR0jBBgwFoAUKbc82JmIG+zs+GMm3IdCd1pRMbIwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBABLZ
19
+ DD0diHmbZn/WwrqwweDDkxb1wxXjyLQVjQi0nPXrlTemSxio6BT5RwzgZNciwywY
20
+ aUoqM47jNDBV7o9KxB16F/OCFNf5qLhCDs9Kh+oOuGpgI9bpHpUi76NWnTGvzJzF
21
+ PTLclXkFSavX6jxZJYu5hc7UrMklczYg8Ca/GCocI93tPpnVuoq0aURfTBbkUJAE
22
+ KwO7GYdkLMxYb/vEweR3CSGzsNdoYnSokTbsR4OUu0N8xp4vETcIxPcrv15genHf
23
+ PDHwBNgr37g/hx+0iWoG4hkwJcdZEMRdmdSJ/D/vL13fGLxRI91cUaD9zhttdv6U
24
+ ht1iX/kdJ7b4zESDI1k=
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXglY3cxcjANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDYyNzEyMzYxM1oXDTM2MDYy
5
+ NDEyMzYxM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtBNLTDXkh2mLQ3Ih2KEQlGelcM
8
+ RVwb4eKNAolkdBwDKj9jX5IAGTQO5symrlt0jUh+ekeqPRz6wZH/PMzWKGppWNqc
9
+ 17OEeGXD4KrjYqHP+LSIUOJ2ZdCjVm1aLf+LDTDBwFyDv4kfHcetTiPrKFyANzWs
10
+ cLqpoqPDDPmThVVfvBbWqjLsqOBBD+ZdZxhHqvPes+JD3abVy70OZIrFupFdUsqC
11
+ 3PeIKOs4KupJbs/ENaWo+jrtwOA9+5CqlYkCK4Kifd9wWGdfcFKT7pWsCmC59uDH
12
+ VEe6zFe6eAV7780/O+I7i6pEIBdDv+AzK4AdD6U53BxJXs+6O8pyDJchZqcCAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQUyCs6aEBAGEzVjPxYd3To7pL+XGQw
17
+ HwYDVR0jBBgwFoAUyCs6aEBAGEzVjPxYd3To7pL+XGQwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBACxk
19
+ i94+5hdSwWNNoC+nRDU6euJjFs2y9MFCKg5uYg5tIp80rRBhrAqGweIs1skizACp
20
+ tenGtmIBvdqvcGGOGL9cRibb2cFA290dhcFhlJtU0c2WaxMaQgQknn9aG6paAN3N
21
+ 58GVuHsnN8qzHt3GTR8BQIG31QKKoYsAGMxxSlSF5feNpMUiRkZe/z5KmRO5LNZ6
22
+ +es7TAXFF31aZdyhGk74fZgUBzH2/N0iSujyW+rLX4MmS1VGpSVZjl8XTh6e/ArX
23
+ 7THS5gYGhsdR2aDDyxjUTKNyteHTLoxkHxTgsurX26RntGVGfLPQReUMWz4rftaM
24
+ NzhW+W+vbYv0zWK/wVo=
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXglY3c5kjANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDYyNzEyMzYxM1oXDTM2MDYy
5
+ NDEyMzYxM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALExMVGfG1yMpIE4nIO4riyPIcA3
8
+ pAHNOIj7Y+Gzq7j9IwMCqHb08jzJ6tqqnInUOmH367aeo9/FJAsf5wXK3RySMtqG
9
+ v6L40/EvUkdrA/yPXTruAhZU0m36G+Iq5b8j7N4V5FbcUElsX7XhpCHiGj8Ar32q
10
+ uxKwiVX9/c73u72y5+OQgVfmhJtA41VpP+NPDhBUbeuRaN6KSIm9p4Pe38hWVP24
11
+ ANF9D5l/E8dtBPvZp6hJ5mJtapHHTMYSwwxGem2kFXeErD4i/2g0xBD+Y0xpHcFe
12
+ y9dNJAjaUXbeW6ihLPLhV1wbAN6TojhlstJ7ezVs1I+/RXr5psWVwIrWRVkCAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQUlCjIQiZ7wrPrKQLn29olSTNF2Kgw
17
+ HwYDVR0jBBgwFoAUlCjIQiZ7wrPrKQLn29olSTNF2KgwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBAHSe
19
+ i6LBDFpew317pGF0gDt2lgxG/b6A6yhCPZA/dT8hMLPm1mu2aosRxm2lvhxEIFEM
20
+ zqYJd8KXAeSLgBkEfoEYKjiOU+82SN8aPOnUT3/njZeTLwgajDECZQwH0Tsj+vcm
21
+ wpNVc1f+Ovy8B9Wg4BQgel5cQ4ItqIRxV/48c1mBSANykrGne1zor9f2RiVjw0dS
22
+ vuxDnOU2Hh5NGa1XWx2OCEMaLrVqaxyUAiXVZCjR67JAg2ZbTJ8IDV4FK4zz4/aH
23
+ fbtkz7qVd2pOc5MK2I8G3bnyvObf2bNKeydy7CdvEP0x8HMPIXk3fnMqUbvoZ47M
24
+ xg+xalW93QTyWI41KxI=
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXdVh2g4JzANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDQwNzE4NDgwM1oXDTM2MDQw
5
+ NDE4NDgwM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMhBslFMtRXQ2Ww7JAtPLoM7I1s
8
+ QP7mmHOv0U7mcSLib/yksMNT0G2U5J1EHI+Km1JwTYXujJnzi/ouuuQsWUsm3zP6
9
+ KAO1XzQuIYf8iEBblzOCA53eTvo056zNfeDoUb9l1CfQH/H6sL2js786dUpuJCG9
10
+ fuCfgrExRbzZQrELcduwRPuVio770NK086orAzFIXaRM20F4HMkTtorsRoGUIU5s
11
+ u6Fqy9nmdKY4w4JHQMafO3L1lHEbGuVwZmmkXmTQtBIS6W8tPSa9fh7GrlHJP4Zc
12
+ cgcp/xuXcpWfHjJaAmUQtCuNprlywJBChlstWkJ09zj1VvqoAWd0GL7ehQkCAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQUVOT0LzYI7XAMQ11FOV/+tUCUkvYw
17
+ HwYDVR0jBBgwFoAUVOT0LzYI7XAMQ11FOV/+tUCUkvYwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBABiN
19
+ x0XNf1nDyRyJQCQ4GMS9e/xrjO3FV106IJRPEosoB10R7zBL92ra4+3AilGnNOeM
20
+ 1O5eIel67DNL2kjw+5ggagtOmhJ3g3ZXFMpF08BeKnMwavoLs74yBZVFDq+2fOxs
21
+ kDdMX5TOpC4kZHMG5G9Cha9mcWjYSAYWVko/WCfby4D+MQiwraAraDL12uFcRVnP
22
+ htDTuNxs+dfKefiIsTgSlkJMisfGEV/EzmwSsTpvtuUZ5DwKddolRGsB/cXqTjc0
23
+ vGxHFjsuqp77gUyb9LNqE8ENi7pOZQFFhAmjSXTXcklWVynycgQ1E0TSNNQio4Xi
24
+ QZtA1NgPnLI6b2kubUQ=
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXglY3c3ZzANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDYyNzEyMzYxM1oXDTM2MDYy
5
+ NDEyMzYxM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIlhQT3T5fhiwtNe0Ae3yQ3XAZvA
8
+ sEdIzmPuhurL3MBR3JRZi3Morx+UD8jpb4/l4gZRWzX+TvRwUBQctbnDCj6ZLWen
9
+ 6gcumEXV8FYtMyOTyJFqb8WoBUmp0OPtNfRu9gAN+XYDRit0CkMTMr0zIWEh5euW
10
+ ZKx6ZpMUMNPfPNaoO+cE5aADJjEekzAqVpXzudo0+duv+bRWU0mOfivQs0N0YpbN
11
+ 7YwStxLJUKjdbblUcRXI2rvcjIYdZN7XY8q5qltuifewAmHzfRv5Wfjgn12PyU+g
12
+ hyDjbRF3LgtBHHAzr4mNeHmnJwigMkI68fTiJ45/aFH7km0Mm8m/CFD2W78CAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQU+Q9sO43yN6z+xLSImsP76Gbxx3Yw
17
+ HwYDVR0jBBgwFoAU+Q9sO43yN6z+xLSImsP76Gbxx3YwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBADBi
19
+ Y/2NeeJ2LPT0CbtDfN1474vbUy9Q+GURBnUQ2Mc7y6fhp1CxB3yQPJ9aQrDpWjrx
20
+ YdRrZeX2qbDhGH+zqxHC9JTKlqLwFj8L1R2ltyDMtAoX7qeaDVH0BposXSxgUYqp
21
+ Q3IISU5N5N88gGwDVSUUyvmdF6rI5nU1eZ1PqQC+pwLQ9WPzoGSNDku9Q/EmmXA+
22
+ 7t0uxFMs+DNEMrjLgrea1tIwCBacdzXF/LX5sfVkufxqb00W6QHBV+vzt3jJ9uRv
23
+ 42DSE14JQMdk9Wjq7Cns3x0ZRsx9Vdt6rHzimqlmbwvkevaaB3lEk8uvhxqiU7xr
24
+ 5wDZjybtYHwX0KlYTeg=
25
+ -----END CERTIFICATE-----
@@ -170,6 +170,8 @@
170
170
  <option value="events">Events Server</option>
171
171
  <option value="status">Status Server</option>
172
172
  <option value="activeAlarms">Active Alarms</option>
173
+ <option value="getSessions">Get Sessions</option>
174
+ <option value="deleteSessions">Delete Sessions</option>
173
175
  <option value="method-input">Method Input</option>
174
176
  <option value="method-output">Method Output</option>
175
177
  </select>
@@ -341,6 +343,80 @@ msg.payload = [
341
343
  ]
342
344
  </code></pre>
343
345
 
346
+ <h3>Get Sessions</h3>
347
+ <p>Returns a JSON array of all currently active OPC UA sessions on the server.</p>
348
+ <p><b>Input</b>: any message triggers a session snapshot.</p>
349
+ <p><b>Output</b>: <code>msg.payload</code> is an array of session objects:</p>
350
+ <pre><code>[
351
+ {
352
+ "sessionId": "ns=1;g=...",
353
+ "sessionName": "UaExpert@hostname",
354
+ "status": "active",
355
+ "creationDate": "2024-01-01T00:00:00.000Z",
356
+ "sessionTimeout": 30000,
357
+ "clientLastContactTime": 1234567890,
358
+ "channelId": 1,
359
+ "clientDescription": {
360
+ "applicationUri": "urn:hostname:client",
361
+ "productUri": "urn:hostname:client",
362
+ "applicationName": "UaExpert",
363
+ "applicationType": "1"
364
+ },
365
+ "userIdentityToken": {
366
+ "policyId": "anonymous",
367
+ "userName": null,
368
+ "tokenType": "AnonymousIdentityToken"
369
+ },
370
+ "channel": {
371
+ "channelId": 1,
372
+ "remoteAddress": "127.0.0.1",
373
+ "remotePort": 54321,
374
+ "bytesRead": 500,
375
+ "bytesWritten": 300,
376
+ "transactionsCount": 10,
377
+ "securityMode": "None",
378
+ "securityPolicy": "None"
379
+ },
380
+ "currentSubscriptionCount": 1,
381
+ "cumulatedSubscriptionCount": 2,
382
+ "currentMonitoredItemCount": 5,
383
+ "aborted": false
384
+ }
385
+ ]</code></pre>
386
+ <p>The node also fetches sessions automatically on deploy, just like <b>Status Server</b> mode.</p>
387
+
388
+ <h3>Delete Sessions</h3>
389
+ <p>Forces the server to close one or more active OPC UA sessions by their <code>sessionId</code>.</p>
390
+ <p><b>Input</b>: <code>msg.payload</code> must be an array of objects, each containing a <code>sessionId</code>
391
+ (the GUID string returned by <b>Get Sessions</b>):</p>
392
+ <pre><code>[
393
+ { "sessionId": "ns=1;g=F4F511E2-664B-2191-89A7-46EE461DB86C" },
394
+ { "sessionId": "ns=1;g=A1B2C3D4-1234-5678-ABCD-EF0123456789" }
395
+ ]</code></pre>
396
+ <p><b>Output</b>: <code>msg.payload</code> is an array of result objects, one per requested session.
397
+ The node status badge summarises deleted / not found / error counts:</p>
398
+ <pre><code>[
399
+ {
400
+ "sessionId": "ns=1;g=F4F511E2-664B-2191-89A7-46EE461DB86C",
401
+ "status": "deleted"
402
+ },
403
+ {
404
+ "sessionId": "ns=1;g=AAAAAAAA-0000-0000-0000-000000000000",
405
+ "status": "not_found"
406
+ },
407
+ {
408
+ "sessionId": "ns=1;g=BBBBBBBB-0000-0000-0000-000000000000",
409
+ "status": "error",
410
+ "error": "cannot find session …"
411
+ }
412
+ ]</code></pre>
413
+ <p>Possible <code>status</code> values:</p>
414
+ <ul>
415
+ <li><b>deleted</b> — session was found and successfully closed with reason <code>Forcing</code>.</li>
416
+ <li><b>not_found</b> — no active session with that <code>sessionId</code> exists.</li>
417
+ <li><b>error</b> — the session was found but <code>engine.closeSession()</code> threw; the
418
+ <code>error</code> field contains the message.</li>
419
+ </ul>
344
420
 
345
421
 
346
422
 
@@ -36,6 +36,8 @@ module.exports = function (RED) {
36
36
  node._childListenerAttached = false;
37
37
  node._attachedChild = null;
38
38
  node._childListenerRetry = null;
39
+ node._pendingDoneCallbacks = new Map();
40
+ node._pendingMessages = new Map();
39
41
 
40
42
  const handler = (msg) => {
41
43
  onMessage(msg, node);
@@ -49,10 +51,13 @@ module.exports = function (RED) {
49
51
  registerMethodInput(node);
50
52
  }
51
53
  if (node.mode === "events") {
52
- registerEvents(node, { throwOnError: false, waitForServer: true, timeoutMs: 5000 });
54
+ registerEvents(node, { throwOnError: false, waitForServer: true, timeoutMs: 5000, silentOnError: true });
53
55
  }
54
56
  if (node.mode === "status") {
55
- requestSnapshot(node, null, { throwOnError: false, waitForServer: true, timeoutMs: 5000 });
57
+ requestSnapshot(node, null, { throwOnError: false, waitForServer: true, timeoutMs: 5000, silentOnError: true });
58
+ }
59
+ if (node.mode === "getSessions") {
60
+ requestSessions(node, null, { throwOnError: false, waitForServer: true, timeoutMs: 5000, silentOnError: true });
56
61
  }
57
62
 
58
63
 
@@ -62,38 +67,69 @@ module.exports = function (RED) {
62
67
  node.send.apply(node, arguments);
63
68
  };
64
69
 
70
+ if (msg && msg._msgid) {
71
+ node._pendingDoneCallbacks.set(msg._msgid, done);
72
+ node._pendingMessages.set(msg._msgid, msg);
73
+ }
74
+
65
75
  if (node.mode === "read") {
66
76
  await handleRead(node, msg, send);
67
77
  }
68
-
69
- if (node.mode === "write") {
78
+ else if (node.mode === "write") {
70
79
  await handleWrite(node, msg, send);
71
80
  }
72
-
73
- if (node.mode === "event") {
81
+ else if (node.mode === "event") {
74
82
  await handleEvent(node, msg, send);
75
83
  }
76
-
77
- if (node.mode === "activeAlarms") {
84
+ else if (node.mode === "activeAlarms") {
78
85
  await handleActiveAlarms(node, msg, send);
79
86
  }
80
-
81
- if (node.mode === "method-output") {
87
+ else if (node.mode === "method-output") {
82
88
  await handleMethodOutput(node, msg, send);
83
89
  done();
84
- return;
90
+ if (msg && msg._msgid) {
91
+ node._pendingDoneCallbacks.delete(msg._msgid);
92
+ }
85
93
  }
86
- if (node.mode === "events") {
94
+ else if (node.mode === "events") {
87
95
  await registerEvents(node, { waitForServer: true, timeoutMs: 5000 });
96
+ done();
97
+ if (msg && msg._msgid) {
98
+ node._pendingDoneCallbacks.delete(msg._msgid);
99
+ }
88
100
  }
89
- if (node.mode === "status") {
101
+ else if (node.mode === "status") {
90
102
  await requestSnapshot(node, msg, { waitForServer: true, timeoutMs: 5000 });
103
+ done();
104
+ if (msg && msg._msgid) {
105
+ node._pendingDoneCallbacks.delete(msg._msgid);
106
+ }
107
+ }
108
+ else if (node.mode === "getSessions") {
109
+ await requestSessions(node, msg, { waitForServer: true, timeoutMs: 5000 });
110
+ done();
111
+ if (msg && msg._msgid) {
112
+ node._pendingDoneCallbacks.delete(msg._msgid);
113
+ }
114
+ }
115
+ else if (node.mode === "deleteSessions") {
116
+ await handleDeleteSessions(node, msg, { waitForServer: true, timeoutMs: 5000 });
117
+ done();
118
+ if (msg && msg._msgid) {
119
+ node._pendingDoneCallbacks.delete(msg._msgid);
120
+ }
91
121
  }
92
122
 
93
- done();
94
123
  } catch (error) {
95
124
  node.status({ fill: "red", shape: "ring", text: node.mode + " failed" });
96
- done(error);
125
+ node.error(error.message || String(error), msg);
126
+ if (done) {
127
+ done();
128
+ }
129
+ if (msg && msg._msgid) {
130
+ node._pendingDoneCallbacks.delete(msg._msgid);
131
+ node._pendingMessages.delete(msg._msgid);
132
+ }
97
133
  }
98
134
  });
99
135
 
@@ -104,6 +140,8 @@ module.exports = function (RED) {
104
140
  }
105
141
 
106
142
  detachChildListener(node, handler);
143
+ node._pendingDoneCallbacks.clear();
144
+ node._pendingMessages.clear();
107
145
 
108
146
 
109
147
  if (node.mode === "method-input") {
@@ -144,21 +182,63 @@ module.exports = function (RED) {
144
182
  data.payload = restoreBuffers(data.payload);
145
183
  }
146
184
 
147
- node.send(data);
185
+ const originalMsgId = data && data._msgid;
186
+ let actualMsg = data;
187
+ if (originalMsgId && node._pendingMessages.has(originalMsgId)) {
188
+ actualMsg = node._pendingMessages.get(originalMsgId);
189
+ actualMsg.payload = data.payload;
190
+ actualMsg.opcua = data.opcua;
191
+ actualMsg.topic = data.topic;
192
+ node._pendingMessages.delete(originalMsgId);
193
+ }
194
+
195
+ node.send(actualMsg);
196
+
197
+ if (originalMsgId && node._pendingDoneCallbacks.has(originalMsgId)) {
198
+ const pendingDone = node._pendingDoneCallbacks.get(originalMsgId);
199
+ pendingDone();
200
+ node._pendingDoneCallbacks.delete(originalMsgId);
201
+ }
148
202
  }
149
203
 
150
204
  if (msg.type === "error") {
151
205
  node.status(msg.data);
152
- node.error(msg.error);
206
+
207
+ const originalMsgId = msg.originalMsg && msg.originalMsg._msgid;
208
+ let catchMsg = msg.originalMsg || {};
209
+ if (originalMsgId && node._pendingMessages.has(originalMsgId)) {
210
+ catchMsg = node._pendingMessages.get(originalMsgId);
211
+ node._pendingMessages.delete(originalMsgId);
212
+ }
213
+ catchMsg.error = msg.error;
214
+
215
+ node.error(msg.error, catchMsg);
216
+
217
+ if (originalMsgId && node._pendingDoneCallbacks.has(originalMsgId)) {
218
+ const pendingDone = node._pendingDoneCallbacks.get(originalMsgId);
219
+ pendingDone();
220
+ node._pendingDoneCallbacks.delete(originalMsgId);
221
+ }
153
222
  }
154
223
 
155
224
  if (msg.type === "partialError") {
156
225
  // Route failed items to catch node without changing the node status
157
- const catchMsg = Object.assign({}, msg.originalMsg || {}, {
158
- payload: msg.failed,
159
- error: msg.error
160
- });
226
+ const originalMsgId = msg.originalMsg && msg.originalMsg._msgid;
227
+ let catchMsg = msg.originalMsg || {};
228
+ if (originalMsgId && node._pendingMessages.has(originalMsgId)) {
229
+ catchMsg = node._pendingMessages.get(originalMsgId);
230
+ node._pendingMessages.delete(originalMsgId);
231
+ }
232
+ catchMsg.payload = msg.failed;
233
+ catchMsg.error = msg.error;
234
+
161
235
  node.error(msg.error, catchMsg);
236
+
237
+ if (originalMsgId && node._pendingDoneCallbacks.has(originalMsgId)) {
238
+ const pendingDone = node._pendingDoneCallbacks.get(originalMsgId);
239
+ pendingDone();
240
+ node._pendingDoneCallbacks.delete(originalMsgId);
241
+ }
162
242
  }
163
243
 
164
244
  if (msg.type === "sendMethod") {
@@ -223,16 +303,20 @@ module.exports = function (RED) {
223
303
  async function registerMethodInput(node) {
224
304
  await sendToChild(node, {
225
305
  type: "registerMethodInput",
226
- node: node,
306
+ node: {
307
+ methodName: node.methodName
308
+ },
227
309
  nodeId: node.id
228
310
 
229
- }, { throwOnError: false, waitForServer: true, timeoutMs: 5000 });
311
+ }, { throwOnError: false, waitForServer: true, timeoutMs: 5000, silentOnError: true });
230
312
  }
231
313
 
232
314
  async function registerEvents(node, options) {
233
315
  return sendToChild(node, {
234
316
  type: "eventsServer",
235
- node: node,
317
+ node: {
318
+ intervalMs: node.intervalMs
319
+ },
236
320
  nodeId: node.id
237
321
  }, options);
238
322
  }
@@ -240,7 +324,22 @@ module.exports = function (RED) {
240
324
  async function requestSnapshot(node, msg, options) {
241
325
  return sendToChild(node, {
242
326
  type: "buildServerSnapshot",
243
- node: node,
327
+ msg: msg,
328
+ nodeId: node.id
329
+ }, options);
330
+ }
331
+
332
+ async function requestSessions(node, msg, options) {
333
+ return sendToChild(node, {
334
+ type: "readActiveSessions",
335
+ msg: msg,
336
+ nodeId: node.id
337
+ }, options);
338
+ }
339
+
340
+ async function handleDeleteSessions(node, msg, options) {
341
+ return sendToChild(node, {
342
+ type: "deleteActiveSessions",
244
343
  msg: msg,
245
344
  nodeId: node.id
246
345
  }, options);
@@ -455,7 +554,9 @@ module.exports = function (RED) {
455
554
  const error = new Error("OPC UA server child process is not available for serverRef: " + node.serverRef);
456
555
  node.status({ fill: "red", shape: "ring", text: "server unavailable" });
457
556
  if (options.throwOnError === false) {
458
- node.error(error.message);
557
+ if (!options.silentOnError) {
558
+ node.error(error.message);
559
+ }
459
560
  return false;
460
561
  }
461
562
  throw error;
@@ -473,7 +574,9 @@ module.exports = function (RED) {
473
574
  node._attachedChild = null;
474
575
  ensureChildListener(node, handler);
475
576
  if (options.throwOnError === false) {
476
- node.error(error.message);
577
+ if (!options.silentOnError) {
578
+ node.error(error.message);
579
+ }
477
580
  return false;
478
581
  }
479
582
  throw error;
@@ -263,3 +263,55 @@
263
263
  margin-left: 0;
264
264
  }
265
265
  }
266
+
267
+ /* Standardized configuration card styling */
268
+ .opcua-config-card {
269
+ padding: 14px;
270
+ background: var(--red-ui-form-input-background, #fcfcfc);
271
+ border: 1px solid var(--red-ui-form-input-border-color, #d9d9d9);
272
+ border-radius: 6px;
273
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
274
+ }
275
+
276
+ .opcua-config-card .opcua-card-title {
277
+ margin-top: 0;
278
+ margin-bottom: 12px;
279
+ font-weight: bold;
280
+ border-bottom: 1px solid var(--red-ui-form-input-border-color, #eee);
281
+ padding-bottom: 6px;
282
+ }
283
+
284
+ .opcua-config-form {
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: 10px;
288
+ }
289
+
290
+ .opcua-config-row {
291
+ margin: 0 !important;
292
+ display: flex;
293
+ align-items: center;
294
+ }
295
+
296
+ .opcua-config-row--checkbox {
297
+ height: 34px;
298
+ }
299
+
300
+ .opcua-config-label {
301
+ width: 240px;
302
+ margin: 0 !important;
303
+ font-weight: 500;
304
+ flex-shrink: 0;
305
+ display: inline-block;
306
+ vertical-align: middle;
307
+ }
308
+
309
+ .opcua-config-input {
310
+ width: 300px !important;
311
+ margin: 0 !important;
312
+ }
313
+
314
+ .opcua-config-input[type="checkbox"] {
315
+ width: auto !important;
316
+ display: inline-block;
317
+ }