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

markdownzip

v0.1.1

Published

A powerful tool to package and manage Markdown documents with their resources in a single file

Downloads

8

Readme

MarkdownZip (MDZ)

MarkdownZip (MDZ) 是一个专为Markdown文档设计的打包格式,它能将Markdown文件及其相关资源(图片、视频、附件等)封装为单一的自包含文件,实现文档的便捷分享与存储。MDZ格式支持密码保护、完整性校验等高级特性。

特性

  • 将Markdown内容和所有资源文件封装到单一文件中
  • 支持密码加密保护敏感内容
  • 文件完整性校验,防止文件损坏
  • 安全的文件操作,防止路径遍历攻击
  • 支持丰富的元数据(标题、作者、创建和修改时间等)
  • 简单易用的TypeScript API
  • 支持命令行操作

安装

NPM包安装

npm install markdownzip

全局安装CLI工具

npm install -g markdownzip

CLI使用说明

MDZ提供了命令行工具,方便快速创建、查看和管理MDZ文件。

基本命令

# 创建MDZ文件
mdz create <output.mdz> <input.md> [选项]

# 提取MDZ文件内容
mdz extract <input.mdz> <output.md> [选项]

# 显示MDZ文件信息
mdz info <input.mdz> [选项]

# 添加资源到MDZ文件
mdz add <mdz文件> <资源文件> [选项]

# 列出MDZ文件中的资源
mdz list <mdz文件> [选项]

# 更新MDZ文件的元数据
mdz metadata <mdz文件> [选项]

# 设置或更改MDZ文件的密码
mdz password <mdz文件> [选项]

# 验证MDZ文件的完整性
mdz verify <mdz文件> [选项]

# 提取MDZ文件中的特定资源
mdz extract-asset <mdz文件> <资源ID> <输出路径> [选项]

# 显示版本信息
mdz version

# 显示帮助信息
mdz help
mdz --help

常用选项

全局选项:

  • --password=<密码>-p <密码> - 设置或提供密码
  • --verbose-v - 显示详细信息
  • --quiet-q - 减少输出信息
  • --force-f - 强制操作,忽略警告

create 命令特有选项:

  • --title=<标题>-t <标题> - 设置文档标题
  • --author=<作者>-a <作者> - 设置文档作者

extract 命令特有选项:

  • --overwrite - 覆盖已存在的文件

add 命令特有选项:

  • --relative-path=<路径>-r <路径> - 设置资源在MDZ中的相对路径

list 命令特有选项:

  • --json - 以JSON格式输出资源列表

metadata 命令特有选项:

  • --title=<标题>-t <标题> - 更新文档标题
  • --author=<作者>-a <作者> - 更新文档作者
  • --json=<json> - 以JSON格式提供完整的元数据更新

password 命令特有选项:

  • --new-password=<密码> - 设置新密码
  • --remove - 移除密码保护

命令详解

create - 创建MDZ文件

从Markdown文件创建新的MDZ文件。

mdz create example.mdz README.md --title="示例文档" --author="作者" --password=123456

此命令会从README.md创建一个新的MDZ文件,设置标题为"示例文档",作者为"作者",并添加密码保护。输出文件为example.mdz。

extract - 提取MDZ文件内容

将MDZ文件的主要内容提取到Markdown文件中。

mdz extract example.mdz extracted.md --password=123456

此命令会从example.mdz提取主要内容到extracted.md文件中。如果文件有密码保护,需要提供密码。

info - 显示MDZ文件信息

显示MDZ文件的元数据和资源列表。

mdz info example.mdz --password=123456

输出包括文件标题、作者、版本、创建和更新时间、是否加密以及资源列表等信息。

add - 添加资源到MDZ文件

向MDZ文件添加一个资源文件。

mdz add example.mdz image.png --password=123456

此命令会向example.mdz文件添加image.png资源,并返回资源ID。

list - 列出MDZ文件中的资源

列出MDZ文件中所有资源的详细信息。

mdz list example.mdz --password=123456
mdz list example.mdz --json  # 以JSON格式输出

metadata - 更新MDZ文件的元数据

更新MDZ文件的元数据信息,如标题、作者等。

