mcpField
P
pinme

pinme

github.com/glitternetwork云与 DevOps3.8k711 次安装15 周前更新
代码仓库

关于 pinme

pinme 是面向 Agent 的部署技能,指导使用 PinMe CLI 发布静态文件,或创建并部署包含 React + Vite、Cloudflare Worker 和 D1 的全栈项目。它还涵盖分阶段更新、R2 对象存储及 Worker 邮件发送。

主要功能

  1. 01上传静态文件到 IPFS
  2. 02创建全栈项目模板
  3. 03部署 Worker 与 D1 数据库
  4. 04分别更新前端、后端或数据库
  5. 05使用 R2 存储对象

适用场景

  1. 01发布静态网站或单个文件
  2. 02部署带 API 和数据库的 Web 应用
  3. 03为 Worker 增加文件存储或邮件发送

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/glitternetwork/pinme --skill pinme

安装后在 Claude Code 中输入/pinme确认已加载。

详细介绍

PinMe

零配置部署工具:将静态文件上传到 IPFS,或创建并部署全栈 Web 项目(React+Vite + Cloudflare Worker + D1 数据库)。Worker 还支持通过 PinMe 平台 API 发送电子邮件。

适用场景

digraph pinme_decision {
    "User Request" [shape=doublecircle];
    "Needs backend API or database?" [shape=diamond];
    "Upload Files (Path 1)" [shape=box];
    "Full-Stack Project (Path 2)" [shape=box];

    "User Request" -> "Needs backend API or database?";
    "Needs backend API or database?" -> "Upload Files (Path 1)" [label="No"];
    "Needs backend API or database?" -> "Full-Stack Project (Path 2)" [label="Yes"];
}

路径 1:上传文件 / 静态网站

需要登录。在运行 pinme upload 或 pinme import 前,请使用 pinme login 或 pinme set-appkey <AppKey>。

digraph upload_flow {
    "Install/update pinme to latest" [shape=box];
    "Authenticate" [shape=box];
    "Determine build artifacts" [shape=box];
    "pinme upload <path>" [shape=box];
    "Return preview URL" [shape=doublecircle];

    "Install/update pinme to latest" -> "Authenticate";
    "Authenticate" -> "Determine build artifacts";
    "Determine build artifacts" -> "pinme upload <path>";
    "pinme upload <path>" -> "Return preview URL";
}

1. 检查安装情况并更新到最新版本:

LOCAL=$(pinme --version 2>/dev/null || echo "0.0.0")
LATEST=$(npm view pinme version)
[ "$LOCAL" != "$LATEST" ] && npm install -g pinme@latest || echo "pinme is up to date ($LOCAL)"

2. 进行身份验证:

pinme login
# or: pinme set-appkey <AppKey>

3. 确定上传目标(按优先级排序):

  1. dist/ — Vite / Vue / React
  2. build/ — Create React App
  3. out/ — Next.js 静态导出
  4. public/ — 普通静态文件

4. 上传:

pinme upload <path>
pinme upload ./dist --domain my-site  # Optional: bind subdomain (wallet balance required)

5. 返回 PinMe 输出的最终 URL 给用户。URL 优先级为:DNS 域名 > PinMe 子域名 > 短 URL > 预览 URL。如果回退到预览 URL,请返回包含所有哈希字符的完整 URL,不要截断。

常见示例
pinme upload ./document.pdf          # Single file
pinme upload ./my-folder             # Folder
pinme upload dist                    # Vite/Vue build artifacts
pinme upload build                   # CRA build artifacts
pinme upload out                     # Next.js static export
pinme upload ./dist --domain my-site # Bind PinMe subdomain (wallet balance required)
pinme import ./my-archive.car        # Import CAR file
请勿上传
  • node_modules/、.env、.git/、src/
  • 只上传构建产物,绝不上传源代码

路径 2:全栈项目

需要登录。使用 React+Vite 前端 + Cloudflare Worker 后端 + D1 SQLite 数据库。 设计前端项目时,请以 Ant Design 作为主要设计参考,并优先遵循其布局、组件、间距和交互模式规范。

