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

gitnestr

v0.1.2

Published

A powerful SDK for Electron applications that provides both Git repository management and gitnestr CLI integration

Readme

GitNestr Electron SDK

A powerful SDK for Electron applications that provides both Git repository management and GitNestr CLI integration, enabling seamless transfer of Git repositories and interaction with the HORNET Storage network.

Features

Git Bridge

  • 🔄 Efficient transfer of Git repositories from disk to browser memory
  • 📦 Chunked file transfer to handle large repositories
  • 🌳 Full Git repository structure preservation
  • 🔍 Repository metadata access (branches, remotes, HEAD)
  • ⚡ Built on LightningFS for high-performance in-memory filesystem
  • 🛡️ Error handling and transfer verification

GitNestr Bridge

  • 🚀 Direct integration with the GitNestr CLI
  • 🔐 Key management for secure repository access
  • 🔄 Repository operations (init, clone, push, pull, fetch)
  • 📦 Archive retrieval for repository DAGs
  • 🛡️ Comprehensive error handling and event system

Installation

# For Git repository management
npm install @gitnestr/electron-git-bridge @gitnestr/browser-git-bridge

# For gitnestr CLI integration
npm install @gitnestr/electron-gitnestr-bridge @gitnestr/browser-gitnestr-bridge

Architecture

The SDK consists of four main packages:

Git Bridge Packages

  1. @gitnestr/electron-git-bridge: Runs in the main process, handles filesystem access for Git repositories
  2. @gitnestr/browser-git-bridge: Runs in the renderer process, manages in-memory filesystem for Git repositories

GitNestr Bridge Packages

  1. @gitnestr/electron-gitnestr-bridge: Runs in the main process, interfaces with the GitNestr CLI
  2. @gitnestr/browser-gitnestr-bridge: Runs in the renderer process, communicates with the main process via IPC

Usage

Git Bridge Usage

Main Process (Electron)

import { GitBridge } from "@gitnestr/electron-git-bridge";

// Initialize GitBridge with repository path
const bridge = new GitBridge("/path/to/repository");

// Get repository metadata
const metadata = await bridge.getMetadata();
console.log("Repository info:", metadata);

// Stream repository to renderer
for await (const chunk of bridge.streamRepository()) {
  // If it's a manifest, send it first
  if ("manifest" in chunk) {
    mainWindow.webContents.send("repo-metadata", {
      ...metadata,
      manifest: chunk.manifest,
    });
    continue;
  }

  // Send file chunks to renderer
  mainWindow.webContents.send("repo-chunk", chunk);
}

Renderer Process (Browser)

import { BrowserGitBridge } from "@gitnestr/browser-git-bridge";

// Initialize BrowserGitBridge
const bridge = new BrowserGitBridge({
  fsName: "my-git-repo",
  persistCache: false,
});

// Initialize filesystem
await bridge.init();

// Handle repository metadata and manifest
ipcRenderer.on("repo-metadata", async (_, data) => {
  bridge.setTransferManifest(data.manifest);
  updateUI(data); // Update UI with repository info
});

// Handle incoming file chunks
ipcRenderer.on("repo-chunk", async (_, chunk) => {
  try {
    await bridge.receiveChunk(chunk);

    // Check if transfer is complete
    if (bridge.isTransferComplete()) {
      // Verify the transfer
      const verification = await bridge.verifyTransfer();
      if (verification.success) {
        // Access repository information
        const repo = await bridge.getRepository("/");
        console.log("Repository loaded:", repo);
      } else {
        console.error("Transfer verification failed:", verification.errors);
      }
    }
  } catch (error) {
    console.error("Error receiving chunk:", error);
  }
});

GitNestr Bridge Usage

Main Process (Electron)

import { GitnestrBridge } from "@gitnestr/electron-gitnestr-bridge";
import { app, BrowserWindow, ipcMain } from "electron";

// Create a new GitnestrBridge instance
const gitnestr = new GitnestrBridge({
  gitnestrPath: "/path/to/gitnestr", // Optional: defaults to 'gitnestr' in PATH
  timeout: 30000, // Optional: timeout in milliseconds
});

// Set up IPC handler for gitnestr bridge
ipcMain.handle("gitnestr-bridge", async (event, { request }) => {
  try {
    const { id, method, params } = request;

    // Call the appropriate method on the GitnestrBridge instance
    const result = await gitnestr[method](...params);

    // Return the result
    return { id, result };
  } catch (error) {
    // Handle errors
    return {
      id: request.id,
      error: {
        code: error.code || "INTERNAL_ERROR",
        message: error.message || "Unknown error",
        details: error.details,
      },
    };
  }
});

// Forward events from GitnestrBridge to renderer
gitnestr.addListener("event", (event) => {
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send("gitnestr-bridge-event", {
      type: "event",
      event,
    });
  }
});

Renderer Process (Browser)

import { BrowserGitnestrBridge } from "@gitnestr/browser-gitnestr-bridge";

// Create a new BrowserGitnestrBridge instance
const gitnestr = new BrowserGitnestrBridge({
  timeout: 30000, // Optional: timeout in milliseconds
});

// Initialize a new repository
await gitnestr.init("/path/to/repo");

// Clone a repository
await gitnestr.clone(
  "gitnestr://example.com/repo",
  "/path/to/destination",
  "keyAlias"
);

// Pull changes
await gitnestr.pull("/path/to/repo", "branch");

// Push changes
await gitnestr.push("/path/to/repo", "privateKey");

// Generate keys
const { privateKey, publicKey } = await gitnestr.generateKeys();

// Store a key
await gitnestr.storeKey("alias", privateKey, "passphrase");

// Unlock a key
const key = await gitnestr.unlockKey("alias", "passphrase");

