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. 03WorkerとD1データベースをデプロイ
  4. 04フロントエンド・バックエンド・DBを個別更新
  5. 05R2でオブジェクトを保存

活用シーン

  1. 01静的サイトや単一ファイルの公開
  2. 02APIとデータベースを備えたWebアプリのデプロイ
  3. 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. アップロード先を決定します(優先順位順):

  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 はフロントエンド、バックエンド、データベースを一度にデプロイします。変更したのが 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 の型制約:

使用しない型代替
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 がサポートする方法で設定することを優先してください。
  • フロントエンドの API URL は VITE_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

コメント