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 🙏

© 2024 – Pkg Stats / Ryan Hefner

disklet

v0.5.2

Published

A tiny, composable filesystem API

Downloads

2,072

Readme

Disklet

Build Status JavaScript Style Guide

A tiny, composable filesystem API.

The Disklet library provides a simple way to read and write files on a variety of platforms:

  • Browser (via LocalStorage)
  • Node.js
  • React Native
  • Memory

The API focuses on simplicity and ease-of-use, rather than advanced features. It packs everything you need into six simple methods:

  • getData / getText
  • setData / setText
  • delete
  • list

These methods do a lot, though. If you try to write to a folder that doesn't exist, for example, Disklet will automatically create it for you. Likewise, the delete method works on both files and folders. This lets you focus on your data, not path manipulation or other filesystem details.

Here is an example:

import { makeMemoryDisklet } from 'disklet'

async function demo () {
  // Let's make an in-memory filesystem:
  const disklet = makeMemoryDisklet()

  // Writing a file automatically creates any necessary folders:
  await disklet.setText('a/file.txt', 'Hello')

  // Binary files work with Arrays / Uint8Arrays of bytes:
  await disklet.setData('a/b/file.bin', [72, 73, 10])
  await disklet.getData('a/b/file.bin') // Uint8Array [ 72, 73, 10 ]

  // Listing a folder returns paths and types:
  await disklet.list('./a/') // { 'a/file.txt': 'file', 'a/b': 'folder' }

  // Removing stuff is easy:
  await disklet.delete('a')
}

You can compose these Disklet objects together in various ways:

  • navigateDisklet opens a new Disklet object pointed at a sub-folder. All paths are relative to this new location.
  • logDisklet wraps logging around any Disklet instance (great for debugging).
  • mergeDisklets creates a merged view of two folders.

The library has tree-shaking support, so tools like rollup.js or Webpack can automatically trim away any features you don't use. Even with all platforms and features present, the library is only about 4.5K (min + gzip).

Disklet requires a Promise implementation, but is plain ES5 otherwise. The library also includes TypeScript and Flow typings if you need them.

React Native

To use this library on React Native, simply run react-native link disklet after installing via yarn / NPM.

Legacy API

Disklet used to have an older, more complicated API. To help porting old codebases to the new API, this library contains a downgradeDisklet function, which will convert a modern Disklet object to the older Folder interface.

The old functions are deprecated but still present for now. They will go away in an upcoming 1.0 release.

API overview

The Disklet interface has the following methods:

export interface Disklet {
  // Like `rm -r path`:
  delete(path: string): Promise<unknown>

  // Like `cat path`:
  getData(path: string): Promise<Uint8Array>
  getText(path: string): Promise<string>

  // Like `ls -l path`:
  list(path?: string): Promise<DiskletListing>

  // Like `mkdir -p $(dirname path); echo data > path`:
  setData(path: string, data: ArrayLike<number>): Promise<unknown>
  setText(path: string, text: string): Promise<unknown>
}

export type DiskletListing = { [path: string]: 'file' | 'folder' }

The following functions create new Disklet objects:

  • makeLocalStorageDisklet
  • makeMemoryDisklet
  • makeNodeDisklet(path)
  • makeReactNativeDisklet

These functions combine or wrap Disklet instances in various ways:

  • logDisklet
  • mergeDisklets
  • navigateDisklet

Finally, the library contains some standalone functions to help with folder listings:

  • deepList
  • justFiles
  • justFolders

Text vs. Data

Some backends, such as Node.js and React Native, store binary data on disk. They implement getText and setText using the UTF-8 encoding.

Other backends, such as LocalStorage, only store text. They implement getData and setData using the base64 encoding.

This means saving a file in binary format and then loading it in text format (or vice-versa) will be undefined and platform-dependent. This is an unfortunate side-effect of running in multiple environments.

Paths

All Disklet paths are relative URI's. This means the folder separator is always '/', even on Windows. Paths are not allowed to be absolute, so something like '/home/user/somefile.txt' is not valid. Likewise, paths are not allowed to "escape" the Disklet location, so '../somefile.txt' isn't valid either (but 'a/../somefile.txt' is fine).

You can use the navigateDisklet function to create a new Disklet instance locked to a particular location. If you pass this folder to a module within your program, you can rest assured that the module will only write files where it is supposed to. At the same time, the module never has to worry about where the right location is, since the Disklet object encapsulates that information.

API reference

Storage backends

makeLocalStorageDisklet(storage = window.localStorage, opts = {}): Disklet

Creates a Disklet that stores its data in the browser's localStorage.

A file's path becomes its localStorage key, and its contents become a localStorage string value. If a prefix is provided via the opts parameter, then all localStorage keys will begin with the provided string. Binary data is transformed to base64, since localStorage can only handle strings.

makeMemoryFolder(storage = {}): Disklet

A memory folder stores its contents in a Javascript object.

The file paths are the object keys, and the file contents are stored as-is (Uint8Arrays for setData and strings for setText). All paths start with /, so they will never conflict with "magic" Javascript names like __proto__.

makeNodeDisklet(path: string): Disklet

The Node.js folder backend writes files and folders directly to disk. It requires a starting path that everything will be located under.

Binary data is written as-is, while text is stored in utf-8.

makeReactNativeDisklet()

Creates a Disklet object with access to the phone's file system, starting at the app's document directory.

Helpers

deepList(disklet: Disklet, path: string = ''): Promise<DiskletListing>

Recursively lists a folder.

justFiles(listing: DiskletListing): string[]

This function will return an array with just the file names in a listing. You can use it like justFiles(await disklet.list()) or justFiles(await deepList(disklet)).

justFolders(listing: DiskletListing): string[]

Like justFiles, but for folders, this will return an array with just the paths to subfolders.

logDisklet(disklet: Disklet, opts = {}): Disklet

This function wraps a Disklet with logging.

By default, only changes will be logged. To log everything, set opts.verbose to true.

If you would like to send the logs somewhere other than console.log, pass a callback function as opts.callback. The callback's parameters are a path and an operation name, which is one of:

  • "delete"
  • "get data"
  • "get text"
  • "list"
  • "set data"
  • "set text"

mergeDisklets(master: Disklet, fallback: Disklet): Disklet

Creates a unified view of two Disklets. When reading files, the union tries the master folder first, and then the fallback folder if anything goes wrong. All writes go to the master folder, and deletes go to both folders.

navigateDisklet(disklet: Disklet, path: string): Disklet

Creates a new Disklet scoped to a sub-folder of the parent Disklet.

Disklet

delete(path: string): Promise<unknown>

Recursively deletes a file or folder (including all contents). Does nothing if the path doesn't exist.

getData(path: string): Promise<Uint8Array>

Reads a file's contents as binary data. The path must exist and be a binary file, or this will fail.

getText(path: string): Promise<string>

Reads a file's contents as text. The path must exist and be a text file, or this will fail.

list(path?: string): Promise<DiskletListing>

Lists a folders's contents. Returns an empty listing if the location is missing ({}). If the path points to a file instead of a folder, returns the file's normalized path and type ({ 'a/somefile.txt': 'file' }).

setData(path: string, data: ArrayLike<number>): Promise<unknown>

Writes an array of bytes to disk as a file. This will recursively create any folders needed to hold the file.

setText(path: string, text: string): Promise<unknown>

Writes a string to disk as a file. This will recursively create any folders needed to hold the file.