koffi 2.10.1 → 2.11.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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/doc/assets.ini CHANGED
@@ -11,7 +11,7 @@ Ignore = favicon.png *.js *.css
11
11
 
12
12
  [static/site.min.js]
13
13
  Type = Bundle
14
- Source = flaat/flaat.js
14
+ Source = flat/static.js
15
15
 
16
16
  [static/highlight.min.js]
17
17
  Type = Bundle
@@ -20,6 +20,8 @@
20
20
  OTHER DEALINGS IN THE SOFTWARE. */
21
21
 
22
22
  @import url('../../../vendor/opensans/OpenSans.css');
23
+ @import url('./reset.css');
24
+
23
25
  @import url('./normal.css');
24
26
  @import url('./small.css');
25
27
  @import url('./print.css');
@@ -20,9 +20,16 @@
20
20
  OTHER DEALINGS IN THE SOFTWARE. */
21
21
 
22
22
  html {
23
+ --top_color: #ccc;
24
+ --anchor_color: #383838;
25
+ --button_color: #888;
26
+ --focus_color: #ececec;
27
+
23
28
  --top_height: 90px;
24
29
  --top_padding: 6px;
25
30
  --small_height: 80px;
31
+ --top_background: white;
32
+ --footer_background: #f6f6f9;
26
33
 
27
34
  height: 100%;
28
35
  scroll-padding-top: calc(var(--top_height) + 10px);
@@ -44,8 +51,13 @@ body {
44
51
  flex-direction: column;
45
52
  }
46
53
 
54
+ canvas:focus {
55
+ border: none;
56
+ outline: none;
57
+ }
58
+
47
59
  a {
48
- color: var(--primary_color, #383838);
60
+ color: var(--color, var(--anchor_color));
49
61
  cursor: pointer;
50
62
  text-decoration: none;
51
63
  }
@@ -55,9 +67,9 @@ a:has(> img) { text-decoration: none !important; }
55
67
  #top {
56
68
  position: sticky;
57
69
  top: 0;
58
- background: white;
70
+ background: var(--top_background);
59
71
  z-index: 9;
60
- border-bottom: 2px solid white;
72
+ border-bottom: 2px solid var(--top_background);
61
73
  transition: border-bottom-color 0.4s ease;
62
74
  }
63
75
  #top.border { border-bottom-color: #383838; }
@@ -94,14 +106,20 @@ a:has(> img) { text-decoration: none !important; }
94
106
  display: block;
95
107
  border-bottom: 1px solid #383838;
96
108
  text-transform: uppercase;
109
+ text-wrap: nowrap;
97
110
  }
98
111
  #top li > a:hover, #top li.active > a {
99
112
  margin-bottom: -1px;
100
- border-bottom: 2px solid var(--primary_color);
113
+ border-bottom: 2px solid var(--top_color);
114
+ color: var(--top_color);
115
+ }
116
+ #top li > a.active {
117
+ font-weight: bold;
118
+ border-bottom-color: var(--top_color);
119
+ color: var(--top_color);
101
120
  }
102
- #top li > a.active { font-weight: bold; }
103
121
  #top li > div { display: none; }
104
- .nojs #top li:has(> div):hover, #top li:has(> div).active { border-left-color: var(--primary_color); }
122
+ .nojs #top li:has(> div):hover, #top li:has(> div).active { border-left-color: var(--top_color); }
105
123
  .nojs #top li:has(> div):hover > a, #top li:has(> div).active > a {
106
124
  margin-bottom: 1px;
107
125
  border-bottom: none;
@@ -114,9 +132,9 @@ a:has(> img) { text-decoration: none !important; }
114
132
  padding: 12px 1em 10px 1em;
115
133
  display: flex;
116
134
  flex-direction: column;
117
- background: white;
118
- border-left: 2px solid var(--primary_color);
119
- border-bottom: 2px solid var(--primary_color);
135
+ background: var(--top_background);
136
+ border-left: 2px solid var(--top_color);
137
+ border-bottom: 2px solid var(--top_color);
120
138
  }
