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

partitions-tool-esp

v0.1.2

Published

Pure TypeScript library to generate and parse ESP-IDF partition tables, NVS, SPIFFS and FatFS partition images (Node + Browser).

Readme

partitions-tool-esp

中文

A pure JavaScript / TypeScript implementation for generating and parsing ESP-IDF partition tables and their common partition contents.

Currently supports generation and parsing of the following partition formats:

  • Partition Table partition_table
  • NVS nvs
    • Plain-text NVS v1 / v2
    • multipage blob
  • FAT data.fat
    • FAT12 / FAT16 / FAT32
    • SFN(8.3) or LFN
    • Wear leveling
  • SPIFFS data.spiffs

Installation

pnpm add partitions-tool-esp # or use your preferred package manager

Quick Start

[!TIP]

When the partition size of NVS, SPIFFS, or FATFS cannot accommodate the provided files, the related functions will throw an error.

Partition Table

The partition table supports mutual conversion between CSV format files and partitions.bin.

// PartitionTable is a class; import it from the subpath export.
import { PartitionTable } from 'partitions-tool-esp/partition-table';

const csv = `# Name, Type, SubType, Offset, Size, Flags
nvs,      data, nvs,     ,        0x6000,
phy_init, data, phy,     ,        0x1000,
factory,  app,  factory, ,        1M,
`;

const table = PartitionTable.fromCSV(csv, { flashSize: 4 * 1024 * 1024 });
const bin = table.toBinary(); // Uint8Array, suitable for writing to partitions.bin

const roundtrip = PartitionTable.fromBinary(bin);
console.log(roundtrip.entries[0].name); // "nvs"
console.log(roundtrip.toCSV()); // restore CSV

The Partition Table generation logic is implemented based on gen_esp32part.py.

NVS

NVS partitions support three equivalent construction methods:

import { NVS } from 'partitions-tool-esp';

// 1) Using ESP-IDF `nvs_partition_gen.py` tool-style CSV
const csvBin = NVS.generate(
  NVS.parseCSV(`key,type,encoding,value
storage,namespace,,
greeting,data,string,hello world
counter,data,u32,42
`),
  { size: 0x6000 },
);

// 2) Chained Builder
const builderBin = NVS.generate(
  new NVS.NvsBuilder()
    .namespace('storage')
    .string('greeting', 'hello world')
    .u32('counter', 42)
    .binary('blob', new Uint8Array([0xde, 0xad, 0xbe, 0xef]))
    .namespace('settings')
    .u8('flag', 1)
    .build(),
  { size: 0x6000 },
);

// 3) Structured object: namespace -> { key: value }
const objectBin = NVS.generate(
  NVS.fromObject({
    storage: {
      greeting: 'hello world',
      counter: 42, // inferred as u32
      signed: -1, // inferred as i32
      blob: new Uint8Array([0xde, 0xad]), // inferred as binary
      flag: { type: 'u8', value: 1 }, // explicit width
      hex: { type: 'binary', value: 'deadbeef', encoding: 'hex2bin' },
    },
    settings: {
      bigCounter: 1n << 40n, // inferred as u64
    },
  }),
  { size: 0x6000 },
);

// Reverse parsing
const dump = NVS.parse(builderBin);
for (const page of dump.pages) {
  for (const entry of page.entries) {
    if (entry.state === 'Written') console.log(entry);
  }
}

In structured object mode, when a type is not explicitly specified, the library will automatically attempt to infer the data type. You can also specify it manually.

| JS Type | NVS Encoding | | --------------------------------------- | -------------------------------------------------- | | number (non-negative integer) | u32 | | number (negative integer) | i32 | | bigint (non-negative) | u64 | | bigint (negative) | i64 | | string | string | | Uint8Array | binary (raw) | | { type: 'u8'\|'i8'\|...'i64', value } | explicit integer type | | { type: 'string', value } | explicit string | | { type: 'binary', value, encoding? } | encoding can be 'raw' \| 'hex2bin' \| 'base64' |

The NVS tool is implemented based on nvs_partition_tool.

SPIFFS

import { SPIFFS, createDir, createFile } from 'partitions-tool-esp';

const image = SPIFFS.generate({
  imageSize: 0x10000,
  pageSize: 256,
  objNameLen: 32,
  metaLen: 4,
  useMagic: true,
  useMagicLength: true,
  source: createDir('root', [createFile('hello.txt', new TextEncoder().encode('hello\n'))]),
});

const parsed = SPIFFS.parse(image, { pageSize: 256, objNameLen: 32, metaLen: 4 });
for (const f of parsed.files) {
  console.log(f.path, new TextDecoder().decode(f.content));
}

The SPIFFS functionality is implemented based on spiffsgen.py.

FatFS

Supports generation and parsing of FAT12 / FAT16 / FAT32, with optional wear leveling support.

import { FatFS, createDir, createFile } from 'partitions-tool-esp';

