syscall-napi 0.1.3 → 0.1.4

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/README.md CHANGED
@@ -6,9 +6,11 @@ Node.js module to perform promise-based asynchronous syscalls
6
6
 
7
7
  This module allows to execute syscalls on linux based systems. NAPI is being used to stay ABI compatible with future Node.js versions. The focus of this module is not (yet) performance, but providing a clear interface to the linux kernel.
8
8
 
9
+ Previously this module supported asynchronous operation, which turned out not to work as expected. Although it would be possible, currently this is not supported anymore. If you need to execute long running syscalls in parallel, use Workers.
10
+
9
11
  ## Requirements
10
12
 
11
- - `Node.js >= 22` as this is a native TypeScript module
13
+ - `Node.js >= 20`, might work on older
12
14
 
13
15
  ## Installation
14
16
 
@@ -24,7 +26,8 @@ yarn install syscall-napi
24
26
 
25
27
  ## API
26
28
 
27
- ### `syscall({ syscallNumber: bigint, args: (bigint | Uint8Array)[] })` => `{ errno: undefined, ret: BigInt } | { errno: number, ret: undefined }`
29
+ `syscall({ syscallNumber: bigint, args: (bigint | Uint8Array)[] })`
30
+ => `{ errno: undefined, ret: BigInt } | { errno: number, ret: undefined }`
28
31
 
29
32
  Supported argument types:
30
33
  - `BigInt` arguments are converted to native integers
@@ -33,7 +36,7 @@ Supported argument types:
33
36
  In case of an error the promise is rejected with an error object.
34
37
 
35
38
  For params see `man 2 syscall`.
36
-
39
+
37
40
  ### `syscallNumbers.{syscall}`
38
41
  This module provides syscall numbers (e.g. `getpid`) that are defined in `uapi/asm-generic/unistd.h` in the linux kernel.
39
42
 
@@ -43,7 +46,7 @@ This module provides syscall numbers (e.g. `getpid`) that are defined in `uapi/a
43
46
  import { syscall, syscallNumbers } from "syscall-napi";
44
47
 
45
48
  const { errno, ret: pid } = syscall({
46
- syscallNumber: syscallNumbers.__NR_getpid,
49
+ syscallNumber: syscallNumbers.getpid,
47
50
  args: []
48
51
  });
49
52
 
@@ -52,4 +55,5 @@ if (errno === undefined) {
52
55
  } else {
53
56
  console.log(`errno = ${errno}`);
54
57
  }
58
+
55
59
  ```
@@ -2,7 +2,7 @@ import { createNativeAddonLoader } from "./snippets/native-loader.js";
2
2
 
3
3
  const nativeAddonLoader = createNativeAddonLoader();
4
4
  const native = nativeAddonLoader.loadRelativeToPackageRoot({
5
- relativeBuildFolderPath: "./build"
5
+ relativeBuildFolderPath: "./build"
6
6
  });
7
7
 
8
8
  /*type TSyscallSync = (args: bigint, ...rest: (bigint | Uint8Array)[]) => { errno: number; ret?: bigint; };*/