mdz metadata example.mdz --title="新标题" --author="新作者" --password=123456
mdz metadata example.mdz --json='{"title":"JSON格式标题","author":"JSON格式作者"}'

password - 设置或更改MDZ文件的密码

设置新密码、更改现有密码或移除密码保护。

# 设置新密码或更改现有密码
mdz password example.mdz --password=123456 --new-password=654321

# 移除密码保护
mdz password example.mdz --password=123456 --remove

verify - 验证MDZ文件的完整性

验证MDZ文件中所有资源的校验和,检查文件是否被篡改或损坏。

mdz verify example.mdz --password=123456

extract-asset - 提取MDZ文件中的特定资源

根据资源ID提取MDZ文件中的特定资源到指定路径。

mdz extract-asset example.mdz 5f2d8da6-e716-4c0e-8b0c-ec92d0b44dbd ./output.png --password=123456

示例场景

基本工作流程

# 1. 创建MDZ文件
mdz create document.mdz README.md --title="项目文档" --author="团队"

# 2. 查看MDZ文件信息
mdz info document.mdz

# 3. 添加资源
mdz add document.mdz logo.png
mdz add document.mdz screenshot.jpg

# 4. 列出所有资源
mdz list document.mdz

# 5. 提取内容到新文件
mdz extract document.mdz extracted.md

使用密码保护

# 创建带密码的MDZ文件
mdz create secure.mdz confidential.md --password=123456 --title="机密文档"

# 提取受保护的MDZ文件
mdz extract secure.mdz extracted.md --password=123456

# 查看受保护的MDZ文件信息
mdz info secure.mdz --password=123456

# 验证文件完整性
mdz verify secure.mdz --password=123456

# 更改密码
mdz password secure.mdz --password=123456 --new-password=newpass

元数据管理

# 创建MDZ文件
mdz create document.mdz README.md

# 更新元数据
mdz metadata document.mdz --title="更新的标题" --author="新作者"

# 使用JSON格式更新更多元数据字段
mdz metadata document.mdz --json='{"title":"JSON标题","author":"JSON作者","keywords":["markdown","mdz","文档"]}'

批量处理

# 创建一个批处理脚本示例(bash)
#!/bin/bash

# 批量创建MDZ文件
for mdfile in *.md; do
  mdz create "${mdfile%.md}.mdz" "$mdfile" --title="$(basename "${mdfile%.md}")" --author="自动化脚本"
done

# 批量验证MDZ文件
for mdzfile in *.mdz; do
  mdz verify "$mdzfile"
done

API使用示例

创建一个新的MDZ文件

import { MDZFile } from 'markdownzip';

async function createMDZ() {
  // 创建一个新的MDZ文件
  const mdz = new MDZFile('example.mdz');
  
  // 准备Markdown内容
  const content = `# Hello MDZ
  
这是一个MDZ文档示例。

![示例图片](./assets/image.png)
`;
  
  // 创建文件
  await mdz.create(content, {
    title: '示例文档',
    author: '张三',
    password: '可选密码' // 可选
  });
  
  // 添加资源文件
  await mdz.addAsset('/path/to/image.png');
  
  // 保存文件
  await mdz.save();
  
  // 关闭文件
  await mdz.close();
}

打开并读取MDZ文件

import { MDZFile } from 'markdownzip';

async function openMDZ() {
  // 创建MDZ实例
  const mdz = new MDZFile('example.mdz');
  
  // 打开文件(如果有密码保护,则提供密码)
  await mdz.open('可选密码');
  
  // 读取主要内容
  const content = await mdz.getMainContent();
  console.log(content);
  
  // 获取元数据
  const metadata = mdz.getMetadata();
  console.log(`标题: ${metadata.title}`);
  console.log(`作者: ${metadata.author}`);
  
  // 获取资源列表
  const assets = mdz.getAssets();
  console.log(`资源数量: ${assets.length}`);
  
  // 导出资源
  if (assets.length > 0) {
    await mdz.extractAsset(assets[0].id, '/path/to/output.png');
  }
  
  // 关闭文件
  await mdz.close();
}

编辑MDZ文件

import { MDZFile } from 'markdownzip';

