npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jellybrick/ffi-cjs

v0.7.0

Published

Foreign Function Interface Helper.

Readme

About

Foreign Function Interface helper. Provides a friendly abstraction/API for:

Syntax is inspired by Deno FFI. The goal was to be able to easily switch from ffi-napi to koffi or vice versa.

📦 Scoped @xan105 packages are for my own personal use but feel free to use them.

  • Forked form @xan105/ffi (MIT)

Example

Loading a library with Deno like syntax

import { dlopen } from "@jellybrick/ffi-cjs/[ napi | koffi ]";

const lib = dlopen("libm", {
  ceil: { 
    result: "double", 
    parameters: [ "double" ] 
  }
});
lib.ceil(1.5); // 2

Async

import { dlopen } from "@jellybrick/ffi-cjs/[ napi | koffi ]";

const lib = dlopen("libm", {
  ceil: { 
    result: "double", 
    parameters: [ "double" ],
    nonblocking: true 
  }
});
await lib.ceil(1.5); // 2

Calling directly from a library

import { load, types } from "@jellybrick/ffi-cjs/[ napi | koffi ]";

const call = load("user32.dll", { abi: "stdcall" });
const MessageBoxA = call("MessageBoxA", "int", [
  "void *", 
  types.win32.LPCSTR, 
  types.win32.LPCSTR, 
  "uint"
]);

const MB_ICONINFORMATION = 0x40;
MessageBoxA(null, "Hello World!", "Message", MB_ICONINFORMATION);

Callback with Deno like syntax

import { dlopen, Callback} from "@jellybrick/ffi-cjs/koffi";

const library = dlopen(
  "./callback.so",
  {
    set_status_callback: {
      parameters: ["function"],
      result: "void"
    },
    start_long_operation: {
      parameters: [],
      result: "void"
    }
  }
);

const callback = new Callback(
  {
    parameters: ["u8"],
    result: "void",
  },
  (success) => {}
);

library.set_status_callback(callback.pointer);
library.start_long_operation();

Install

npm install @jellybrick/ffi-cjs

Please note that ffi-napi and koffi are optional peer dependencies. Install the one you wish to use yourself (or both 🙃).

API

⚠️ This module is only available as an CommonJS module (CJS).

💡 This lib doesn't have a default entry point. Choose the export corresponding to your liking.

TypeScript

import ... from "@jellybrick/ffi-cjs/napi";
//OR
import ... from "@jellybrick/ffi-cjs/koffi";

JavaScript

const ... = require("@jellybrick/ffi-cjs/napi");
//OR
const ... = require("@jellybrick/ffi-cjs/koffi");

Named export

load(path: string, option?: object): function

Load the given library path and return an handle function to call library's symbol(s).

Option

  • ignoreLoadingFail?: boolean (false)

Silent fail if the given library couldn't be loaded. 💡 Called symbol will be undefined in that case.

  • ignoreMissingSymbol?: boolean (false)

Silent fail if the given library doesn't have the called symbol. 💡 Called symbol will be undefined in that case.

  • abi?: string ("func" for koffi and "default_abi" for ffi-napi)

ABI convention to use. Use this when you need to ex: winapi x86 requires "stdcall".

Return

function(symbol: string | number, result: unknown, parameters: unknown[]): any;

💡 Koffi can call by ordinal (symbol:number)

See the corresponding FFI library for more information on what to pass for result and parameters as they have string type parser, structure/array/pointer interface, ... and other features.

❌ Throws on error

Example:

import { load } from "@jellybrick/ffi-cjs/[ napi | koffi ]";
const call = load("libm");

const ceil = call("ceil", "double", ["double"])
ceil(1.5); //2

dlopen(path: string, symbols: object, option?: object): object

Open library and define exported symbols. This is a friendly wrapper to load() inspired by Deno FFI dlopen syntax.

If you ever use ffi-napi ffi.Library() this will be familiar.

Param

  • path: string

    Library path to load

  • symbols: object

    Symbol(s) definition:

  {
    name: {
      result?: unknown,
      parameters?: unknown[],
      nonblocking?: boolean,
      symbol?: string | number
    },
    ...
  }

