@tier0/opcua-client 0.1.0 → 0.2.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 (45) hide show
  1. package/BENCHMARK.md +53 -2
  2. package/README.md +131 -14
  3. package/THIRD_PARTY_NOTICES.md +20 -0
  4. package/binding.gyp +1 -1
  5. package/lib/client.js +48 -7
  6. package/lib/native.js +25 -10
  7. package/lib/points.js +187 -21
  8. package/lib/prebuild.js +42 -0
  9. package/lib/security.js +96 -0
  10. package/node_modules/node-addon-api/LICENSE.md +9 -0
  11. package/node_modules/node-addon-api/README.md +95 -0
  12. package/node_modules/node-addon-api/common.gypi +21 -0
  13. package/node_modules/node-addon-api/except.gypi +25 -0
  14. package/node_modules/node-addon-api/index.js +14 -0
  15. package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  16. package/node_modules/node-addon-api/napi-inl.h +7244 -0
  17. package/node_modules/node-addon-api/napi.h +3420 -0
  18. package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  19. package/node_modules/node-addon-api/node_api.gyp +9 -0
  20. package/node_modules/node-addon-api/noexcept.gypi +26 -0
  21. package/node_modules/node-addon-api/nothing.c +0 -0
  22. package/node_modules/node-addon-api/package-support.json +21 -0
  23. package/node_modules/node-addon-api/package.json +481 -0
  24. package/node_modules/node-addon-api/tools/README.md +73 -0
  25. package/node_modules/node-addon-api/tools/check-napi.js +99 -0
  26. package/node_modules/node-addon-api/tools/clang-format.js +71 -0
  27. package/node_modules/node-addon-api/tools/conversion.js +301 -0
  28. package/nodes/connection.html +165 -6
  29. package/nodes/connection.js +99 -20
  30. package/nodes/read.html +3 -0
  31. package/nodes/read.js +3 -1
  32. package/nodes/subscribe.html +9 -3
  33. package/nodes/subscribe.js +330 -99
  34. package/nodes/write.html +3 -0
  35. package/package.json +15 -4
  36. package/prebuilds/linux-x64-musl/opcua_open62541.node +0 -0
  37. package/scripts/build-offline-prebuild.sh +15 -0
  38. package/scripts/build-open62541.sh +14 -4
  39. package/scripts/build-test-server.sh +23 -0
  40. package/scripts/install.js +28 -0
  41. package/scripts/verify-offline-package.js +20 -0
  42. package/scripts/verify-runtime.js +20 -0
  43. package/src/addon.cc +707 -119
  44. package/vendor/open62541-LICENSE +373 -0
  45. package/vendor/open62541-v1.4.16.tar.gz +0 -0
package/lib/points.js CHANGED
@@ -11,6 +11,32 @@ function positiveNumber(value, fallback) {
11
11
  return Number.isFinite(number) && number > 0 ? number : fallback;
12
12
  }
13
13
 
14
+ function booleanValue(value, fallback) {
15
+ if (value == null || value === '') return fallback;
16
+ if (typeof value === 'boolean') return value;
17
+ if (value === 1 || /^(true|1)$/i.test(String(value))) return true;
18
+ if (value === 0 || /^(false|0)$/i.test(String(value))) return false;
19
+ throw new Error(`Invalid Boolean value: ${value}`);
20
+ }
21
+
22
+ function normalizeIndexRange(value, fallback = '') {
23
+ const source = value == null || value === '' ? fallback : value;
24
+ const text = String(source == null ? '' : source).trim();
25
+ if (!text) return '';
26
+ const dimensions = text.split(',').map((dimension) => dimension.trim());
27
+ for (const dimension of dimensions) {
28
+ if (!/^\d+(?::\d+)?$/.test(dimension)) {
29
+ throw new Error(`Invalid OPC UA IndexRange: ${text}`);
30
+ }
31
+ const bounds = dimension.split(':').map(Number);
32
+ if (bounds.some((bound) => !Number.isSafeInteger(bound) || bound > 0xffffffff) ||
33
+ (bounds.length === 2 && bounds[0] > bounds[1])) {
34
+ throw new Error(`Invalid OPC UA IndexRange: ${text}`);
35
+ }
36
+ }
37
+ return dimensions.join(',');
38
+ }
39
+
14
40
  function normalizePoint(input, defaults = {}) {
15
41
  const source = typeof input === 'string' ? { nodeId: input } : { ...(input || {}) };
16
42
  const nodeId = String(source.nodeId || source.topic || '').trim();
@@ -27,14 +53,44 @@ function normalizePoint(input, defaults = {}) {
27
53
  source.queueSize,
28
54
  positiveNumber(defaults.queueSize, DEFAULTS.queueSize)
29
55
  )),