@@ -10,5 +10,5 @@ const native = nativeAddonLoader.loadRelativeToPackageRoot({
10
10
  const syscall_sync = native.syscall_sync /*as TSyscallSync*/;
11
11
 
12
12
  export {
13
- syscall_sync
13
+ syscall_sync
14
14
  };
@@ -4,118 +4,155 @@ import nodePath from "node:path";
4
4
  import nodeModule from "node:module";
5
5
 
6
6
  const findPackageJson = ({ startPath, maxUpwardSteps }/*: { startPath: string; maxUpwardSteps: number }*/) => {
7
- let currentPath = startPath;
7
+ let currentPath = startPath;
8
8
 
9
- for (let i = 0; i < maxUpwardSteps; i += 1) {
10
- const packageJsonPath = nodePath.join(currentPath, "package.json");
9
+ for (let i = 0; i < maxUpwardSteps; i += 1) {
10
+ const packageJsonPath = nodePath.join(currentPath, "package.json");
11
11
 
12
- if (nodeFs.existsSync(packageJsonPath)) {
13
- return packageJsonPath;
14
- }
15
-
16
- const parentPath = nodePath.dirname(currentPath);
12
+ if (nodeFs.existsSync(packageJsonPath)) {
13
+ return packageJsonPath;
14
+ }
17
15
 
18
- // Reached filesystem root
19
- if (parentPath === currentPath) {
20
- break;
21
- }
16
+ const parentPath = nodePath.dirname(currentPath);
22
17
 
23
- currentPath = parentPath;
18
+ // Reached filesystem root
19
+ if (parentPath === currentPath) {
20
+ break;
24
21
  }
25
22
 
26
- throw new Error(`Could not find package.json within ${maxUpwardSteps} directory levels from ${startPath}`);
23
+ currentPath = parentPath;
24
+ }
25
+
26
+ throw new Error(`Could not find package.json within ${maxUpwardSteps} directory levels from ${startPath}`);
27
27
  };
28
28
 
29
29
  const findPackageRoot = ({ maxUpwardSteps }/*: { maxUpwardSteps: number }*/) => {
30
- const ourScriptUrl = import.meta.url;
31
- const ourScriptPath = nodeUrl.fileURLToPath(ourScriptUrl);
32
- const ourScriptDirectory = nodePath.dirname(ourScriptPath);
30
+ const ourScriptUrl = import.meta.url;
31
+ const ourScriptPath = nodeUrl.fileURLToPath(ourScriptUrl);
32
+ const ourScriptDirectory = nodePath.dirname(ourScriptPath);
33
33
 
34
- const ourPackageJsonPath = findPackageJson({
35
- startPath: ourScriptDirectory,
36
- maxUpwardSteps,
37
- });
34
+ const ourPackageJsonPath = findPackageJson({
35
+ startPath: ourScriptDirectory,
36
+ maxUpwardSteps,
37
+ });
38
38
 
39
- const ourPackageRoot = nodePath.dirname(ourPackageJsonPath);
39
+ const ourPackageRoot = nodePath.dirname(ourPackageJsonPath);
40
40
 
41
- return ourPackageRoot;
41
+ return ourPackageRoot;
42
42
  };
43
43
 
44
44
  const findAddonInAddonFolder = ({ addonFolderPath }/*: { addonFolderPath: string }*/) => {
45
- const entries = nodeFs.readdirSync(addonFolderPath);
45
+ const entries = nodeFs.readdirSync(addonFolderPath);
46
46
 
47
- const addonEntries = entries.filter((entry) => {
48
- return entry.endsWith(".node");
49
- });
47
+ const addonEntries = entries.filter((entry) => {
48
+ return entry.endsWith(".node");
49
+ });
50
50
 
51
- if (addonEntries.length === 0) {
52
- throw Error(`no .node addon file found in build folder "${addonFolderPath}"`);
53
- }
51
+ if (addonEntries.length === 0) {
52
+ throw Error(`no .node addon file found in build folder "${addonFolderPath}"`);
53
+ }
54
54
 
55
- if (addonEntries.length > 1) {
56
- throw Error(`multiple .node addon files found in build folder "${addonFolderPath}", cannot determine which to load`);
57
- }
55
+ if (addonEntries.length > 1) {
56
+ throw Error(`multiple .node addon files found in build folder "${addonFolderPath}", cannot determine which to load`);
57
+ }
58
58
 
59
- const addonFileName = addonEntries[0];
59
+ const addonFileName = addonEntries[0];
60
60
 
61
- return addonFileName;
61
+ return addonFileName;
62
62
  };
63
63
 
64
64
  const loadAddonAtPath = ({ addonFilePath }/*: { addonFilePath: string }*/) => {
65
- const require = nodeModule.createRequire(import.meta.url);
65
+ const require = nodeModule.createRequire(import.meta.url);
66
66
 
67
- const native = require(addonFilePath);
67
+ const native = require(addonFilePath);
68
68
 
69
- return native;
69
+ return native;
70
70
  };
71
71
 
72
- const createNativeAddonLoader = () => {
72
+ const assertOnlyOneOfDebugOrReleaseExists = ({
73
+ debugFolderExists,
74
+ releaseFolderExists
75
+ }/*: {
76
+ debugFolderExists: boolean;
77
+ releaseFolderExists: boolean
78
+ }*/) => {
79
+ if (debugFolderExists && releaseFolderExists) {
80
+ throw Error(`both Debug and Release build folders exist, please remove one to avoid ambiguity`);
81
+ }
82
+ };
83
+
84
+ const assertAtLeastOneOfDebugOrReleaseExists = ({
85
+ debugFolderExists,
86
+ releaseFolderExists
87
+ }/*: {
88
+ debugFolderExists: boolean;
89
+ releaseFolderExists: boolean
90
+ }*/) => {
91
+ if (!debugFolderExists && !releaseFolderExists) {
92
+ throw Error(`neither Debug nor Release build folders found, make sure to build the native addon first`);
93
+ }
94
+ };
73
95
 
74
- const loadRelativeToPackageRoot = ({ relativeBuildFolderPath }/*: { relativeBuildFolderPath: string }*/) => {
75
- let packageRoot/*: string*/;
76
-
77
- try {
78
- packageRoot = findPackageRoot({ maxUpwardSteps: 10 });
79
- } catch (err) {
80
- throw Error(`could not find our package root, make sure to keep the package structure intact when distributing the package - a package.json and built addon at ./build are required`);
81
- }
96
+ const determineReleaseOrDebugFolder = ({ buildFolderPath }/*: { buildFolderPath: string }*/) => {
97
+ const debugFolderPath = nodePath.join(buildFolderPath, "Debug");
98
+ const releaseFolderPath = nodePath.join(buildFolderPath, "Release");
82
99
 
83
- const buildFolderPath = nodePath.join(packageRoot, relativeBuildFolderPath);
100
+ const debugFolderExists = nodeFs.existsSync(debugFolderPath);
101
+ const releaseFolderExists = nodeFs.existsSync(releaseFolderPath);
84
102
 
85
- if (!nodeFs.existsSync(buildFolderPath)) {
86
- throw Error(`no build folder found at our package root "${buildFolderPath}", make sure to build the native addon first`);
87
- }
103
+ try {
104
+ assertAtLeastOneOfDebugOrReleaseExists({ debugFolderExists, releaseFolderExists });
105
+ assertOnlyOneOfDebugOrReleaseExists({ debugFolderExists, releaseFolderExists });
106
+ } catch (ex) {
107
+ throw Error(`invalid build folder structure at "${buildFolderPath}"`, { cause: ex });
108
+ }
88
109
 
89
- const debugFolderPath = nodePath.join(buildFolderPath, "Debug");
90
- const releaseFolderPath = nodePath.join(buildFolderPath, "Release");
110
+ const addonFolderPath = releaseFolderExists ? releaseFolderPath : debugFolderPath;
91
111
 
92
- const debugFolderExists = nodeFs.existsSync(debugFolderPath);
93
- const releaseFolderExists = nodeFs.existsSync(releaseFolderPath);
112
+ return addonFolderPath;
113
+ };
114
+
115
+ const loadAddonFromFolder = ({ addonFolderPath }/*: { addonFolderPath: string }*/) => {
116
+ const addonFileName = findAddonInAddonFolder({ addonFolderPath });
117
+
118
+ const addonFilePath = nodePath.resolve(addonFolderPath, addonFileName);
119
+
120
+ const native = loadAddonAtPath({ addonFilePath });
121
+
122
+ return native;
123
+ };
94
124
 
95
- if (!debugFolderExists && !releaseFolderExists) {
96
- throw Error(`neither Debug nor Release build folders found at our package root "${buildFolderPath}", make sure to build the native addon first`);
97
- }
125
+ const createNativeAddonLoader = () => {
98
126
 
99
- if (debugFolderExists && releaseFolderExists) {
100
- throw Error(`both Debug and Release build folders exist at our package root "${buildFolderPath}", please remove one to avoid ambiguity`);
101
- }
127
+ const loadRelativeToPackageRoot = ({ relativeBuildFolderPath }/*: { relativeBuildFolderPath: string }*/) => {
128
+ let packageRoot/*: string*/;
102
129
 
103
- const addonFolderPath = releaseFolderExists ? releaseFolderPath : debugFolderPath;
130
+ try {
131
+ packageRoot = findPackageRoot({ maxUpwardSteps: 10 });
132
+ } catch (err) {
133
+ let message = "could not find our package root";
134
+ message += ", make sure to keep the package structure intact when distributing the package";
135
+ message += " - a package.json and built addon at ./build are required";
136
+ throw Error(message, { cause: err });
137
+ }
104
138
 
105
- const addonFileName = findAddonInAddonFolder({ addonFolderPath });
139
+ const buildFolderPath = nodePath.join(packageRoot, relativeBuildFolderPath);
106
140
 
107
- const addonFilePath = nodePath.resolve(addonFolderPath, addonFileName);
141
+ if (!nodeFs.existsSync(buildFolderPath)) {
142
+ throw Error(`no build folder found at our package root "${buildFolderPath}", make sure to build the native addon first`);
143
+ }
108
144
 
109
- const native = loadAddonAtPath({ addonFilePath });
145
+ const addonFolderPath = determineReleaseOrDebugFolder({ buildFolderPath });
146
+ const native = loadAddonFromFolder({ addonFolderPath });
110
147
 
111
- return native;
112
- };
148
+ return native;
149
+ };
113
150
 
114
- return {
115
- loadRelativeToPackageRoot,
116
- };
151
+ return {
152
+ loadRelativeToPackageRoot,
153
+ };
117
154
  };
118
155
 
119
156
  export {
120
- createNativeAddonLoader,
157
+ createNativeAddonLoader,
121
158
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
+ "version": "0.1.4",
2
3
  "name": "syscall-napi",
3
4
  "type": "module",
4
- "version": "0.1.3",
5
5
  "description": "Node.js module to perform synchronous syscalls",
6
6
  "files": [
7
7
  "dist/**/*",
@@ -12,11 +12,11 @@
12
12
  "scripts": {
13
13
  "build": "rm -rf dist/ && deno-node-build --root . --out dist/ --entry lib/index.ts",
14
14
  "test": "c8 --reporter lcov --reporter html --reporter text mocha test/**/*.ts",
15
- "eslint": "eslint ."
15
+ "lint": "eslint ."
16
16
  },
17
17
  "devDependencies": {
18
18
  "@eslint/js": "^9.39.2",
19
- "@k13engineering/releasetool": "^0.0.1",
19
+ "@k13engineering/releasetool": "^0.0.5",
20
20
  "@types/mocha": "^10.0.10",
21
21
  "@types/node": "^25.0.3",
22
22
  "c8": "^10.1.3",