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

@nuwainfo/ffl-js

v0.1.2

Published

Node.js binding for FastFileLink, backed by the portable ffl.com APE

Readme

@nuwainfo/ffl-js

Dependency-free Node.js binding for FastFileLink. The npm package bundles the portable ffl.com APE, so callers do not need a separate FFL installation or Python runtime.

The low-level command grammar is generated by APEBind from binding/ffl.apebind.yaml. The public API in src/ffl/client.js is handwritten so FFL-specific library semantics remain explicit and reviewable.

Runtime requirements

  • Node.js 18 or newer
  • An environment where child processes can execute the bundled APE

There are no runtime npm dependencies.

CLI

The package also exposes the bundled FFL command-line program. Run it without a project installation:

npx @nuwainfo/ffl-js --version

After npm install @nuwainfo/ffl-js, run the project-local command with:

npx --no-install ffl-js --version

Usage

import { share } from '@nuwainfo/ffl-js';

const session = await share('release.zip', {
  maxDownloads: 1,
  timeoutSeconds: 1800,
});

console.log(session.link);
await session.stop();

Multiple files can be shared directly:

const session = await share(['one.txt', 'two.txt'], {
  name: 'files.zip',
});

Text and bytes helpers own their temporary source until the share session closes:

import { shareText } from '@nuwainfo/ffl-js';

const session = await shareText('hello', { name: 'hello.txt' });
console.log(session.link);
await session.close();

Optional-value FFL flags use natural JavaScript values. receipt: true emits --receipt without a value, while receipt: '[email protected]' emits the flag and address.

Streams and events

Use shareStream() to send a Node Readable directly to FFL without creating a temporary file:

import { createReadStream } from 'node:fs';
import { shareStream } from '@nuwainfo/ffl-js';

const session = await shareStream(createReadStream('database.sql'), {
  name: 'database.sql',
});

session.on('ready', (event) => console.log(event.data));
session.on('progress', (event) => console.log(event.data));

Semantic event names are ready, progress, transport, and completed. For FFL protocol diagnostics, use session.onRaw('/hook/...', listener) or session.rawEvents(). Hook servers and temporary sources are released when the APE process ends, even if the caller does not explicitly close the session.

Download

import { download } from '@nuwainfo/ffl-js';

const result = await download('https://example.fastfilelink/...', {
  outputPath: 'download.bin',
});

console.log(result.outputPath);
console.log(result.transferMode);

download() preserves the underlying process result while exposing parsed transfer mode and output path information.

For cancellation or binary streaming, use a download session:

import { downloadStream, startDownload } from '@nuwainfo/ffl-js';

const controller = new AbortController();
const transfer = await startDownload('https://example.fastfilelink/...', {
  outputPath: 'download.bin',
  signal: controller.signal,
});

await transfer.done;

const streamed = await downloadStream('https://example.fastfilelink/...');
streamed.stdout.pipe(process.stdout);
await streamed.done;

downloadStream() preserves arbitrary bytes from FFL stdout; it does not decode the download payload as UTF-8.

Authentication secrets

For shares protected with HTTP Basic Auth, set FFL_AUTH_PASSWORD in the application environment and pass only authUser. The bundled FFL subprocess inherits the environment, so the password stays out of its command line:

export FFL_AUTH_PASSWORD='use-your-secret-manager'
$env:FFL_AUTH_PASSWORD = 'use-your-secret-manager'
const session = await share('release.zip', { authUser: 'deploy' });

Do not also pass authPassword: FFL gives the explicit CLI option precedence over FFL_AUTH_PASSWORD. The environment variable applies to the sharing side; pass download credentials explicitly when downloading a protected link.

WSL2

If an operation fails with TLSError([0x6300]), WSL may be routing the bundled .com APE through Windows interop. Run the following in WSL, then restart the WSL session:

sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop'

Key generation

import { keygen } from '@nuwainfo/ffl-js';

const result = await keygen('alice');
console.log(result.publicKeyPath);
console.log(result.privateKeyPath);

Version and raw access

import { raw, version } from '@nuwainfo/ffl-js';

console.log(await version());
const result = await raw(['download', '--help']);

Development

The repository is a normal npm source project. The .tgz produced by npm pack is a build artifact, not the source of truth.

npm test
npm run test:packaging
npm run test:real
npm pack

The test groups are kept separate because the real and packaging suites execute the bundled APE.

Updating the generated binding

Install the matching APEBind source project. When adopting a new ffl.com, first refresh the raw CLI discovery evidence:

python scripts/inspect.py --ape /path/to/ffl.com

Review binding/ffl.discovered.apebind.yaml, then manually merge intentional changes into the canonical semantic contract binding/ffl.apebind.yaml. Automatic inspection never overwrites the semantic contract.

Regenerate only the machine-owned low-level files:

python scripts/regenerate.py --ape /path/to/ffl.com

Regeneration updates:

  • src/ffl/_generated.js
  • src/ffl/_generated.d.ts
  • src/ffl/_runtime.js
  • src/ffl/_runtime.d.ts
  • src/ffl/bin/ffl.com

It deliberately does not overwrite the handwritten client, result parsers, public type declarations, tests, or semantic schema.