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

@lyrify/znl-plugin-fs

v0.1.3

Published

ZNL file management plugin with chunked transfer, CRUD, and patch support

Readme

@lyrify/znl-plugin-fs

基于 ZNL 的文件管理插件(Master 管理、Slave 存储),提供:

  • 目录/文件的增删查改(CRUD)
  • 统一 diff 的 patch 应用
  • 大文件分片上传/下载(5MB 分片、ACK 确认、断点续传)

适用场景:使用 ZNL 作为通信层,在远程节点上进行可靠的文件管理。


特性

  • 命名空间注入:加载插件后自动为 ZNL 实例注入 fs 命名空间
  • CRUDlist / get / patch / delete / rename / stat
  • 分片传输:上传/下载均支持 5MB 分片 + ACK
  • 断点续传:断线后自动从已写入偏移继续
  • Patch 支持:Slave 端使用 diff 解析 unified diff 并落盘

安装

pnpm add @lyrify/znl-plugin-fs

使用方式(基于示例脚本)

1) Slave 端

import { ZNL } from "@lyrify/znl";
import "../index.js";

const slave = new ZNL({
  role: "slave",
  id: "core-001",
  endpoints: {
    router: "tcp://127.0.0.1:6003",
  },
  authKey: "your-shared-key",
  encrypted: false,
});

async function run() {
  await slave.start();

  await slave.fs.enable({
    root: "./examples/storage",
    logChunks: true,
  });

  console.log("slave ready: core-001");
}

run().catch((error) => {
  console.error("slave error:", error);
  process.exitCode = 1;
});

2) Master 端

import { ZNL } from "@lyrify/znl";
import { createTwoFilesPatch } from "diff";
import "../index.js";

const master = new ZNL({
  role: "master",
  id: "master-1",
  endpoints: {
    router: "tcp://127.0.0.1:6003",
  },
  authKey: "your-shared-key",
  encrypted: false,
});

function waitForSlave(id, timeoutMs = 10000) {
  if (master.slaves.includes(id)) return Promise.resolve();

  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      master.off("slave_connected", onConnected);
      reject(new Error(`等待 slave 超时:${id}`));
    }, timeoutMs);

    function onConnected(connectedId) {
      if (connectedId !== id) return;
      clearTimeout(timer);
      master.off("slave_connected", onConnected);
      resolve();
    }

    master.on("slave_connected", onConnected);
  });
}

async function run() {
  await master.start();

  const slaveId = "core-001";
  await waitForSlave(slaveId, 10000);

  // 列目录
  const listResult = await master.fs.list(slaveId, ".");
  console.log("list:", listResult);

  // 获取文件
  const getResult = await master.fs.get(slaveId, "kuke.json");
  const content = Buffer.isBuffer(getResult.body?.[0])
    ? getResult.body[0].toString("utf8")
    : String(getResult.body?.[0] ?? "");
  console.log("get:", content);

  // Patch 示例(Master 只发送统一 diff)
  const originalText = content;
  const updatedText = content.replace('"name": "restaurant"', '"name": "aura"');
  const unifiedDiff = createTwoFilesPatch(
    "kuke.json",
    "kuke.json",
    originalText,
    updatedText,
  );

  const patchResult = await master.fs.patch(slaveId, "kuke.json", unifiedDiff);
  console.log("patch:", patchResult);

  // 上传示例
  const uploadResult = await master.fs.upload(
    slaveId,
    "./examples/upload.txt",
    "upload.txt",
  );
  console.log("upload:", uploadResult);

  // 下载示例
  const downloadResult = await master.fs.download(
    slaveId,
    "upload.txt",
    "./examples/download.txt",
  );
  console.log("download:", downloadResult);
}

run().catch((error) => {
  console.error("master error:", error);
  process.exitCode = 1;
});

API 列表

Master 端

  • master.fs.list(slaveId, path):列出 path 目录下的文件与子目录信息
  • master.fs.get(slaveId, path):读取 path 文件内容(返回 Buffer 或文本)
  • master.fs.patch(slaveId, path, unifiedDiff):对 path 文件应用统一 diff 补丁
  • master.fs.upload(slaveId, localPath, remotePath):把本地 localPath 上传到 Slave 的 remotePath
  • master.fs.download(slaveId, remotePath, localPath):从 Slave 的 remotePath 下载到本地 localPath
  • master.fs.delete(slaveId, path):删除 Slave 上的文件或目录
  • master.fs.rename(slaveId, from, to):重命名或移动路径
  • master.fs.stat(slaveId, path):读取文件/目录元信息(size、mtime、类型等)

Slave 端

  • slave.fs.enable({ root }):启用文件服务并限定根目录为 root

测试

集成测试(真实 Master/Slave)

pnpm test

说明:

  • pnpm test 会顺序跑 plainencrypted 两套流程
  • 测试目录为 test/tmp/<scene>,脚本结束后自动清理

注意事项

  • slave.fs.enable({ root }) 必须传入 root
  • 传入路径必须在 root 范围内
  • Patch 使用 unified diff,Slave 端自动解析并应用
  • 大文件传输请使用 upload / download(已实现分片 + 断点续传)
  • upload / download 支持可选参数 { chunkSize, logChunks }
  • slave.fs.enable({ root, logChunks }) 可开启分片日志