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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@glifox/lorofs

v0.0.1

Published

File-system base on Loro CRDT

Downloads

5

Readme

LoroFS

LoroFS is a file system for the web built using Loro, designed to be local-first and support collaborative editing. It focuses on managing the file structure and metadata, while giving the user full control over the actual file content. This approach prevents the main LoroDoc from becoming excessively large and slow.

LoroFS also provides an integrated file explorer component to efficiently interact with and visualize the file system in the DOM.

Installation

npm install @glifox/gnosis

Usage

LoroFS Core

The LoroFS class manages the file system's structure and metadata using a LoroDoc internally.

import { LoroDoc, LoroFS } from "@glifox/gnosis";

// A callback function to handle saving/deleting LoroDoc instances (file contents & main FS doc)
const mySaveCallback = (key: string, doc: LoroDoc, options?: { delete?: boolean }) => {
    if (options?.delete) {
        console.log(`Permanently deleting content for file UUID: ${key}`);
        // Implement actual deletion of the LoroDoc content (e.g., from IndexedDB, cloud storage)
    } else {
        console.log(`Saving document "${key}". Current state:`, doc.exportFromLatest());
        // Implement actual persistence of the LoroDoc (e.g., to IndexedDB, cloud storage)
    }
};

// 1. Create a new LoroFS instance
const fs = LoroFS.new("my-project", mySaveCallback);

// 2. Or, load an existing LoroFS instance from a snapshot
// const snapshot: Uint8Array = /* ... load from storage ... */;
// const fs = LoroFS.load(snapshot, mySaveCallback);

// Create a directory
const srcId = fs.createDirectory("src");
console.log(`Created 'src' directory with ID: ${srcId}`);

// Create a subdirectory inside 'src'
const iconsId = fs.createDirectory("icons", srcId);
console.log(`Created 'icons' subdirectory with ID: ${iconsId}`);

// Create a file
const { nodeId: readmeId, fileUuid: readmeContentId } = fs.createFile("README.md", "text/markdown");
console.log(`Created 'README.md' file with node ID: ${readmeId} and content UUID: ${readmeContentId}`);

// Rename a node
fs.renameNode(readmeId, "README-v2.md");

// Move a file/directory
fs.moveNode(readmeId, iconsId); // Move README-v2.md into the 'icons' directory

// Move a node to trash
fs.moveToTrash(readmeId);

// Permanently delete a node and its children
// This returns the UUIDs of all file contents that need to be deleted by the host system.
const deletedFileUuids = fs.deleteNodePermanently(readmeId);
deletedFileUuids.forEach(uuid => console.log(`Notified to delete file content with UUID: ${uuid}`));


// Export the current state of the file system
const snapshot = fs.exportSnapshot();
// mySaveCallback("my-project", fs.getLoroDoc()); // The main FS document is also saved via the callback

onSave Callback: The onSave callback is crucial for integrating LoroFS with your persistence layer. It's invoked for:

  • The main file system LoroDoc whenever the structure changes.
  • New file content LoroDoc instances when createFile is called.
  • Notifying your system to permanently delete file content LoroDoc instances when deleteNodePermanently is used (indicated by options.delete = true).

Internal Explorer

The Explorer component allows you to render and interact with the LoroFS structure in the DOM. It listens to Loro events from the LoroFS instance to provide reactive UI updates with a clear separation of concerns:

  • Explorer: Handles business logic and coordinates between LoroFS and Renderer.
  • Renderer: Manages all DOM manipulation and visual updates.
  • Event System: Modular event handling with separate mouse and keyboard event types.
import { Explorer, LoroFS, LoroTreeNode } from "@glifox/gnosis";
import { defaultListeners } from "@glifox/gnosis/events/listeners";
import { IconProvider } from "@glifox/gnosis/icons/loader";

const fs = LoroFS.new("Example", /* mySaveCallback defined above */);
const el = document.getElementById("explorer")!;

// Optional: Custom Icon Provider
// const iconConfig = { themes: [...] }; // Your icon theme data (e.g., from VSCode/Zed icon packs)
// const customIconProvider = IconProvider.new(iconConfig, "vs-seti");

const explorer = new Explorer(fs, el, {
  listeners: defaultListeners(), // Provides core file explorer functionality
  // iconProvider: customIconProvider, // Uncomment to use a custom icon provider
  onOpenFile: (node: LoroTreeNode) => {
    console.log(`Opening file: ${node.data.get("name")}, Content UUID: ${node.data.get("uuid")}`);
    // Implement file opening logic here (e.g., load LoroDoc content using node.data.get("uuid"))
  }
});

// To stop the explorer and clean up listeners/DOM
// explorer.stop();

Interactive File/Directory Creation and Renaming

The explorer includes interactive methods for creating and renaming items, providing a smooth user experience:

  • Placeholder Input: An input field appears directly in the tree for naming.
  • Reactive Icons: File icons update automatically based on the entered name's extension.
  • Keyboard Controls: Enter to confirm, Escape to cancel. Auto-confirm on blur (if a name is provided).
  • Automatic File Type Detection: MIME type inferred from file extension.
  • Validation: Basic name validation with user-friendly error messages.
// Create new file in root directory (or specify a parent HTML element)
explorer.createNewFile();

// Create new directory in root directory
explorer.createNewDirectory();

// Assuming `dirElement` is an HTMLElement representing a directory in the explorer
// explorer.createNewFile(dirElement);
// explorer.createNewDirectory(dirElement);

