关于 pinme
pinme 是面向 Agent 的部署技能,指导使用 PinMe CLI 发布静态文件,或创建并部署包含 React + Vite、Cloudflare Worker 和 D1 的全栈项目。它还涵盖分阶段更新、R2 对象存储及 Worker 邮件发送。
主要功能
- 01上传静态文件到 IPFS
- 02创建全栈项目模板
- 03部署 Worker 与 D1 数据库
- 04分别更新前端、后端或数据库
- 05使用 R2 存储对象
适用场景
- 01发布静态网站或单个文件
- 02部署带 API 和数据库的 Web 应用
- 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. 确定上传目标(按优先级排序):
dist/— Vite / Vue / Reactbuild/— Create React Appout/— Next.js 静态导出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 类型限制:
| 不要使用 | 替代方案 |
|---|---|
BOOLEAN | INTEGER(0 = false,1 = true) |
DATETIME / TIMESTAMP | TEXT,以 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: pinme | npm 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