koffi 3.0.0 → 3.0.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@
7
7
 
8
8
  ### Koffi 3.0
9
9
 
10
+ #### Koffi 3.0.1
11
+
12
+ *Released on 2026-05-20*
13
+
14
+ - Fix error when importing default koffi module from TypeScript
15
+ - Optimize creation of new JS objects for return values
16
+ - Adjust build flags for performance
17
+
10
18
  #### Koffi 3.0.0
11
19
 
12
20
  *Released on 2026-05-16*
@@ -22,10 +30,10 @@
22
30
  * Use `koffi.type()` to resolve type specifiers (strings or objects) to type objects
23
31
  * Access type information directly on type objects without `koffi.introspect()`
24
32
  - Replace use of externals with BigInt pointers
25
- - Support ESM and CJS module types
26
33
 
27
34
  **Other changes:**
28
35
 
36
+ - Support ESM and CJS module types
29
37
  - Add `koffi.enumeration()` to create [enum types](input#enum-types)
30
38
  - Add fast decode functions for integers, floats and strings
31
39
  - Use proper types for various objects and handles:
package/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Overview
2
2
 
3
- Koffi is a fast and easy-to-use C FFI module for Node.js, featuring:
3
+ Koffi is a fast and easy-to-use dynamic C FFI module for Node.js, featuring:
4
4
 
5
- * Low-overhead and fast performance (see [benchmarks](https://koffi.dev/benchmarks))
5
+ * Low-overhead compared to a static Node-API implementation (see [benchmarks](https://koffi.dev/benchmarks))
6
6
  * Support for primitive and aggregate data types (structs and fixed-size arrays), both by reference (pointer) and by value
7
+ * Support for synchronous and asynchronous calls
7
8
  * Javascript functions can be used as C callbacks
8
9
  * Well-tested code base for popular OS/architecture combinations
9
10
 
@@ -14,11 +15,11 @@ ISA / OS | Windows | Linux/glibc | Linux/musl | macOS | Fre
14
15
  x86 (IA32) [^1] | ✅ Yes | ✅ Yes | 🟨 Probably | ⬜️ *N/A* | ✅ Yes | ✅ Yes
15
16
  x86_64 (AMD64) | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes
16
17
  ARM64 (AArch64) LE | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | 🟨 Probably
17
- RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | 🟨 Probably | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
18
+ RISC-V 64 [^2] | ⬜️ *N/A* | ✅ Yes | 🟨 Probably | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
18
19
  LoongArch64 | ⬜️ *N/A* | ✅ Yes | 🟨 Probably | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
19
20
 
20
21
  [^1]: The following call conventions are supported: cdecl, stdcall, MS fastcall, thiscall.
21
- [^3]: The prebuilt binary uses the LP64D (double-precision float) ABI. The LP64 ABI is supported in theory if you build Koffi from source but this is untested. The LP64F ABI is not supported.
22
+ [^2]: The prebuilt binary uses the LP64D (double-precision float) ABI. The LP64 ABI is supported in theory if you build Koffi from source but this is untested. The LP64F ABI is not supported.
22
23
 
23
24
  Go to the web site for more information: https://koffi.dev/
24
25
 
package/cnoke.cjs CHANGED
@@ -34,7 +34,7 @@ var import_node_child_process = require("node:child_process");
34
34
  // ../cnoke/src/abi.js
35
35
  var import_node_fs = __toESM(require("node:fs"), 1);
36
36
  function determineAbi() {
37
- let abi = process.arch;
37
+ let abi = process.arch.toString();
38
38
  if (abi == "riscv32" || abi == "riscv64") {
39
39
  let buf = readFileHeader(process.execPath, 512);
40
40
  let header = decodeElfHeader(buf);
@@ -586,9 +586,9 @@ function Builder(config = {}) {
586
586
  let major = parseInt(runtime_version, 10);
587
587
  let required = getNapiVersion(options2.napi, major);
588
588
  if (required == null)
589
- throw new Error(`Project ${options2.name} does not support the Node ${major}.x branch (old or missing N-API)`);
589
+ throw new Error(`Project ${options2.name} does not support the Node ${major}.x branch (old or missing Node-API)`);
590
590
  if (compareVersions(runtime_version, required) < 0)
591
- throw new Error(`Project ${options2.name} requires Node >= ${required} in the Node ${major}.x branch (with N-API >= ${options2.napi})`);
591
+ throw new Error(`Project ${options2.name} requires Node >= ${required} in the Node ${major}.x branch (with Node-API >= ${options2.napi})`);
592
592
  }
593
593
  }
594
594
  function readCNokeOptions() {
package/doc/benchmarks.md CHANGED
@@ -1,86 +1,63 @@
1
1
  # Overview
2
2
 
3
- Here is a quick overview of the execution time of Koffi calls on three benchmarks, where it is compared to a theoretical ideal FFI implementation (approximated with pre-compiled static N-API glue code):
3
+ This pages presents the execution time of Koffi calls on three benchmarks, where it is compared to a theoretical ideal FFI implementation (approximated with pre-compiled static Node-API glue code), and other FFI implementations:
4
4
 
5
- - The first benchmark is based on `rand()` calls
6
- - The second benchmark is based on `atoi()` calls
7
- - The third benchmark is based on `memset()` calls
8
-
9
- <div class="benchmark chart" data-platform="linux_x64"></div>
10
- <div class="benchmark chart" data-platform="win32_x64"></div>
11
- <div class="benchmark chart" data-platform="darwin_arm64"></div>
12
-
13
- These results are detailed and explained below, and compared to node-ffi/node-ffi-napi.
5
+ - The first benchmark is based on `atoi()` calls
6
+ - The second benchmark is based on `memset()` calls
14
7
 
15
8
  # Linux x86_64
16
9
 
17
10
  The results presented below were measured on my x86_64 Linux machine (Intel® Core™ Ultra 9 185H).
18
11
 
19
- ## rand results
20
-
21
- This test is based around repeated calls to a simple standard C function `rand`, which takes no parameter and returns a 32-bit integer.
22
-
23
- <div class="benchmark table" data-platform="linux_x64" data-benchmark="rand"></div>
24
-
25
- Because rand is a pretty small function, the FFI overhead is clearly visible.
12
+ <div class="benchmark chart" data-platform="linux_x64"></div>
26
13
 
27
- ## atoi results
14
+ ## atoi results for Linux x86_64 ^ atoi results
28
15
 
29
- This test is similar to the rand one, but it is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
16
+ This test is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
30
17
 
31
18
  <div class="benchmark table" data-platform="linux_x64" data-benchmark="atoi"></div>
32
19
 
33
- ## memset results
20
+ ## memset results for Linux x86_64 ^ memset results
34
21
 
35
22
  This test is based around repeated calls to the standard C function `memset`. All implementations pass a Node.js Buffer for the pointer argument.
36
23
 
37
24
  <div class="benchmark table" data-platform="linux_x64" data-benchmark="memset"></div>
38
25
 
39
- # Windows x86_64
40
-
41
- The results presented below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460).
42
-
43
- ## rand results
26
+ # macOS ARM64
44
27
 
45
- This test is based around repeated calls to a simple standard C function `rand`, which takes no parameter and returns a 32-bit integer.
28
+ The results presented below were measured on an Apple Mac mini M2 hosted by Scaleway.
46
29
 
47
- <div class="benchmark table" data-platform="win32_x64" data-benchmark="rand"></div>
30
+ <div class="benchmark chart" data-platform="darwin_arm64"></div>
48
31
 
49
- ## atoi results
32
+ ## atoi results for macOS ARM64 ^ atoi results
50
33
 
51
- This test is similar to the rand one, but it is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
34
+ This test is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
52
35
 
53
- <div class="benchmark table" data-platform="win32_x64" data-benchmark="atoi"></div>
36
+ <div class="benchmark table" data-platform="darwin_arm64" data-benchmark="atoi"></div>
54
37
 
55
- ## memset results
38
+ ## memset results for macOS ARM64 ^ memset results
56
39
 
57
40
  This test is based around repeated calls to the standard C function `memset`. All implementations pass a Node.js Buffer for the pointer argument.
58
41
 
59
- <div class="benchmark table" data-platform="win32_x64" data-benchmark="memset"></div>
60
-
61
- # macOS ARM64
62
-
63
- The results presented below were measured on an Apple Mac mini M2 hosted by Scaleway.
64
-
65
- ## rand results
42
+ <div class="benchmark table" data-platform="darwin_arm64" data-benchmark="memset"></div>
66
43
 
67
- This test is based around repeated calls to a simple standard C function `rand`, which takes no parameter and returns a 32-bit integer.
44
+ # Windows x86_64
68
45
 
69
- <div class="benchmark table" data-platform="darwin_arm64" data-benchmark="rand"></div>
46
+ The results presented below were measured on my x86_64 Windows machine (AMD Ryzen™ 5 2600).
70
47
 
71
- Because rand is a pretty small function, the FFI overhead is clearly visible.
48
+ <div class="benchmark chart" data-platform="win32_x64"></div>
72
49
 
73
- ## atoi results
50
+ ## atoi results for Windows x86_64 ^ atoi results
74
51
 
75
- This test is similar to the rand one, but it is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
52
+ This test is based on `atoi`, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
76
53
 
77
- <div class="benchmark table" data-platform="darwin_arm64" data-benchmark="atoi"></div>
54
+ <div class="benchmark table" data-platform="win32_x64" data-benchmark="atoi"></div>
78
55
 
79
- ## memset results
56
+ ## memset results for Windows x86_64 ^ memset results
80
57
 
81
58
  This test is based around repeated calls to the standard C function `memset`. All implementations pass a Node.js Buffer for the pointer argument.
82
59
 
83
- <div class="benchmark table" data-platform="darwin_arm64" data-benchmark="memset"></div>
60
+ <div class="benchmark table" data-platform="win32_x64" data-benchmark="memset"></div>
84
61
 
85
62
  # Running benchmarks
86
63
 
package/doc/callbacks.md CHANGED
@@ -142,19 +142,10 @@ koffi.unregister(cb1);
142
142
  koffi.unregister(cb2);
143
143
  ```
144
144
 
145
- Starting *with Koffi 2.2*, you can optionally specify the `this` value for the function as the first argument.
146
-
147
- ```js
148
- class ValueStore {
149
- constructor(value) { this.value = value; }
150
- get() { return this.value; }
151
- }
152
-
153
- let store = new ValueStore(42);
154
-
155
- let cb1 = koffi.register(store.get, 'IntCallback *'); // If a C function calls cb1 it will fail because this will be undefined
156
- let cb2 = koffi.register(store, store.get, 'IntCallback *'); // However in this case, this will match the store object
157
- ```
145
+ > [!NOTE]
146
+ > In Koffi 2.x (starting with Koffi 2.2), you could bind a specific `this` value to the callback function, by giving an object as the first argument to `koffi.register()`.
147
+ >
148
+ > This feature has been deprecated in Koffi 3 and will eventually be removed. Replace with an explicit call to `function.bind()` instead.
158
149
 
159
150
  # Special considerations
160
151
 
package/doc/contribute.md CHANGED
@@ -6,7 +6,7 @@ Please note that the source code is not in this repository, instead it lives in
6
6
 
7
7
  # Build from source
8
8
 
9
- We provide prebuilt binaries, packaged in the NPM archive, so in most cases it should be as simple as `npm install koffi`. If you want to hack Koffi or use a specific platform, follow the instructions below.
9
+ We provide prebuilt binaries, packaged in NPM packages, so in most cases it should be as simple as `npm install koffi`. If you want to hack Koffi or use a specific platform, follow the instructions below.
10
10
 
11
11
  Start by cloning the repository with [Git](https://git-scm.com/):
12
12
 
@@ -25,7 +25,7 @@ First, make sure the following dependencies are met:
25
25
  - [CMake meta build system](https://cmake.org/)
26
26
  - [Node.js](https://nodejs.org/) 16 or later
27
27
 
28
- Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
28
+ Once this is done, run this command from the _src/koffi_ directory:
29
29
 
30
30
  ```sh
31
31
  cd src/koffi
@@ -44,7 +44,7 @@ Make sure the following dependencies are met:
44
44
  - [CMake meta build system](https://cmake.org/)
45
45
  - [Node.js](https://nodejs.org/) 16 or later
46
46
 
47
- Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
47
+ Once this is done, run this command from the _src/koffi_ directory:
48
48
 
49
49
  ```sh
50
50
  cd src/koffi
package/doc/index.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Overview
2
2
 
3
- Koffi is a **fast and easy-to-use C FFI module for Node.js**, featuring:
3
+ Koffi is a **fast and easy-to-use dynamic C FFI module for Node.js**, featuring:
4
4
 
5
- * Low-overhead and fast performance (see [benchmarks](benchmarks))
5
+ * Low-overhead compared to a static Node-API implementation (see [benchmarks](benchmarks))
6
6
  * Support for primitive and aggregate data types (structs and fixed-size arrays), both by reference (pointer) and by value
7
+ * Support for synchronous and asynchronous calls
7
8
  * Javascript functions can be used as C callbacks
8
9
  * Well-tested code base for popular OS/architecture combinations
9
10
 
package/doc/migration.md CHANGED
@@ -1,3 +1,103 @@
1
+ # Koffi 2.x to 3.x
2
+
3
+ Most programs should work as-is with Koffi 3.x.
4
+
5
+ However, some changes could impact your code:
6
+
7
+ - Koffi is now distributed in [split packages](#split-packages) to reduce install size/bloat.
8
+ - Pointers are now [BigInt values](#bigint-pointers) instead of opaque V8 external values.
9
+ - Types created by koffi are now [type objects](#type-objects) insted of opaque V8 external values.
10
+ - Using `koffi.register()` with a [receiver value](#registered-callback-binding) is deprecated.
11
+ - Several old [deprecated functions](#removed-functions) have been removed.
12
+
13
+ ## Split packages
14
+
15
+ The main koffi package does not contain native code any longer. Instead, it depends on platform-specific packages (such as `@koromix/koffi-linux-x64`) for platform support, specified through `optionalDependencies`.
16
+
17
+ Your package manager should automatically install the binary package relevant to your platform. Importing koffi should work transparently, just as before.
18
+
19
+ However, if you redistribute software that uses Koffi, you will probably **need to change your packaging system** or configure your bundler differently.
20
+
21
+ ## BigInt pointers
22
+
23
+ For performance reasons, Koffi now uses BigInt numbers for pointers instead of V8 external objects.
24
+
25
+ Most code should work without any change, but there are two cases where this might impact you:
26
+
27
+ - If you use a **type system**, for example in TypeScript code (e.g. for parameters), you may need to accept BigInt values now if you pass pointer values around.
28
+ - BigInt pointers **do not carry the C type around**. In Koffi 2.x, trying to pass a pointer to an integer to a `void Myfunc(MyStruct *)` function would have triggerd an exception, but in Koffi 3.x this will "work" (and probably crash).
29
+
30
+ ## Type objects
31
+
32
+ Type functions, such as `koffi.struct()`, now create *TypeObject* objects, and type information is directly available without `koffi.introspect()`.
33
+
34
+ You can resolve type strings to type objects with `koffi.type()`. This function replaces `koffi.resolve()`, which is now a deprecated alias for `koffi.type()`.
35
+
36
+ > [!NOTE]
37
+ > For compatibility reasons, both `koffi.resolve()` and `koffi.introspect()` still exist, as aliases for `koffi.type()`. Using them will emit a deprecation warning.
38
+
39
+ Read the documentation about [type specifiers](migration#type-specifiers) for more information.
40
+
41
+ The two versions below illustrate the API difference between Koffi 2.x and Koffi 3.x:
42
+
43
+ ```js
44
+ // Koffi 2.x
45
+
46
+ const MyStruct = koffi.struct('MyStruct', {
47
+ a: 'int',
48
+ b: 'int'
49
+ });
50
+
51
+ console.log(koffi.introspect(MyStruct).members); // Prints MyStruct members
52
+ console.log(koffi.introspect('MyStruct').members); // Prints MyStruct members
53
+
54
+ console.log(koffi.introspect(koffi.types.int).alignment); // Prints MyStruct members
55
+ console.log(koffi.introspect('int').alignment); // Prints alignment of int type
56
+
57
+ // Koffi 3.x
58
+
59
+ const MyStruct = koffi.struct('MyStruct', {
60
+ a: 'int',
61
+ b: 'int'
62
+ });
63
+
64
+ console.log(MyStruct.members); // Prints MyStruct members
65
+ console.log(koffi.type('MyStruct').members); // Prints MyStruct members
66
+
67
+ console.log(koffi.types.int.alignment); // Prints alignment of int type
68
+ console.log(koffi.type('int').alignment); // Prints alignment of int type
69
+ ```
70
+
71
+ ## Registered callback binding
72
+
73
+ In Koffi 2.x, it was possible to bind a specific `this` value to the callback function when using `koffi.register()`, by passing an object as the first argument. This feature has been deprecated, it still works but will emit a warning.
74
+
75
+ You should replace these calls with an explicit call to the `bind()` method:
76
+
77
+ ```js
78
+ class ValueStore {
79
+ constructor(value) { this.value = value; }
80
+ get() { return this.value; }
81
+ }
82
+
83
+ let store = new ValueStore(42);
84
+
85
+ // Koffi 2.x
86
+
87
+ let cb = koffi.register(store, store.get, 'IntCallback *');
88
+
89
+ // Koffi 3.x
90
+
91
+ let cb = koffi.register(store.get.bind(store), 'IntCallback *');
92
+ ```
93
+
94
+ ## Removed functions
95
+
96
+ Two deprecated functions have been removed:
97
+
98
+ - `koffi.callback()`: if you still use it, replace with `koffi.proto()`.
99
+ - `koffi.handle()`: if you still use it, replace with `koffi.opaque()`.
100
+
1
101
  # Koffi 1.x to 2.x
2
102
 
3
103
  The API was changed in 2.x in a few ways, in order to reduce some excessively "magic" behavior and reduce the syntax differences between C and the C-like prototypes.
package/doc/start.md CHANGED
@@ -9,11 +9,11 @@ npm install koffi
9
9
  Once you have installed Koffi, you can start by loading it:
10
10
 
11
11
  ```js
12
- // CommonJS syntax
13
- const koffi = require('koffi');
14
-
15
12
  // ES6 modules
16
13
  import koffi from 'koffi';
14
+
15
+ // CommonJS syntax
16
+ const koffi = require('koffi');
17
17
  ```
18
18
 
19
19
  # Simple examples
@@ -112,7 +112,9 @@ Please read the [dedicated page](packaging) for information about bundling and p
112
112
 
113
113
  # Build manually
114
114
 
115
- Follow the [build instrutions](contribute#build-from-source) if you want to build the native Koffi code yourself.
115
+ Follow the [build instructions](contribute#build-from-source) if you want to build the native Koffi code yourself.
116
116
 
117
117
  > [!NOTE]
118
- > This is only needed if you want to hack on Koffi. The official NPM package provide prebuilt binaries and you don't need to compile anything if you only want to use Koffi in Node.js.
118
+ > This is only needed if you want to hack on Koffi. The official NPM package provides prebuilt binaries and you don't need to compile anything if you only want to use Koffi in Node.js.
119
+ >
120
+ > Just run `npm install koffi`!