// Listen for events
gitnestr.addListener("event", (event) => {
  if (event.type === "progress") {
    console.log(`Progress: ${event.message}`);
  } else if (event.type === "error") {
    console.error(`Error: ${event.message}`);
  }
});

Configuration Options

Git Bridge Options

ElectronGitBridge Options

interface GitBridgeOptions {
  maxRepoSize?: number; // Maximum repository size (default: 1GB)
  chunkSize?: number; // Size of transfer chunks (default: 1MB)
  excludePatterns?: string[]; // Glob patterns to exclude (default: ['node_modules/**'])
  includeGitHistory?: boolean; // Include .git directory (default: true)
}

BrowserGitBridge Options

interface BrowserGitBridgeOptions {
  fsName?: string; // Name for LightningFS instance
  maxRepoSize?: number; // Maximum repository size (default: 1GB)
  chunkSize?: number; // Size of transfer chunks (default: 1MB)
  cacheSize?: number; // LightningFS cache size (default: 100MB)
  persistCache?: boolean; // Persist filesystem cache (default: true)
}

GitNestr Bridge Options

ElectronGitnestrBridge Options

interface GitnestrBridgeOptions {
  gitnestrPath?: string; // Path to gitnestr executable (default: 'gitnestr' in PATH)
  timeout?: number; // Command timeout in milliseconds (default: 60000)
  env?: Record<string, string>; // Custom environment variables
  relays?: string[]; // List of relay URLs
}

BrowserGitnestrBridge Options

interface BrowserGitnestrBridgeOptions {
  timeout?: number; // Request timeout in milliseconds (default: 60000)
  relays?: string[]; // List of relay URLs
}

Error Handling

Git Bridge Errors

try {
  await bridge.receiveChunk(chunk);
} catch (error) {
  if (error instanceof GitBridgeError) {
    console.error("Git operation failed:", error.message);
    console.error("Error code:", error.code);
    console.error("Additional info:", error.details);
  }
}

GitNestr Bridge Errors

try {
  await gitnestr.pull("/path/to/repo");
} catch (error) {
  if (error instanceof GitnestrError) {
    console.error("Gitnestr operation failed:", error.message);
    console.error("Error code:", error.code);
    console.error("Additional info:", error.details);

    if (error.code === GitnestrErrorCode.TIMEOUT) {
      // Handle timeout error
    } else if (error.code === GitnestrErrorCode.COMMAND_FAILED) {
      // Handle command failure
    }
  }
}

Example Application

Check out the example directory for a complete working example of:

  • Repository selection dialog
  • Progress tracking
  • Error handling
  • Repository information display
  • GitNestr CLI integration

To run the example:

cd example
npm install
npm start

API Reference

Git Bridge API

ElectronGitBridge

  • constructor(repoPath: string, options?: GitBridgeOptions)
  • async getMetadata(): Promise<GitRepository>
  • async *streamRepository(): AsyncGenerator<FileChunk | { manifest: TransferManifest }>
  • async validateRepo(): Promise<ValidationResult>

BrowserGitBridge

  • constructor(options?: BrowserGitBridgeOptions)
  • async init(): Promise<void>
  • setTransferManifest(manifest: TransferManifest): void
  • async receiveChunk(chunk: FileChunk): Promise<void>
  • isTransferComplete(): boolean
  • async verifyTransfer(): Promise<{ success: boolean; errors: string[] }>
  • async getRepository(path: string): Promise<GitRepository>

GitNestr Bridge API

ElectronGitnestrBridge

  • constructor(options?: GitnestrBridgeOptions)
  • async executeCommand(command: string, args?: string[], options?: GitnestrCommandOptions): Promise<GitnestrCommandResult>
  • async init(repoPath: string): Promise<GitnestrRepository>
  • async clone(url: string, destPath: string, keyAlias?: string): Promise<GitnestrRepository>
  • async pull(repoPath: string, branch?: string): Promise<GitnestrCommandResult>
  • async push(repoPath: string, privateKey?: string): Promise<GitnestrCommandResult>
  • async fetch(repoPath: string, branch?: string, privateKey?: string): Promise<GitnestrCommandResult>
  • async archive(url: string, branch: string, privateKey: string, keyAlias?: string): Promise<string[]>
  • async generateKeys(): Promise<{ privateKey: string; publicKey: string }>
  • async storeKey(alias: string, privateKey: string, passphrase: string): Promise<void>
  • async unlockKey(alias: string, passphrase: string): Promise<string>
  • addListener(event: 'event', listener: GitnestrEventListener): this
  • removeListener(event: 'event', listener: GitnestrEventListener): this
  • cancelAll(): void

BrowserGitnestrBridge

  • constructor(options?: BrowserGitnestrBridgeOptions)
  • async init(repoPath: string): Promise<GitnestrRepository>
  • async clone(url: string, destPath: string, keyAlias?: string): Promise<GitnestrRepository>
  • async pull(repoPath: string, branch?: string): Promise<GitnestrCommandResult>
  • async push(repoPath: string, privateKey?: string): Promise<GitnestrCommandResult>
  • async fetch(repoPath: string, branch?: string, privateKey?: string): Promise<GitnestrCommandResult>
  • async archive(url: string, branch: string, privateKey: string, keyAlias?: string): Promise<string[]>
  • async generateKeys(): Promise<{ privateKey: string; publicKey: string }>
  • async storeKey(alias: string, privateKey: string, passphrase: string): Promise<void>
  • async unlockKey(alias: string, passphrase: string): Promise<string>
  • addListener(event: 'event', listener: GitnestrEventListener): this
  • removeListener(event: 'event', listener: GitnestrEventListener): this
  • cancelAll(): void