pinme について
pinmeは、AgentがPinMe CLIで静的ファイルを公開したり、React + Vite、Cloudflare Worker、D1を使うフルスタックプロジェクトを構築・デプロイしたりするためのスキルです。個別更新、R2ストレージ、Workerからのメール送信も扱います。
主な機能
- 01静的ファイルをIPFSへアップロード
- 02フルスタックの雛形を作成
- 03WorkerとD1データベースをデプロイ
- 04フロントエンド・バックエンド・DBを個別更新
- 05R2でオブジェクトを保存
活用シーン
- 01静的サイトや単一ファイルの公開
- 02APIとデータベースを備えたWebアプリのデプロイ
- 03Workerへのファイル保存やメール送信の追加
インストール
コマンドをコピーしてターミナルで実行します。
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はフロントエンド、バックエンド、データベースを一度にデプロイします。変更したのが 1 つの部分だけだと確実にわかっている場合に限り、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 の機能 | Worker は現在、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 がサポートする方法で設定することを優先してください。- フロントエンドの API URL は
VITE_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