async function editMDZ() {
  // 打开现有文件
  const mdz = new MDZFile('example.mdz');
  await mdz.open('可选密码');
  
  // 获取当前内容并修改
  let content = await mdz.getMainContent();
  content += '\n\n## 新章节\n\n这是一个新添加的章节。\n';
  
  // 更新内容
  await mdz.setMainContent(content);
  
  // 更新元数据
  mdz.updateMetadata({
    title: '更新后的文档标题'
  });
  
  // 添加新资源
  await mdz.addAsset('/path/to/another-image.jpg');
  
  // 保存更改
  await mdz.save();
  
  // 关闭文件
  await mdz.close();
}

MDZ文件格式

MDZ文件本质上是一个ZIP文件,具有以下内部结构:

  • manifest.json - 包含元数据和资源列表的清单文件
  • content/ - 包含主Markdown文件及其他内容文件的目录
    • main.md - 主Markdown文件
  • assets/ - 包含所有资源文件的目录
  • signature - 用于验证MDZ文件格式有效性的签名文件

API参考

核心类

MDZFile

主要的类,用于创建、读取和修改MDZ文件。

构造函数:

constructor(filePath?: string, options?: MDZOptions)

方法:

| 方法 | 说明 | 参数 | 返回值 | |------|------|------|--------| | create | 创建新的MDZ文件 | mainContent: string, options?: MDZOptions | Promise<void> | | open | 打开现有MDZ文件 | password?: string | Promise<void> | | save | 保存MDZ文件 | targetPath?: string | Promise<void> | | close | 关闭文件并清理临时资源 | - | Promise<void> | | getMainContent | 获取主Markdown内容 | - | Promise<string> | | setMainContent | 设置主Markdown内容 | content: string | Promise<void> | | addAsset | 添加资源 | sourcePath: string, relativePath?: string | Promise<string> | | removeAsset | 移除资源 | assetId: string | Promise<void> | | getAssetContent | 获取资源内容 | assetId: string | Promise<Buffer> | | extractAsset | 导出资源 | assetId: string, targetPath: string | Promise<void> | | getAssets | 获取所有资源信息 | - | MDZAsset[] | | getMetadata | 获取元数据 | - | MDZMetadata | | updateMetadata | 更新元数据 | metadata: Partial<MDZMetadata> | void | | setPassword | 设置或移除密码保护 | newPassword: string | null, currentPassword?: string | Promise<void> | | isModified | 检查文件是否已修改 | - | boolean |

类型定义

MDZMetadata

MDZ文件的元数据接口。

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | version | string | 是 | MDZ格式版本 | | title | string | 否 | 文档标题 | | author | string | 否 | 作者 | | createdAt | string | 是 | 创建时间,ISO格式 | | updatedAt | string | 是 | 更新时间,ISO格式 | | encrypted | boolean | 是 | 是否加密 | | checksum | string | 是 | 校验和 |

MDZAsset

MDZ文件的资源项目接口。

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | id | string | 是 | 资源唯一标识符 | | path | string | 是 | 资源在zip中的路径 | | originalName | string | 是 | 原始文件名 | | mimeType | string | 是 | MIME类型 | | size | number | 是 | 文件大小(字节) | | checksum | string | 是 | 文件校验和 |

MDZManifest

MDZ文件的清单接口。

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | metadata | MDZMetadata | 是 | 元数据 | | mainDocument | string | 是 | 主Markdown文件路径 | | assets | MDZAsset[] | 是 | 资源列表 |

MDZOptions

创建或修改MDZ文件时的选项。

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | title | string | 否 | 文档标题 | | author | string | 否 | 作者 | | password | string | 否 | 加密密码 | | tempDir | string | 否 | 临时目录路径 | | mainFileName | string | 否 | 主文件名(默认为main.md) |

MDZErrorType

MDZ操作错误类型枚举。

| 枚举值 | 说明 | |------|------| | FILE_NOT_FOUND | 文件未找到或无法访问 | | INVALID_FORMAT | 无效的MDZ格式或结构 | | ENCRYPTION_ERROR | 加密或解密错误 | | CHECKSUM_MISMATCH | 校验和验证失败 | | IO_ERROR | 输入/输出操作错误 | | UNKNOWN_ERROR | 未知或未指定的错误 | | PERMISSION_DENIED | 权限被拒绝 | | VALIDATION_ERROR | 内容验证错误 | | TIMEOUT | 操作超时 |