const image = FatFS.generate({
  size: 512 * 1024,
  source: createDir('', [
    createFile('HELLO.TXT', new TextEncoder().encode('hello\n')),
    // LFN (long filename) support is enabled by default, so you can use it directly
    createFile('Hello Long Name.txt', new TextEncoder().encode('long\n')),
    createDir('SUB', [createFile('INNER.TXT', new Uint8Array([1, 2, 3]))]),
  ]),
  // volumeUuid: 0x12345678, // Volume UUID: optional, auto-assigned if omitted; specify for deterministic output
  // explicitFatType: 32,    // FAT Type: defaults to auto-select 12/16 by cluster count; pass 32 to force FAT32
  // longFilenames: false,   // Long filename support: only 8.3 filenames supported when LFN is disabled
  // espIdfCompat: false,    // IDF style preference: defaults to true
});

const parsed = FatFS.parse(image);
for (const { path, content } of FatFS.flatten(parsed.root)) {
  console.log(path, content.byteLength);
}

Parameter description:

  • longFilenames LFN (long filename) support, enabled by default. When disabled, only 8.3 filenames are supported, and an error is thrown when encountering overly long filenames.
  • espIdfCompat IDF style preference, enabled by default. The IDF built-in fatfsgen.py has some preferences when generating FAT images, including UTF-16 lowercase byte conversion, -N short aliases, etc. Setting espIdfCompat to true produces output similar to IDF's fatfsgen.py, while setting it to false produces output preferred by fsck.fat.

To use with the wear_levelling component (i.e., enabling wear leveling), enable the wearLeveling option. The generated FATFS image will automatically reserve 1 dummy sector + 2 state sectors + 1 config sector (safe mode adds 2 more dump sectors), consistent with wl_fatfsgen.py:

import { FatFS, createDir, createFile } from 'partitions-tool-esp';

const image = FatFS.generate({
  size: 1024 * 1024,
  sectorSize: FatFS.WL_SECTOR_SIZE, // WL requires 4096
  source: createDir('', [createFile('HELLO.TXT', new TextEncoder().encode('hi\n'))]),
  wearLeveling: true, // or { mode: 'safe', deviceId: 0xdeadbeef }
});

// When parsing, declare wearLeveling: true, and the library will strip WL metadata before parsing.
const parsed = FatFS.parse(image, { wearLeveling: true });

// You can also manually unwrap / wrap:
const plain = FatFS.removeWearLeveling(image);
const wrapped = FatFS.wrapWearLeveling(plain, image.byteLength, { mode: 'perf' });

IO Utility Helpers

This project provides some Node.js / browser I/O utility helpers.

// Node.js
import { readDir, writeDir } from 'partitions-tool-esp/io/node';
const tree = await readDir('./assets');
await writeDir(tree, './out');

// Browser
import { fromFileList, fromDirectoryHandle } from 'partitions-tool-esp/io/browser';
const dir1 = await fromFileList(inputElement.files!);
const dir2 = await fromDirectoryHandle(await showDirectoryPicker());

Package Exports

| Entry | Purpose | | ------------------------------------- | -------------------------------------------------------------------------------------------- | | partitions-tool-esp | Aggregate export, equivalent to import * as PartitionTable from '.../partition-table' etc. | | partitions-tool-esp/partition-table | Partition table only | | partitions-tool-esp/nvs | NVS only | | partitions-tool-esp/spiffs | SPIFFS only | | partitions-tool-esp/fatfs | FatFS only | | partitions-tool-esp/io/node | Node.js filesystem bridge | | partitions-tool-esp/io/browser | Browser FileList / File System Access API bridge |

Development

pnpm install
pnpm prepare # Initialize husky pre-commit hook
pnpm format
pnpm lint
pnpm typecheck
pnpm test # run tests, including byte-level comparison tests against ESP-IDF built-in scripts
pnpm build

Regenerating Fixtures

The comparison files in tests/fixtures/ come from official ESP-IDF Python tools. When upstream formats change or new cases are needed:

# Enable ESP-IDF environment
source $IDF_PATH/export.sh

# Run the script (IDF_PATH environment variable should be available)
pnpm fixtures
# or
IDF_PATH=/path/to/esp-idf OUT=tests/fixtures bash scripts/build-fixtures.sh

scripts/build-fixtures.sh will invoke:

  • components/partition_table/gen_esp32part.py
  • components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py
  • components/spiffs/spiffsgen.py
  • components/fatfs/fatfsgen.py

and write the results back to tests/fixtures/.

The BS_VolID (4 bytes at offset 39) in the FatFS image is randomly generated by fatfsgen.py; test cases first read this value from the test sample and pass it as volumeUuid to FatFS.generate, achieving byte-level consistency.

Current Limitations and Roadmap

  • FatFS: Supports FAT12 / FAT16 / FAT32, long filenames (LFN), wear leveling (perf / safe). ESP-IDF itself only supports 4096B sectors for WL (the 512 sector_size WL path is a Python-side special case), and this library similarly requires sectorSize === 4096.
  • NVS: Encryption (encrypted_partition) and version detection patches are not yet implemented.

License

Apache-2.0