30
- discardOldest: source.discardOldest == null
31
- ? defaults.discardOldest !== false
32
- : source.discardOldest !== false,
56
+ discardOldest: booleanValue(
57
+ source.discardOldest,
58
+ booleanValue(defaults.discardOldest, true)
59
+ ),
33
60
  };
34
61
 
62
+ const indexRange = normalizeIndexRange(
63
+ source.indexRange ?? source.range,
64
+ defaults.indexRange ?? defaults.range
65
+ );
66
+ if (indexRange) point.indexRange = indexRange;
67
+ else {
68
+ delete point.indexRange;
69
+ }
70
+ delete point.range;
71
+
35
72
  if (point.alias != null) point.alias = String(point.alias);
73
+ else delete point.alias;
36
74
  if (point.dataType != null) point.dataType = String(point.dataType);
37
- if (point.enabled == null) point.enabled = true;
75
+ else delete point.dataType;
76
+ if (point.deadbandType == null || point.deadbandType === '') delete point.deadbandType;
77
+ else {
78
+ const deadbandType = String(point.deadbandType).toLowerCase();
79
+ const normalizedDeadbandType = deadbandType === 'a' ? 'absolute' :
80
+ (deadbandType === 'p' ? 'percent' : deadbandType);
81
+ if (!['none', 'absolute', 'percent'].includes(normalizedDeadbandType)) {
82
+ throw new Error(`Invalid OPC UA deadband type: ${point.deadbandType}`);
83
+ }
84
+ point.deadbandType = normalizedDeadbandType;
85
+ }
86
+ if (point.deadbandValue == null || point.deadbandValue === '') delete point.deadbandValue;
87
+ else {
88
+ point.deadbandValue = Number(point.deadbandValue);
89
+ if (!Number.isFinite(point.deadbandValue) || point.deadbandValue < 0) {
90
+ throw new Error(`Invalid OPC UA deadband value: ${source.deadbandValue}`);
91
+ }
92
+ }
93
+ point.enabled = booleanValue(point.enabled, true);
38
94
  return point;
39
95
  }
40
96
 
@@ -94,20 +150,38 @@ function parseCsvLine(line) {
94
150
  return fields;
95
151
  }
96
152
 