By default the property name is used for symbol when omitted. Use symbol if you are using a different name than the symbol name or if you want to call by ordinal (Koffi).

When nonblocking is true (default false) this will return the promisified async() method of the corresponding symbol (see corresponding ffi library asynchronous calling). The rest is the same as for load().

  • option?: object

    Pass option(s) to load(). See above.

Return

An object with the given symbol(s) as properties.

❌ Throws on error

Example

import { dlopen, types } from "@jellybrick/ffi-cjs/[ napi | koffi ]";
const { BOOL } = types.win32;

const lib = dlopen("xinput1_4", {
  "XInputEnable": {
    parameters: [BOOL],
    nonblocking: true
  }
}, { abi: "stdcall" });

await lib.XInputEnable(1);

const types: object

The FFI Library's primitive types as well as corresponding alias are exposed for convenience. Such as Deno types (rust) and Windows specific types (DWORD,...).

💡 Windows specific types are grouped together under win32.

import { types } from "@jellybrick/ffi-cjs/[ napi | koffi ]";
const { DWORD, LPCSTR } = types.win32;

💡 When using koffi alias are also set with koffi.alias() so you can use them as string.

import { load } from "@jellybrick/ffi-cjs/koffi";
const call = load("user32.dll", { abi: "stdcall" });
const MessageBoxA = call("MessageBoxA", "int", ["void *", "LPCSTR", "LPCSTR", "uint"]);

⚠️ Types are not exposed under their own namespace because some words are illegal or already in use in JavaScript. You can still use destructuring if needed as long as the name is "allowed".

❌ No

import { i32 } from "@jellybrick/ffi-cjs/koffi/types"

✔️ Yes

import { types } from "@jellybrick/ffi-cjs/koffi"
const { i32 } = types;

🚫 Forbidden

import { types } from "@jellybrick/ffi-cjs/napi"
const { function } = types;

class Callback

Create a callback to be called at a later time (registered callback).

This is a class wrapper to the FFI library's callback function(s) inspired by Deno FFI UnsafeCallback class syntax.

Constructor

(definition: { result: unknown, parameters: unknown[] }, callback?: Function | null)

Properties
  • pointer: unknown

The pointer to the callback.

  • address: number | BigInt | null

The memory address of the pointer.

  • type: unknown

The type of the callback.

Methods
  • close(): void

Dispose of the callback. Remove function pointer associated with this instance.

  • register(callback?: Function): void

Register the callback. If a callback was already registered with this instance it will be disposed of.

Example
import { dlopen, types, Callback } from "@jellybrick/ffi-cjs/[ napi | koffi ]";

const library = dlopen("./callback.so", {
    setCallback: {
      parameters: [types.function],
      result: "void",
    },
    doSomething(): {
      parameters: [],
      result: "void",
    },
});

const callback = new Callback(
  { parameters: [], result: "void" },
  () => {},
);

library.setCallback(callback.pointer);
library.doSomething();

// After callback is no longer needed
callback.close();

You can also register the callback at a later time:

import { dlopen, Callback } from "@jellybrick/ffi-cjs/[ napi | koffi ]";

const callback = new Callback(
  { parameters: [], result: "void" }
);

const library = dlopen("./callback.so", {
    setCallback: {
      parameters: [callback.type],
      result: "void",
    },
    doSomething(): {
      parameters: [],
      result: "void",
    },
});

callback.register(()=>{});

library.setCallback(callback.pointer);
library.doSomething();

// After callback is no longer needed
callback.close();

pointer(value: unknown, direction?: string): any

Just a shorthand to ref.refType(x) (ffi-napi) and koffi.out/inout(koffi.pointer(x)) (koffi) to define a pointer.

alloc(type: unknown): { pointer: Buffer, get: ()=> unknown }

Allocate a buffer and get the corresponding data when passing a pointer to allow the called function to manipulate memory.

import { dlopen, alloc } from "@jellybrick/ffi-cjs/[ napi | koffi ]";
const dylib = dlopen(...); //lib loading

const number = alloc("int"); //allocate Buffer for the output data
dylib.manipulate_number(number.pointer);
const result = number.get();