digraph fullstack_flow {
    "Install/update pinme to latest" [shape=box];
    "pinme login" [shape=box];
    "pinme create <name>" [shape=box];
    "Modify template code" [shape=box];
    "pinme save" [shape=box];
    "Return preview URL" [shape=doublecircle];

    "Install/update pinme to latest" -> "pinme login";
    "pinme login" -> "pinme create <name>";
    "pinme create <name>" -> "Modify template code";
    "Modify template code" -> "pinme save";
    "pinme save" -> "Return preview URL";
}
架构
层级技术栈部署目标
前端React + Vite(frontend/)IPFS
后端Cloudflare Worker(backend/src/worker.ts){name}.pinme.pro
数据库D1 SQLite(db/*.sql)Cloudflare D1
对象存储R2(env.R2)Cloudflare R2
按功能分类的技能
  • 对于 Worker 文件上传、下载、图像、附件、媒体或对象存储,请使用 pinme-r2 技能。PinMe 会将项目存储桶注入为 env.R2;不要用 D1 BLOB 或 Worker 文件系统状态替代它。
核心命令
pinme login                  # Login (only needed once)
pinme create <dirName>       # Clone template and create project (auto-fills API URL)
pinme save                   # First deploy / full update (frontend + backend + database, single command)
pinme update-worker          # Update backend only (when only backend/src/worker.ts was modified)
pinme update-web             # Update frontend only (when only frontend/src/ was modified)
pinme update-db              # Run SQL migrations only (when only db/ was modified)

pinme save 会一次性部署前端、后端和数据库。只有在确定仅修改了其中一部分时,才使用 pinme update-*。

项目结构
{project}/
├── pinme.toml              # Root config (auto-generated, do not modify)
├── package.json            # Monorepo root (workspaces: frontend + backend)
├── backend/
│   ├── wrangler.toml       # Worker config (auto-generated, do not modify)
│   ├── package.json
│   └── src/
│       └── worker.ts       # Backend entry — primarily used for JSON APIs in this template
├── db/
│   └── 001_init.sql        # SQL table definitions
├── frontend/
│   ├── package.json
│   ├── vite.config.ts      # Dev proxy: /api → localhost:8787
│   ├── index.html
│   ├── .env                # Auto-generated: VITE_API_URL (do not modify)
│   └── src/
│       ├── main.tsx
│       ├── App.tsx
│       ├── utils/
│       │   ├── api.ts      # export const API = import.meta.env.VITE_WORKER_URL || ''
│       │   └── config.ts   # Auto-generated: public_client_config (only when auth is enabled)
│       └── pages/
│           └── Home/
│               └── index.tsx
└── .gitignore
首次部署
LOCAL=$(pinme --version 2>/dev/null || echo "0.0.0")
LATEST=$(npm view pinme version)
[ "$LOCAL" != "$LATEST" ] && npm install -g pinme@latest
pinme login
pinme create my-app
cd my-app

pinme create 会生成一个可运行的 Hello World 模板(包含前端页面、后端 API 路由和数据库架构)。请修改模板以匹配用户的业务逻辑,不要从头编写:

  • 修改 backend/src/worker.ts — 替换 API 路由
  • 修改 frontend/src/pages/ — 替换页面组件
  • 修改 db/001_init.sql — 替换表定义
pinme save
# Single command deploys frontend + backend + database
# Outputs preview URL: https://pinme.eth.limo/#/preview/{CID}

返回预览 URL 给用户。注意:请返回包含所有哈希字符的完整 URL,不要截断。

后端 Worker 部署在 https://{name}.pinme.pro。前端 API 请求已自动配置为指向该地址,无需手动设置。

后续更新
更改内容命令备注
仅后端(backend/src/worker.ts)pinme update-worker更快
仅前端(frontend/src/)pinme update-web生成新的 CID
仅数据库(db/)pinme update-db执行新的迁移
多项更改或不确定pinme save安全的完整部署

每次前端部署都会生成新的 CID 和预览 URL。旧 URL 仍可访问。


Worker 代码模式(backend/src/worker.ts)

在此模板中,Worker 后端主要用于 JSON API。默认情况下,优先使用标准 Web API 和简单的手动路由。必要时可以添加兼容 Worker 的库,但默认模板不依赖额外框架。避免使用依赖完整 Node.js 运行时、持久化本地文件系统、原生二进制文件或子进程的软件包。

export interface Env {
  DB: D1Database;           // When using database
  R2: R2Bucket;             // Project object storage; injected by PinMe
  API_KEY?: string;         // When using email sending
  JWT_SECRET: string;       // When using JWT auth
  ADMIN_PASSWORD: string;   // When using password auth
}

const CORS_HEADERS = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',
};

function json(data: unknown, status = 200): Response {
  return Response.json(data, { status, headers: CORS_HEADERS });
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { pathname } = new URL(request.url);
    const method = request.method;

    if (method === 'OPTIONS') return new Response(null, { status: 204, headers: CORS_HEADERS });

    try {
      if (pathname === '/api/items' && method === 'GET')  return handleGetItems(env);
      if (pathname === '/api/items' && method === 'POST') return handleCreateItem(request, env);
      return json({ error: 'Not found' }, 404);
    } catch {
      return json({ error: 'Internal server error' }, 500);
    }
  },
};
Worker 约束和默认约定
项目说明
依赖选择默认优先使用标准 Web API 和简单的手动路由。如需额外依赖,优先选择兼容 Worker 的库。
Node.js 能力Workers 现在支持部分 Node.js 兼容功能,但并非完整的 Node.js 运行时。不要假设所有 Node.js 内置模块都可用,或其行为完全相同。
文件系统不要把 Worker 当作拥有持久本地磁盘的服务端。即使某些 fs 功能可用,也不要依赖其在请求之间持久保存数据。
响应类型此模板主要使用 Worker 提供 JSON API。如有明确需要,也可以改为返回 HTML 或其他内容。
密码存储切勿以明文存储密码。应使用 bcrypt、scrypt 或 Argon2 等专用密码哈希算法。
SQL不要通过字符串拼接构建 SQL。应使用 .bind() 等参数化查询。
邮件 API 参考(用于 Worker 后端)

后端需要发送邮件时,请使用 PinMe 平台 API(https://pinme.cloud/api/v4/send_email)。

1. 配置 API_KEY

添加到 Env 接口:

export interface Env {
  DB: D1Database;
  API_KEY?: string;  // Required for email sending
}

2. 邮件处理程序代码

async function handleSendEmail(request: Request, env: Env): Promise<Response> {
  const apiKey = env.API_KEY;
  if (!apiKey) {
    return json({ error: 'API_KEY not configured' }, 500);
  }

  const body = await request.json() as {
    to?: string;
    subject?: string;
    html?: string;
  };

  if (!body.to) return json({ error: 'Email address is required' }, 400);
  if (!body.subject) return json({ error: 'Subject is required' }, 400);
  if (!body.html) return json({ error: 'HTML content is required' }, 400);

  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(body.to)) {
    return json({ error: 'Invalid email address' }, 400);
  }

  const response = await fetch('https://pinme.cloud/api/v4/send_email', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey,
    },
    body: JSON.stringify({
      to: body.to,
      subject: body.subject,
      html: body.html,
    }),
  });

  const result = await response.json();
  return json(result);
}

前端 API 工具(frontend/src/utils/api.ts)

// Development: Vite proxies /api to localhost:8787
// Production: VITE_API_URL is auto-injected by pinme create
export const API = import.meta.env.VITE_API_URL || '';

export function getApiUrl(path: string): string {
  return API ? `${API}${path}` : path;
}

D1 数据库操作

// Query multiple rows
const { results } = await env.DB.prepare('SELECT * FROM t WHERE x = ?').bind(val).all();

// Query single row (returns null if not found)
const row = await env.DB.prepare('SELECT * FROM t WHERE id = ?').bind(id).first();

// Insert and return new row
const row = await env.DB.prepare('INSERT INTO t (a, b) VALUES (?, ?) RETURNING *').bind(a, b).first();

// Update
await env.DB.prepare('UPDATE t SET a = ? WHERE id = ?').bind(val, id).run();

// Delete (check if affected)
const { meta } = await env.DB.prepare('DELETE FROM t WHERE id = ?').bind(id).run();
if (meta.changes === 0) return json({ error: 'Not found' }, 404);
SQL 迁移文件

格式: db/NNN_description.sql(例如,001_init.sql)。文件按文件名顺序执行。

SQLite 类型限制:

不要使用替代方案
BOOLEANINTEGER(0 = false,1 = true)
DATETIME / TIMESTAMPTEXT,以 ISO 8601 格式存储(默认值:datetime('now'))
JSON 类型TEXT,使用 JSON.stringify() / JSON.parse()
VARCHAR(n)TEXT

模板架构建议

场景默认建议
文件存储(图片、附件、媒体)通过 env.R2 使用项目的 R2 绑定;使用 pinme-r2 技能了解安全路由和元数据模式
实时通信此模板默认使用常规 HTTP API。如果没有明确的实时需求,请从轮询开始
多个 Worker此模板默认将功能整合到单个 Worker 中,并按前缀区分路由
多个数据库此模板默认将数据整合到一个 D1 数据库中,仅在确实需要隔离时才拆分

重要说明

  • pinme.toml、backend/wrangler.toml 和 frontend/.env 由 PinMe 生成。默认情况下不要手动编辑这些文件。如果确实需要额外的运行时配置,优先通过 PinMe 支持的机制进行设置。
  • 从 VITE_API_URL 环境变量获取前端 API URL。不要将其硬编码。
  • 密码、令牌和 API 密钥必须存储在机密中。切勿将其放入配置文件。

常见错误

错误解决方案
command not found: pinmenpm install -g pinme
No such file or directory确认路径存在
Permission denied检查文件或目录权限
上传失败检查网络连接并重试
未登录先运行 pinme login

其他命令

pinme list / pinme ls -l 5     # View upload history
pinme list -c                  # Clear upload history
pinme rm <hash>                # Delete uploaded content
pinme bind <path> --domain <domain>  # Bind domain (VIP + AppKey required)
pinme export <CID>             # Export as CAR file
pinme set-appkey               # Set/view AppKey
pinme my-domains               # List bound domains
pinme delete <project>          # Delete project (Worker + domain + D1)
pinme logout                   # Log out

评论

支持 Markdown