121
139
  #top li > div > a { margin-top: 3px; }
122
140
  #top li > div > a.active { font-weight: bold; }
@@ -126,7 +144,6 @@ a:has(> img) { text-decoration: none !important; }
126
144
  height: 70%;
127
145
  object-fit: contain;
128
146
  margin-right: 2em;
129
- transition: filter 0.4s ease;
130
147
  }
131
148
  #logo > img {
132
149
  width: 100%;
@@ -163,7 +180,7 @@ a:has(> img) { text-decoration: none !important; }
163
180
  #side a.lv5 { padding-left: 72px; }
164
181
  #side a.lv6 { padding-left: 87px; }
165
182
 
166
- #deploy { display: none; }
183
+ :is(#deploy, .deploy) { display: none; }
167
184
 
168
185
  main {
169
186
  flex: 1;
@@ -177,7 +194,7 @@ main {
177
194
 
178
195
  footer {
179
196
  padding: 0.5em;
180
- background: #f6f6f9;
197
+ background: var(--footer_background);
181
198
  display: flex;
182
199
  gap: 1.5em;
183
200
  align-items: center;
@@ -222,55 +239,131 @@ h3 {
222
239
  * + h1, * + h2, * + h3 { margin-top: 1.2em; }
223
240
 
224
241
  table {
225
- margin: 1em auto;
242
+ margin: 0 auto;
226
243
  border-collapse: collapse;
244
+ empty-cells: show;
227
245
  }
228
- th {
246
+ * + table { margin-top: 1em; }
247
+ tr {
248
+ border-bottom: 1px solid #ededf0;
249
+ vertical-align: middle;
250
+ }
251
+ th, td {
252
+ height: 1.5em;
229
253
  padding: 0.5em;
230
- background: #fafafa;
254
+ vertical-align: middle;
255
+ }
256
+ th {
257
+ background: #f8f8f8;
258
+ font-size: 0.9em;
259
+ font-variant: small-caps;
260
+ text-align: left;
261
+ user-select: none;
262
+ -webkit-user-select: none;
263
+ }
264
+ td {
265
+ background: white;
231
266
  border: 1px solid #ebebeb;
232
267
  }
268
+ thead > tr { border: 1px solid #ededf0; }
233
269
  thead th { text-align: center; }
234
270
  tbody th {
235
271
  text-align: left;
236
272
  font-weight: normal;
237
273
  font-style: italic;
238
274
  }
239
- td {
240
- padding: 0.5em;
241
- background: white;
242
- border: 1px solid #ebebeb;
243
- }
244
275
  th.center, td.center { text-align: center; }
245
276
  th.right, td.right { text-align: right; }
246
-
277
+ table :is(td, th, col).check { width: 2em; }
278
+ table :is(td, th).center { text-align: center; }
279
+ table :is(td, th).right { text-align: right; }
280
+ table :is(tr, td, th, col).missing {
281
+ font-style: italic;
282
+ color: var(--color, gray);
283
+ }
284
+ table :is(td, th).picture { padding: 6px 0 0 6px; }
285
+ table :is(td, th).picture > img {
286
+ width: 24px;
287
+ height: 24px;
288
+ }
247
289
  table + div.legend {
248
- margin-top: calc(-1em + 2px);
290
+ margin-top: 6px;
249
291
  text-align: center;
250
292
  font-size: 0.8em;
251
293
  }
252
294
 
253
- .buttons {
254
- margin: 1em;
295
+ hr {
296
+ margin: 4px auto;
297
+ width: 90%;
298
+ border: none;
299
+ border-bottom: 1px solid #ededf0;
300
+ }
301
+
302
+ button {
303
+ padding: 0.35em 1em 0.45em 1em;
304
+ background: var(--button_color);
305
+ border: none;
306
+ border-radius: 10px;
307
+ color: white;
308
+ cursor: pointer;
309
+ white-space: nowrap;
310
+ }
311
+ button::-moz-focus-inner { border: 0; }
312
+ button:not(:disabled):not(.active):hover {
313
+ background: color-mix(in srgb, var(--button_color) 90%, black);
314
+ color: white;
315
+ }
316
+ button:disabled {
317
+ filter: saturate(10%) brightness(80%);
318
+ cursor: not-allowed;
319
+ pointer-events: none;
320
+ }
321
+ button:disabled > * { opacity: 0.3; }
322
+ button.active { background: color-mix(in srgb, var(--button_color) 50%, black); }
323
+ button > img {
324
+ width: 16px;
325
+ height: 16px;
326
+ transform: translateY(2px);
327
+ }
328
+ button > img:only-child {
329
+ width: 32px;
330
+ height: 32px;
331
+ transform: translateY(4px);
332
+ }
333
+
334
+ .actions {
255
335
  display: flex;
336
+ margin-top: 1em;
256
337
  gap: 20px;
257
338
  justify-content: center;
339
+ align-items: start;
258
340
  flex-wrap: wrap;
259
341
  }
260
- .buttons > a {
342
+ .actions + * { margin-top: 1em; }
343
+ .actions > :is(a, button) {
261
344
  display: block;
262
- width: 40%;
263
- min-width: 250px;
264
- background: var(--secondary_color);
345
+ width: 30%;
346
+ min-width: 10em;
347
+ background: var(--button_color);
265
348
  color: white;
266
- padding: 0.6em 1em;
349
+ padding: 0.35em 2em 0.45em 2em;
267
350
  text-decoration: none;
268
351
  text-align: center;
269
352
  }
270
- .buttons > a:hover {
271
- filter: brightness(80%) contrast(150%);
353
+ .actions > :is(a, button):hover {
354
+ background: color-mix(in srgb, var(--button_color) 90%, black);
272
355
  color: white;
273
356
  }
357
+ .actions > :is(a, button).disabled {
358
+ pointer-events: none;
359
+ filter: saturate(10%) brightness(50%);
360
+ }
361
+
362
+ span.warning { color: var(--color, red); }
363
+ span.warning:before {
364
+ content: "⚠\FE0E";
365
+ margin-right: 2px;
366
+ }
274
367
 
275
368
  code:not(.hljs) {
276
369
  padding: 2px 6px;
@@ -22,8 +22,7 @@
22
22
  @media print {
23
23
  #top { display: none; }
24
24
  #side { display: none; }
25
-
26
- main { padding-right: 16px !important; }
25
+ #side ~ main { padding-right: 16px; }
27
26
  footer { display: none; }
28
27
 
29
28
  h1:not(:first-child) { break-before: page; }
@@ -0,0 +1,41 @@
1
+ /* Copyright (C) 2024 Niels Martignène <niels.martignene@protonmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the “Software”), to deal in
5
+ the Software without restriction, including without limitation the rights to use,
6
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
+ Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
+ OTHER DEALINGS IN THE SOFTWARE. */
21
+
22
+ /* -------------------- Normalization -------------------- */
23
+
24
+ button, input, optgroup, select, textarea {
25
+ box-sizing: border-box;
26
+ font-family: inherit;
27
+ font-size: 100%;
28
+ }
29
+ input[type='checkbox'], input[type='radio'] { vertical-align: -2px; }
30
+
31
+ a { cursor: pointer; }
32
+
33
+ p { margin: 0; }
34
+ p + p { margin-top: 1em; }
35
+
36
+ /* -------------------- Miscellaneous -------------------- */
37
+
38
+ .disabled, .disabled * {
39
+ pointer-events: none !important;
40
+ user-select: none !important;
41
+ }
@@ -27,7 +27,9 @@
27
27
  position: static;
28
28
  }
29
29
 
30
- main { padding-right: 16px !important; }
30
+ #side ~ main { padding-right: 16px; }
31
+
32
+ button > span { display: none; }
31
33
  }
32
34
 
33
35
  @media screen and (max-width: 960px) {
@@ -35,6 +37,7 @@
35
37
 
36
38
  #top menu {
37
39
  height: var(--small_height);
40
+ padding-top: 16px;
38
41
  padding-left: 60px;
39
42
  flex-direction: column;
40
43
  gap: 0;
@@ -76,7 +79,7 @@
76
79
  .js #top.active #logo { display: none; }
77
80
  .nojs #top:hover #logo { display: none; }
78
81
 
79
- #deploy {
82
+ :is(#deploy, .deploy) {
80
83
  display: block !important;
81
84
  position: fixed;
82
85
  width: 42px;
@@ -18,18 +18,18 @@ window.addEventListener('load', e => {
18
18
  initMenu();
19
19
  initSide();
20
20
  initScroll();
21
-
22
- document.documentElement.classList.remove('nojs');
23
- document.documentElement.classList.add('js');
24
21
  });
25
22
 
26
23
  function initDeploy() {
27
- let deploy = document.querySelector('#deploy');
24
+ let el = document.querySelector('#deploy');
28
25
 
29
- deploy.addEventListener('click', e => {
30
- let top = document.querySelector('nav#top');
31
- top.classList.toggle('active');
32
- });
26
+ if (el != null)
27
+ el.addEventListener('click', deploy);
28
+ }
29
+
30
+ function deploy() {
31
+ let top = document.querySelector('nav#top');
32
+ top.classList.toggle('active');
33
33
  }
34
34
 
35
35
  function initMenu() {
@@ -99,10 +99,13 @@ function initSide() {
99
99
  if (ignore_scroll)
100
100
  return;
101
101
 
102
+ let style = window.getComputedStyle(document.documentElement);
103
+ let treshold = parseFloat(style.getPropertyValue('scroll-padding-top')) + 10;
104
+
102
105
  let idx;
103
106
  for (idx = 0; idx < items.length; idx++) {
104
107
  let rect = items[idx][1].getBoundingClientRect();
105
- if (rect.top >= 50)
108
+ if (rect.top >= treshold)
106
109
  break;
107
110
  }
108
111
  if (idx)
@@ -139,7 +142,9 @@ function initScroll() {
139
142
 
140
143
  function adjust_top() {
141
144
  let top = document.querySelector('nav#top');
142
- top.classList.toggle('border', window.pageYOffset >= 20);
145
+
146
+ if (top != null)
147
+ top.classList.toggle('border', window.pageYOffset >= 20);
143
148
  }
144
149
  }
145
150
 
@@ -148,3 +153,9 @@ function findParent(el, func) {
148
153
  el = el.parentElement;
149
154
  return el;
150
155
  }
156
+
157
+
158
+ document.documentElement.classList.remove('nojs');
159
+ document.documentElement.classList.add('js');
160
+
161
+ export { deploy }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use the official repository for bugs, ideas and features requests: https://github.com/Koromix/koffi
4
4
 
5
- Please note that the source code is not in this repository, instead it lives in a monorepo: https://github.com/Koromix/rygel/ (in the *src/koffi* subdirectory).
5
+ Please note that the source code is not in this repository, instead it lives in a monorepo: https://codeberg.org/Koromix/rygel/ (in the *src/koffi* subdirectory).
6
6
 
7
7
  # Build from source
8
8
 
@@ -11,7 +11,7 @@ We provide prebuilt binaries, packaged in the NPM archive, so in most cases it s
11
11
  Start by cloning the repository with [Git](https://git-scm.com/):
12
12
 
13
13
  ```sh
14
- git clone https://github.com/Koromix/rygel
14
+ git clone https://codeberg.org/Koromix/rygel
15
15
  cd rygel
16
16
  ```
17
17
 
@@ -145,4 +145,4 @@ Koffi is programmed in a mix of C++ and assembly code (architecture-specific cod
145
145
 
146
146
  My personal preference goes to a rather C-like C++ style, with careful use of templates (mainly for containers) and little object-oriented programming. I strongly prefer tagged unions and code locality over inheritance and virtual methods. Exceptions are disabled.
147
147
 
148
- Find more information about code style in the [monorepository README](https://github.com/Koromix/rygel/?tab=readme-ov-file#c-flavor) file.
148
+ Find more information about code style in the [monorepository README](https://codeberg.org/Koromix/rygel/#c-flavor) file.
@@ -17,6 +17,13 @@ The same can be done when declaring a function with a C-like prototype string, w
17
17
  - `_Out_` for output parameters
18
18
  - `_Inout_` for dual input/output parameters
19
19
 
20
+ > [!TIP]
21
+ > The Win32 API provides many functions that take a pointer to an empty struct for output, except that the first member of the struct (often named `cbSize`) must be set to the size of the struct before calling the function. An example of such a function is `GetLastInputInfo()`.
22
+ >
23
+ > In order to use these functions in Koffi, you must define the parameter as `_Inout_`: the value must be copied in (to provide `cbSize` to the function) and then the filled struct must be copied out to JS.
24
+ >
25
+ > Look at the [Win32 example](#win32-struct-example) below for more information.
26
+
20
27
  ## Primitive value
21
28
 
22
29
  This Windows example enumerate all Chrome windows along with their PID and their title. The `GetWindowThreadProcessId()` function illustrates how to get a primitive value from an output argument.
@@ -73,7 +80,9 @@ for (let hwnd = null;;) {
73
80
  }
74
81
  ```
75
82
 
76
- ## Struct example
83
+ ## Struct examples
84
+
85
+ ### POSIX struct example
77
86
 
78
87
  This example calls the POSIX function `gettimeofday()`, and uses the prototype-like syntax.
79
88
 
@@ -101,6 +110,28 @@ gettimeofday(tv, null);
101
110
  console.log(tv);
102
111
  ```
103
112
 
113
+ ### Win32 struct example
114
+
115
+ Many Win32 functions that use struct outputs require you to set a size member (often named `cbSize`). These functions won't work with `_Out_` because the size value must be copied from JS to C, use `_Inout_` in this case.
116
+
117
+ ```js
118
+ // ES6 syntax: import koffi from 'koffi';
119
+ const koffi = require('koffi');
120
+
121
+ const user32 = koffi.load('user32.dll');
122
+
123
+ const LASTINPUTINFO = koffi.struct('LASTINPUTINFO', {
124
+ cbSize: 'uint',
125
+ dwTime: 'uint32'
126
+ });
127
+ const GetLastInputInfo = user32.func('bool __stdcall GetLastInputInfo(_Inout_ LASTINPUTINFO *plii)');
128
+
129
+ let info = { cbSize: koffi.sizeof(LASTINPUTINFO) };
130
+ let success = GetLastInputInfo(info);
131
+
132
+ console.log(success, info);
133
+ ```
134
+
104
135
  ## Opaque type example
105
136
 
106
137
  This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.
@@ -53,7 +53,7 @@ In this case, you can use `require('koffi/indirect')` but you will need to make
53
53
 
54
54
  Packaging with electron-builder should work as-is.
55
55
 
56
- Take a look at the full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/electron-builder).
56
+ Take a look at the full [working example in the repository](https://codeberg.org/Koromix/rygel/src/branch/master/src/koffi/examples/electron-builder).
57
57
 
58
58
  ## Electron Forge
59
59
 
@@ -63,13 +63,13 @@ Packaging with Electron Force should work as-is, even when using webpack as conf
63
63
  npm init electron-app@latest my-app -- --template=webpack
64
64
  ```
65
65
 
66
- Take a look at the full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/electron-forge).
66
+ Take a look at the full [working example in the repository](https://codeberg.org/Koromix/rygel/src/branch/master/src/koffi/examples/electron-forge).
67
67
 
68
68
  ## NW.js
69
69
 
70
70
  Packagers such as nw-builder should work as-is.
71
71
 
72
- You can find a full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/nwjs).
72
+ You can find a full [working example in the repository](https://codeberg.org/Koromix/rygel/src/branch/master/src/koffi/examples/nwjs).
73
73
 
74
74
  ## Node.js and esbuild
75
75
 
@@ -79,10 +79,10 @@ You can easily tell esbuild to copy the native files with the copy loader and th
79
79
  esbuild index.js --platform=node --bundle --loader:.node=copy --outdir=dist/
80
80
  ```
81
81
 
82
- You can find a full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/node-esbuild).
82
+ You can find a full [working example in the repository](https://codeberg.org/Koromix/rygel/src/branch/master/src/koffi/examples/node-esbuild).
83
83
 
84
84
  ## Node.js and yao-pkg
85
85
 
86
86
  Use [yao-pkg](https://github.com/yao-pkg/pkg) to make binary packages of your Node.js-based project.
87
87
 
88
- You can find a full [working example in the repository](https://github.com/Koromix/rygel/tree/master/src/koffi/examples/yao-pkg).
88
+ You can find a full [working example in the repository](https://codeberg.org/Koromix/rygel/src/branch/master/src/koffi/examples/yao-pkg).
@@ -248,6 +248,15 @@ Disposable types can only be created from pointer or string types.
248
248
  > [!WARNING]
249
249
  > Be careful on Windows: if your shared library uses a different CRT (such as msvcrt), the memory could have been allocated by a different malloc/free implementation or heap, resulting in undefined behavior if you use `koffi.free()`.
250
250
 
251
+ # External buffers (views)
252
+
253
+ *New in Koffi 2.11.0*
254
+
255
+ You can access unmanaged memory with `koffi.view(ptr, len)`. This function takes a pointer and a length, and creates an ArrayBuffer through which you can access the underlying memory without copy.
256
+
257
+ > [!NOTE]
258
+ > Some runtimes (such as Electron) forbid the use of external buffers. In this case, trying to create a view will trigger an exception.
259
+
251
260
  # Unwrap pointers
252
261
 
253
262
  You can use `koffi.address(ptr)` on a pointer to get the numeric value as a [BigInt object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
@@ -13,9 +13,10 @@
13
13
  You should have received a copy of the GNU General Public License
14
14
  along with this program. If not, see <https://www.gnu.org/licenses/>. */
15
15
 
16
- @import url('../flaat/flaat.css');
16
+ @import url('../flat/flat.css');
17
17
  @import url('../../../vendor/highlight.js/styles/base16/tomorrow.css');
18
18
 
19
19
  html {
20
- --primary_color: #ec7400;
20
+ --top_color: #ec7400;
21
+ --anchor_color: #ec7400;
21
22
  }
package/index.js CHANGED
@@ -363,8 +363,8 @@ var require_package = __commonJS({
363
363
  "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
364
364
  module2.exports = {
365
365
  name: "koffi",
366
- version: "2.10.1",
367
- stable: "2.10.1",
366
+ version: "2.11.0",
367
+ stable: "2.11.0",
368
368
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
369
369
  keywords: [
370
370
  "foreign",
package/indirect.js CHANGED
@@ -363,8 +363,8 @@ var require_package = __commonJS({
363
363
  "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
364
364
  module2.exports = {
365
365
  name: "koffi",
366
- version: "2.10.1",
367
- stable: "2.10.1",
366
+ version: "2.11.0",
367
+ stable: "2.11.0",
368
368
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
369
369
  keywords: [
370
370
  "foreign",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.10.1",
4
- "stable": "2.10.1",
3
+ "version": "2.11.0",
4
+ "stable": "2.11.0",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",