97
- function parseCsv(text) {
98
- const lines = String(text)
99
- .replace(/^\uFEFF/, '')
100
- .split(/\r?\n/)
101
- .filter((line) => line.trim() && !line.trimStart().startsWith('#'));
102
- if (!lines.length) return [];
103
-
104
- const headers = parseCsvLine(lines.shift()).map((header) => header.trim());
105
- if (!headers.includes('nodeId')) throw new Error('CSV header must contain nodeId');
153
+ function forEachCsvLine(text, callback) {
154
+ const source = String(text).replace(/^\uFEFF/, '');
155
+ let start = 0;
156
+ let lineNumber = 0;
157
+ while (start <= source.length) {
158
+ let end = source.indexOf('\n', start);
159
+ if (end === -1) end = source.length;
160
+ const line = source.slice(start, end).replace(/\r$/, '');
161
+ lineNumber += 1;
162
+ if (line.trim() && !line.trimStart().startsWith('#')) callback(line, lineNumber);
163
+ if (end === source.length) break;
164
+ start = end + 1;
165
+ }
166
+ }
106
167
 
107
- return lines.map((line) => {
168
+ function parseCsv(text) {
169
+ let headers;
170
+ const rows = [];
171
+ forEachCsvLine(text, (line) => {
172
+ if (!headers) {
173
+ headers = parseCsvLine(line).map((header) => header.trim());
174
+ if (!headers.includes('nodeId')) throw new Error('CSV header must contain nodeId');
175
+ return;
176
+ }
108
177
  const values = parseCsvLine(line);
109
- return Object.fromEntries(headers.map((header, index) => [header, values[index] ?? '']));
178
+ const row = {};
179
+ for (let index = 0; index < headers.length; index += 1) {
180
+ row[headers[index]] = values[index] ?? '';
181
+ }
182
+ rows.push(row);
110
183
  });
184
+ return rows;
111
185
  }
112
186
 
113
187
  function parsePointPayload(payload, format = 'auto') {
@@ -157,7 +231,17 @@ function messagePoints(msg, staticNodeId, defaults = {}, options = {}) {
157
231
 
158
232
  const nodeId = staticNodeId || msg.nodeId || msg.topic;
159
233
  if (!nodeId) throw new Error('Missing OPC UA nodeId or point list');
160
- return [normalizePoint({ nodeId, alias: msg.alias, dataType: msg.dataType }, defaults)];
234
+ return [normalizePoint({
235
+ nodeId,
236
+ alias: msg.alias,
237
+ dataType: msg.dataType,
238
+ indexRange: msg.indexRange ?? msg.range ?? msg.opcua?.indexRange,
239
+ samplingInterval: msg.samplingInterval ?? msg.interval,
240
+ queueSize: msg.queueSize,
241
+ discardOldest: msg.discardOldest,
242
+ deadbandType: msg.deadbandType,
243
+ deadbandValue: msg.deadbandValue,
244
+ }, defaults)];
161
245
  }
162
246
 
163
247
  function coerceWriteValue(value, dataType) {
@@ -176,20 +260,101 @@ function coerceWriteValue(value, dataType) {
176
260
  return value;
177
261
  }
178
262
 
263
+ function parseWriteCsvPayload(payload, msg, config) {
264
+ const text = Buffer.isBuffer(payload) ? payload.toString('utf8') : String(payload);
265
+ let headers;
266
+ let nodeIdIndex = -1;
267
+ let valueIndex = -1;
268
+ let dataTypeIndex = -1;
269
+ let indexRangeIndex = -1;
270
+ let invalid = 0;
271
+ const points = new Map();
272
+
273
+ forEachCsvLine(text, (line) => {
274
+ if (!headers) {
275
+ headers = parseCsvLine(line).map((header) => header.trim());
276
+ nodeIdIndex = headers.indexOf('nodeId');
277
+ valueIndex = headers.indexOf('value');
278
+ dataTypeIndex = headers.indexOf('dataType');
279
+ indexRangeIndex = headers.indexOf('indexRange');
280
+ if (indexRangeIndex < 0) indexRangeIndex = headers.indexOf('range');
281
+ if (nodeIdIndex < 0) throw new Error('CSV header must contain nodeId');
282
+ return;
283
+ }
284
+
285
+ const values = parseCsvLine(line);
286
+ const nodeId = String(values[nodeIdIndex] || '').trim();
287
+ if (!nodeId) {
288
+ invalid += 1;
289
+ return;
290
+ }
291
+ const dataType = String(
292
+ (dataTypeIndex >= 0 ? values[dataTypeIndex] : '') ||
293
+ msg.dataType || config.dataType || 'String'
294
+ );
295
+ const value = valueIndex >= 0 ? values[valueIndex] : undefined;
296
+ const defaultIndexRange = msg.indexRange ?? msg.range ??
297
+ msg.opcua?.indexRange ?? config.indexRange;
298
+ const indexRange = normalizeIndexRange(
299
+ indexRangeIndex >= 0 ? values[indexRangeIndex] : undefined,
300
+ defaultIndexRange
301
+ );
302
+ points.set(nodeId, {
303
+ nodeId,
304
+ dataType,
305
+ value: coerceWriteValue(value, dataType),
306
+ ...(indexRange ? { indexRange } : {}),
307
+ });
308
+ });
309
+
310
+ if (invalid) throw new Error(`Invalid point list: ${invalid} item(s) failed validation`);
311
+ return [...points.values()];
312
+ }
313
+
179
314
  function messageWritePoints(msg, config = {}) {
180
315
  let points;
181
316
  let configuredPoints = false;
182
- if (looksLikePointList(msg.payload)) {
183
- points = normalizePointPayload(msg.payload, {}, { format: config.inputFormat || 'auto' }).points;
317
+ let configuredPointList;
318
+ const defaultIndexRange = msg.indexRange ?? msg.range ??
319
+ msg.opcua?.indexRange ?? config.indexRange;
320
+ if (config.pointList && Array.isArray(msg.payload)) {
321
+ configuredPointList = normalizePointPayload(
322
+ config.pointList, { indexRange: defaultIndexRange }, { format: 'auto' }
323
+ ).points;
324
+ }
325
+ const directNodeId = config.nodeId || msg.nodeId || msg.topic;
326
+ const arrayValue = Array.isArray(msg.payload) && msg.opcua?.pointList !== true && (
327
+ msg.opcua?.arrayValue === true || directNodeId ||
328
+ (configuredPointList?.length === 1 && configuredPointList[0].useInput)
329
+ );
330
+ if (!arrayValue && looksLikePointList(msg.payload)) {
331
+ const inputFormat = config.inputFormat || 'auto';
332
+ const hasTextPayload = typeof msg.payload === 'string' || Buffer.isBuffer(msg.payload);
333
+ const text = Buffer.isBuffer(msg.payload)
334
+ ? msg.payload.toString('utf8').trimStart()
335
+ : typeof msg.payload === 'string' ? msg.payload.trimStart() : '';
336
+ const isCsv = hasTextPayload && (inputFormat === 'csv' ||
337
+ (inputFormat === 'auto' && text && !text.startsWith('[') && !text.startsWith('{')));
338
+ if (isCsv) return parseWriteCsvPayload(msg.payload, msg, config);
339
+ points = normalizePointPayload(
340
+ msg.payload, { indexRange: defaultIndexRange }, { format: inputFormat }
341
+ ).points;
184
342
  } else if (msg.payload && typeof msg.payload === 'object' && msg.payload.nodeId) {
185
- points = normalizePoints([msg.payload]).points;
343
+ points = normalizePoints([msg.payload], { indexRange: defaultIndexRange }).points;
186
344
  } else if (config.pointList) {
187
- points = normalizePointPayload(config.pointList, {}, { format: 'auto' }).points;
345
+ points = configuredPointList ||
346
+ normalizePointPayload(
347
+ config.pointList, { indexRange: defaultIndexRange }, { format: 'auto' }
348
+ ).points;
188
349
  configuredPoints = true;
189
350
  } else {
190
351
  const nodeId = config.nodeId || msg.nodeId || msg.topic;
191
352
  if (!nodeId) throw new Error('Missing OPC UA nodeId or point list');
192
- points = normalizePoints([{ nodeId, value: msg.payload }]).points;
353
+ points = normalizePoints([{
354
+ nodeId,
355
+ value: msg.payload,
356
+ indexRange: defaultIndexRange,
357
+ }]).points;
193
358
  }
194
359
 
195
360
  return points.map((point) => {
@@ -223,6 +388,7 @@ module.exports = {
223
388
  looksLikePointList,
224
389
  messagePoints,
225
390
  messageWritePoints,
391
+ normalizeIndexRange,
226
392
  normalizePoint,
227
393
  normalizePointPayload,
228
394
  normalizePoints,
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ function linuxLibc(report) {
7
+ if (report?.header?.glibcVersionRuntime || report?.header?.glibcVersionCompiler) {
8
+ return 'glibc';
9
+ }
10
+ return 'musl';
11
+ }
12
+
13
+ function runtimeReport() {
14
+ try {
15
+ return process.report?.getReport?.();
16
+ } catch {
17
+ return undefined;
18
+ }
19
+ }
20
+
21
+ function prebuildKey(options = {}) {
22
+ const platform = options.platform || process.platform;
23
+ const arch = options.arch || process.arch;
24
+ if (platform !== 'linux') return `${platform}-${arch}`;
25
+ return `${platform}-${arch}-${linuxLibc(options.report || runtimeReport())}`;
26
+ }
27
+
28
+ function prebuildPath(packageRoot, options = {}) {
29
+ return path.join(
30
+ packageRoot,
31
+ 'prebuilds',
32
+ prebuildKey(options),
33
+ 'opcua_open62541.node'
34
+ );
35
+ }
36
+
37
+ function resolvePrebuilt(packageRoot, options = {}) {
38
+ const candidate = prebuildPath(packageRoot, options);
39
+ return fs.existsSync(candidate) ? candidate : undefined;
40
+ }
41
+
42
+ module.exports = { linuxLibc, prebuildKey, prebuildPath, resolvePrebuilt };
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ const SECURITY_POLICY_URIS = Object.freeze({
4
+ None: 'http://opcfoundation.org/UA/SecurityPolicy#None',
5
+ Basic256Sha256: 'http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256',
6
+ });
7
+
8
+ const SECURITY_MODES = new Set(['None', 'Sign', 'SignAndEncrypt']);
9
+
10
+ function configurationError(message) {
11
+ const error = new Error(message);
12
+ error.code = 'OPCUA_INVALID_SECURITY_CONFIGURATION';
13
+ return error;
14
+ }
15
+
16
+ function normalizePathList(value) {
17
+ const source = Array.isArray(value)
18
+ ? value
19
+ : String(value || '').split(/\r?\n|;/);
20
+ return [...new Set(source.map((entry) => String(entry || '').trim()).filter(Boolean))];
21
+ }
22
+
23
+ function securityPolicyName(value) {
24
+ const policy = String(value || 'None').trim();
25
+ if (SECURITY_POLICY_URIS[policy]) return policy;
26
+ const match = Object.entries(SECURITY_POLICY_URIS).find(([, uri]) => uri === policy);
27
+ return match?.[0] || policy;
28
+ }
29
+
30
+ function normalizeConnectionOptions(options = {}) {
31
+ const normalized = {
32
+ ...options,
33
+ endpoint: String(options.endpoint || '').trim(),
34
+ securityMode: String(options.securityMode || 'None').trim(),
35
+ securityPolicy: securityPolicyName(options.securityPolicy),
36
+ certificate: String(options.certificate || '').trim(),
37
+ privateKey: String(options.privateKey || '').trim(),
38
+ applicationUri: String(options.applicationUri || '').trim(),
39
+ trustedCertificates: normalizePathList(
40
+ options.trustedCertificates ?? options.trustList
41
+ ),
42
+ revocationList: normalizePathList(options.revocationList),
43
+ };
44
+
45
+ if (!normalized.endpoint) throw configurationError('OPC UA endpoint is required');
46
+ if (!SECURITY_MODES.has(normalized.securityMode)) {
47
+ throw configurationError(`Unsupported OPC UA security mode: ${normalized.securityMode}`);
48
+ }
49
+ if (!SECURITY_POLICY_URIS[normalized.securityPolicy]) {
50
+ throw configurationError(`Unsupported OPC UA security policy: ${normalized.securityPolicy}`);
51
+ }
52
+ if (normalized.securityMode === 'None') {
53
+ if (normalized.securityPolicy !== 'None') {
54
+ throw configurationError('SecurityMode None requires SecurityPolicy None');
55
+ }
56
+ } else {
57
+ if (normalized.securityPolicy === 'None') {
58
+ throw configurationError(`${normalized.securityMode} requires a non-None security policy`);
59
+ }
60
+ if (!normalized.certificate) {
61
+ throw configurationError('Secure OPC UA connections require a client certificate');
62
+ }
63
+ if (!normalized.privateKey) {
64
+ throw configurationError('Secure OPC UA connections require a client private key');
65
+ }
66
+ if (!normalized.trustedCertificates.length) {
67
+ throw configurationError('Secure OPC UA connections require at least one trusted server or CA certificate');
68
+ }
69
+ }
70
+
71
+ normalized.securityPolicyUri = SECURITY_POLICY_URIS[normalized.securityPolicy];
72
+ return normalized;
73
+ }
74
+
75
+ function endpointIdentityTypes(endpoint) {
76
+ return [...new Set((endpoint?.userIdentityTokens || []).map((token) => token.tokenType))];
77
+ }
78
+
79
+ function matchingEndpoints(endpoints, options = {}) {
80
+ const mode = String(options.securityMode || 'None');
81
+ const policy = securityPolicyName(options.securityPolicy);
82
+ const identityType = String(options.identityType || (options.user ? 'Username' : 'Anonymous'));
83
+ return (Array.isArray(endpoints) ? endpoints : []).filter((endpoint) => (
84
+ endpoint.securityMode === mode &&
85
+ securityPolicyName(endpoint.securityPolicyUri || endpoint.securityPolicy) === policy &&
86
+ endpointIdentityTypes(endpoint).includes(identityType)
87
+ ));
88
+ }
89
+
90
+ module.exports = {
91
+ SECURITY_POLICY_URIS,
92
+ matchingEndpoints,
93
+ normalizeConnectionOptions,
94
+ normalizePathList,
95
+ securityPolicyName,
96
+ };
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 [Node.js API collaborators](https://github.com/nodejs/node-addon-api#collaborators)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # **node-addon-api module**
2
+
3
+ [![codecov](https://codecov.io/gh/nodejs/node-addon-api/branch/main/graph/badge.svg)](https://app.codecov.io/gh/nodejs/node-addon-api/tree/main)
4
+
5
+ [![NPM](https://nodei.co/npm/node-addon-api.png?downloads=true&downloadRank=true)](https://nodei.co/npm/node-addon-api/) [![NPM](https://nodei.co/npm-dl/node-addon-api.png?months=6&height=1)](https://nodei.co/npm/node-addon-api/)
6
+
7
+ This module contains **header-only C++ wrapper classes** which simplify
8
+ the use of the C based [Node-API](https://nodejs.org/dist/latest/docs/api/n-api.html)
9
+ provided by Node.js when using C++. It provides a C++ object model
10
+ and exception handling semantics with low overhead.
11
+
12
+ - [API References](doc/README.md)
13
+ - [Badges](#badges)
14
+ - [Contributing](#contributing)
15
+ - [License](#license)
16
+
17
+ ## API References
18
+
19
+ API references are available in the [doc](doc/README.md) directory.
20
+
21
+ <!-- x-release-please-start-version -->
22
+ ## Current version: 8.9.1
23
+ <!-- x-release-please-end -->
24
+
25
+ (See [CHANGELOG.md](CHANGELOG.md) for complete Changelog)
26
+
27
+ node-addon-api is based on [Node-API](https://nodejs.org/api/n-api.html) and supports using different Node-API versions.
28
+ This allows addons built with it to run with Node.js versions which support the targeted Node-API version.
29
+ **However** the node-addon-api support model is to support only the active LTS Node.js versions. This means that
30
+ every year there will be a new major which drops support for the Node.js LTS version which has gone out of service.
31
+
32
+ The oldest Node.js version supported by the current version of node-addon-api is Node.js 18.x.
33
+
34
+ ## Badges
35
+
36
+ The use of badges is recommended to indicate the minimum version of Node-API
37
+ required for the module. This helps to determine which Node.js major versions are
38
+ supported. Addon maintainers can consult the [Node-API support matrix][] to determine
39
+ which Node.js versions provide a given Node-API version. The following badges are
40
+ available:
41
+
42
+ ![Node-API v1 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v1%20Badge.svg)
43
+ ![Node-API v2 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v2%20Badge.svg)
44
+ ![Node-API v3 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v3%20Badge.svg)
45
+ ![Node-API v4 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v4%20Badge.svg)
46
+ ![Node-API v5 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v5%20Badge.svg)
47
+ ![Node-API v6 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v6%20Badge.svg)
48
+ ![Node-API v7 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v7%20Badge.svg)
49
+ ![Node-API v8 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v8%20Badge.svg)
50
+ ![Node-API v9 Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20v9%20Badge.svg)
51
+ ![Node-API Experimental Version Badge](https://github.com/nodejs/abi-stable-node/blob/doc/assets/Node-API%20Experimental%20Version%20Badge.svg)
52
+
53
+ ## Contributing
54
+
55
+ We love contributions from the community to **node-addon-api**!
56
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more details on our philosophy around extending this module.
57
+
58
+ ## Team members
59
+
60
+ ### Active
61
+
62
+ | Name | GitHub Link |
63
+ | ------------------- | ----------------------------------------------------- |
64
+ | Anna Henningsen | [addaleax](https://github.com/addaleax) |
65
+ | Chengzhong Wu | [legendecas](https://github.com/legendecas) |
66
+ | Jack Xia | [JckXia](https://github.com/JckXia) |
67
+ | Kevin Eady | [KevinEady](https://github.com/KevinEady) |
68
+ | Michael Dawson | [mhdawson](https://github.com/mhdawson) |
69
+ | Nicola Del Gobbo | [NickNaso](https://github.com/NickNaso) |
70
+ | Vladimir Morozov | [vmoroz](https://github.com/vmoroz) |
71
+
72
+ <details>
73
+
74
+ <summary>Emeritus</summary>
75
+
76
+ ### Emeritus
77
+
78
+ | Name | GitHub Link |
79
+ | ------------------- | ----------------------------------------------------- |
80
+ | Arunesh Chandra | [aruneshchandra](https://github.com/aruneshchandra) |
81
+ | Benjamin Byholm | [kkoopa](https://github.com/kkoopa) |
82
+ | Gabriel Schulhof | [gabrielschulhof](https://github.com/gabrielschulhof) |
83
+ | Hitesh Kanwathirtha | [digitalinfinity](https://github.com/digitalinfinity) |
84
+ | Jason Ginchereau | [jasongin](https://github.com/jasongin) |
85
+ | Jim Schlight | [jschlight](https://github.com/jschlight) |
86
+ | Sampson Gao | [sampsongao](https://github.com/sampsongao) |
87
+ | Taylor Woll | [boingoing](https://github.com/boingoing) |
88
+
89
+ </details>
90
+
91
+ ## License
92
+
93
+ Licensed under [MIT](./LICENSE.md)
94
+
95
+ [Node-API support matrix]: https://nodejs.org/dist/latest/docs/api/n-api.html#node-api-version-matrix
@@ -0,0 +1,21 @@
1
+ {
2
+ 'variables': {
3
+ 'NAPI_VERSION%': "<!(node -p \"process.env.NAPI_VERSION || process.versions.napi\")",
4
+ 'disable_deprecated': "<!(node -p \"process.env['npm_config_disable_deprecated']\")"
5
+ },
6
+ 'conditions': [
7
+ ['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
8
+ ['NAPI_VERSION==2147483647', { 'defines': ['NAPI_EXPERIMENTAL', 'NODE_API_EXPERIMENTAL_NO_WARNING'] } ],
9
+ ['disable_deprecated=="true"', {
10
+ 'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
11
+ }],
12
+ ['OS=="mac"', {
13
+ 'cflags+': ['-fvisibility=hidden'],
14
+ 'xcode_settings': {
15
+ 'OTHER_CFLAGS': ['-fvisibility=hidden']
16
+ }
17
+ }]
18
+ ],
19
+ 'cflags': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ],
20
+ 'cflags_cc': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ]
21
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ 'defines': [ 'NAPI_CPP_EXCEPTIONS' ],
3
+ 'cflags!': [ '-fno-exceptions' ],
4
+ 'cflags_cc!': [ '-fno-exceptions' ],
5
+ 'conditions': [
6
+ ["OS=='win'", {
7
+ "defines": [
8
+ "_HAS_EXCEPTIONS=1"
9
+ ],
10
+ "msvs_settings": {
11
+ "VCCLCompilerTool": {
12
+ "ExceptionHandling": 1,
13
+ 'EnablePREfast': 'true',
14
+ },
15
+ },
16
+ }],
17
+ ["OS=='mac'", {
18
+ 'xcode_settings': {
19
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
20
+ 'CLANG_CXX_LIBRARY': 'libc++',
21
+ 'MACOSX_DEPLOYMENT_TARGET': '10.7',
22
+ },
23
+ }],
24
+ ],
25
+ }
@@ -0,0 +1,14 @@
1
+ const path = require('path');
2
+ const { version } = require('./package.json');
3
+
4
+ const includeDir = path.relative('.', __dirname);
5
+
6
+ module.exports = {
7
+ include: `"${__dirname}"`, // deprecated, can be removed as part of 4.0.0
8
+ include_dir: includeDir,
9
+ gyp: path.join(includeDir, 'node_api.gyp:nothing'), // deprecated.
10
+ targets: path.join(includeDir, 'node_addon_api.gyp'),
11
+ version,
12
+ isNodeApiBuiltin: true,
13
+ needsFlag: false
14
+ };