// Assuming `elementToRename` is an HTMLElement representing a file or directory
// explorer.startRename(elementToRename);

File Operations & Navigation

The explorer supports comprehensive keyboard navigation and shortcuts, alongside mouse interactions:

Keyboard Shortcuts:

  • Creation:
    • Shift+F: Create new file at the current target or root.
    • Shift+D: Create new directory at the current target or root.
  • Manipulation:
    • F2: Rename selected item.
    • Delete / Backspace: Move selected item to trash.
    • Shift+Delete: Permanently delete selected item (with confirmation).
  • Navigation:
    • Enter: Open file, or toggle (expand/collapse) directory.
    • ArrowRight: Open directory.
    • ArrowLeft: Close current directory, or move focus to parent directory.
    • ArrowDown: Focus next visible item.
    • ArrowUp: Focus previous visible item.

Mouse Interactions:

  • Click: Open file or toggle directory expansion.
  • Drag & Drop: Move files/directories between folders.
  • Right-Click (Context Menu): Access contextual actions like "New File", "New Folder", "Rename". The context menu is extensible via ContextMenuOptions.

Event System Architecture

The event system is modular and extensible. You can provide your own listeners or augment the defaultListeners:

import { defaultListeners } from "@glifox/gnosis/events/listeners";
import { click, dragstart, drop } from "@glifox/gnosis/events/types/mouse";
import { keydown } from "@glifox/gnosis/events/types/keyboard";
import { defaultMenuItems, ContextMenuOptions } from "@glifox/gnosis/events/types/contextmenu";

// Example of custom context menu options
const customContextMenuOptions: ContextMenuOptions = {
    menuItems: [
        ...defaultMenuItems(), // Include default items
        {
            text: 'Custom Action',
            onclick: (explorer, target) => {
                console.log('Custom action for:', target?.dataset.name);
            }
        }
    ]
};

// Example of custom listener setup
const customListeners = [
  { name: "click", callback: click },
  { name: "keydown", callback: keydown },
  { name: "contextmenu", callback: (e, explorer) => { 
      contextmenu(e, explorer, customContextMenuOptions); 
  }}
  // Add more custom listeners or override existing ones
];

const explorer = new Explorer(fs, el, {
  listeners: customListeners
});

Custom Icons

The system supports custom icon providers for an enhanced visual experience:

import { IconProvider } from "@glifox/gnosis/icons/loader";
import { defaultListeners } from "@glifox/gnosis/events/listeners";

// Load your icon theme configuration (e.g., from a JSON file)
// This structure is inspired by VSCode/Zed icon packs.
const myIconConfig = {
  themes: [
    {
      name: "vs-seti",
      appearance: "dark", // or 'light'
      directory_icons: {
        collapsed: "/path/to/icons/folder.svg",
        expanded: "/path/to/icons/folder-open.svg"
      },
      file_stems: {
        "package.json": "/path/to/icons/json.svg",
        "webpack.config": "/path/to/icons/webpack.svg"
      },
      file_suffixes: {
        ".js": "/path/to/icons/javascript.svg",
        ".ts": "/path/to/icons/typescript.svg",
        ".css": "/path/to/icons/css.svg",
        ".html": "/path/to/icons/html.svg"
      },
      file_icons: {
        "text": { path: "/path/to/icons/file.svg" },
        "javascript": { path: "/path/to/icons/javascript.svg" },
        // ... more specific icons
      }
    }
  ]
};

// Create an IconProvider instance for your chosen theme
const customIconProvider = IconProvider.new(myIconConfig, "vs-seti");

const explorer = new Explorer(fs, el, {
  iconProvider: customIconProvider,
  listeners: defaultListeners()
});

If no iconProvider is specified, LoroFS defaults to simple icons from Lucide.

Architecture Overview

Separation of Concerns:

  • LoroFS: Core file system operations and data management using loro-crdt.
  • Explorer: Business logic coordinator, handles user interactions and dispatches commands.
  • Renderer: Pure DOM manipulation, responsible for visual updates and interactive elements like placeholders.
  • Event System: Modular event handling separated by type (mouse, keyboard, context menu).

Key Benefits:

  • Clean separation between data layer and presentation.
  • Extensible event and icon systems.
  • Type-safe operations.
  • Reactive UI updates through Loro's event system.
  • Consistent keyboard and mouse interaction patterns.

Summary of Features

  • File System Operations:
    • Create Directories and Files (with automatic file type detection).
    • Rename files and directories.
    • Move files and directories (including drag & drop).
    • Move to Trash functionality.
    • Permanent deletion (returns UUIDs of file contents for host system cleanup).
    • Snapshot export and load (Loro implementation).
  • User Interface (Explorer):
    • Interactive file/directory creation and renaming (with placeholders, reactive icons, validation).
    • Comprehensive Keyboard shortcuts and navigation (Shift+F/D, F2, Delete, Arrows, Enter).
    • Mouse interaction (click to open/toggle, drag & drop to move).
    • Customizable Right-click Context Menu.
    • Support for custom icon providers, including theme-based icons (inspired by Zed icon packs).
    • Simple default icons using Lucide.
    • Extensible event listener system.
  • Persistence Strategy:
    • onSave callback for the host application to persist the main FS LoroDoc and individual file content LoroDoc instances.

See the sample for complete implementation example.