高级用法

处理错误

MDZ库使用自定义错误类型处理错误情况:

import { MDZFile, MDZError, MDZErrorType } from 'markdownzip';

async function handleMDZErrors() {
  try {
    const mdz = new MDZFile('example.mdz');
    await mdz.open('错误密码');
  } catch (error) {
    if (error instanceof MDZError) {
      switch (error.type) {
        case MDZErrorType.ENCRYPTION_ERROR:
          console.error('密码错误或加密问题:', error.message);
          break;
        case MDZErrorType.FILE_NOT_FOUND:
          console.error('文件不存在:', error.message);
          break;
        case MDZErrorType.INVALID_FORMAT:
          console.error('无效的MDZ格式:', error.message);
          break;
        default:
          console.error('MDZ错误:', error.message);
      }
    } else {
      console.error('未知错误:', error);
    }
  }
}

批量资源处理

处理大量资源文件的示例:

import { MDZFile } from 'markdownzip';
import * as fs from 'fs';
import * as path from 'path';

async function batchAssetProcessing() {
  const mdz = new MDZFile('document.mdz');
  await mdz.create('# 多资源文档');
  
  // 读取目录中的所有图像文件
  const imageDir = '/path/to/images';
  const files = fs.readdirSync(imageDir)
    .filter(file => ['.jpg', '.png', '.gif'].includes(path.extname(file).toLowerCase()));
  
  // 添加所有图像
  for (const file of files) {
    const filePath = path.join(imageDir, file);
    const assetId = await mdz.addAsset(filePath);
    console.log(`添加资源: ${file}, ID: ${assetId}`);
  }
  
  // 更新内容,包含所有图像的引用
  const imageReferences = files.map(file => 
    `![${path.basename(file, path.extname(file))}](./assets/${file})`
  ).join('\n\n');
  
  await mdz.setMainContent(`# 多资源文档\n\n${imageReferences}`);
  await mdz.save();
  await mdz.close();
}

导出与转换

将MDZ文件导出为其他格式:

import { MDZFile } from 'markdownzip';
import * as fs from 'fs';
import * as path from 'path';

async function exportMDZ() {
  const mdz = new MDZFile('example.mdz');
  await mdz.open();
  
  // 创建导出目录
  const exportDir = './export';
  if (!fs.existsSync(exportDir)) {
    fs.mkdirSync(exportDir, { recursive: true });
  }
  
  // 导出主内容
  const content = await mdz.getMainContent();
  fs.writeFileSync(path.join(exportDir, 'content.md'), content);
  
  // 导出所有资源
  const assets = mdz.getAssets();
  const assetsDir = path.join(exportDir, 'assets');
  if (!fs.existsSync(assetsDir)) {
    fs.mkdirSync(assetsDir, { recursive: true });
  }
  
  for (const asset of assets) {
    await mdz.extractAsset(asset.id, path.join(assetsDir, asset.originalName));
  }
  
  // 导出元数据
  const metadata = mdz.getMetadata();
  fs.writeFileSync(
    path.join(exportDir, 'metadata.json'), 
    JSON.stringify(metadata, null, 2)
  );
  
  await mdz.close();
  console.log(`已导出到 ${exportDir}`);
}

安全特性

MDZ格式具有多项安全特性:

  1. 密码保护 - 使用AES-256-CBC加密算法保护敏感内容
  2. 数据完整性 - 使用SHA-256校验和验证文件未被篡改
  3. 安全的路径处理 - 防止目录遍历攻击
  4. 签名验证 - 验证MDZ文件格式的有效性

加密详情

MDZ使用以下加密实现:

  • 使用PBKDF2进行密钥派生,增强密码强度
  • 使用随机盐和初始化向量(IV)确保加密安全性
  • 加密结果包含算法信息、盐值和IV,便于未来格式升级

兼容性与性能

  • 支持Node.js 14及以上版本
  • 支持处理大型文件(>1GB)和大量资源
  • 所有文件操作均支持异步处理,避免阻塞主线程

贡献

欢迎贡献代码、提交问题或改进建议。提交PR前请确保:

  1. 代码遵循项目的代码风格
  2. 添加适当的测试用例
  3. 更新相关文档

许可证

MIT