pinme-email
Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.
Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying id_tokens, querying user info, or listing users via Identity Platform auth proxy APIs.
$ npx -y skills add glitternetwork/pinme --skill pinme-auth --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/pinme-authContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying id_tokens, querying user info, or listing users via Identity Platform auth proxy APIs.
name: pinme-auth description: Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying id_tokens, querying user info, or listing users via Identity Platform auth proxy APIs.
Guides how to call PinMe platform's Identity Platform auth proxy APIs in a PinMe Worker (TypeScript).
// backend/src/worker.ts
export interface Env {
DB: D1Database;
API_KEY: string; // 项目 API Key — 用于所有 auth 接口认证
PROJECT_NAME: string; // 项目名 — 所有 auth 接口必须同时传递
BASE_URL?: string; // 可选,默认 https://pinme.cloud
}> `API_KEY` 和 `PROJECT_NAME` 是所有 auth 接口的必填凭证,缺一不可。
---
| 参数 | 传递方式 | 必填 | 说明 | |------|---------|------|------| | `X-API-Key` | 请求头 | 是 | 项目 API Key | | `project_name` | Query 参数 | 是 | 必须与 `X-API-Key` 对应同一个项目 |
服务端会先校验这两个字段是否匹配同一个项目,再从项目配置中取出 `tenant_id`,然后转调 Identity Platform。
---
| 场景 | HTTP | `data.error` | |------|------|-------------| | 缺少 `X-API-Key` | 401 | `X-API-Key header is required` | | 缺少 `project_name` | 400 | `project_name is required` | | API Key 和项目不匹配 | 401 | `Invalid API key or project name` | | 项目未配置认证租户 | 400 | `Auth service not configured for this project` |
---
type ApiEnvelope<T> = {
code: number // 200=成功,其他=失败
msg: string // "ok" | "fail" | "invalid param"
data: T
}
type ApiErrorData = { error?: string }
type UserInfo = {
uid: string
email: string
display_name: string
photo_url?: string
disabled: boolean
email_verified: boolean
}---
**Endpoint:** `POST {BASE_URL}/api/v1/auth/create_user?project_name={project_name}`
仅用于邮箱密码注册。成功时用户已创建且验证邮件已发出;失败时自动回滚,不会留下僵尸账号。
> 创建成功后用户默认仍是"未验证"状态,需点击邮件验证链接后,`verify_token` 才能通过校验。
{ "email": "alice@example.com", "password": "Test@12345678", "display_name": "Alice" }| 字段 | 类型 | 必填 | |------|------|------| | `email` | string | 是 | | `password` | string | 是 | | `display_name` | string | 否 |
| 场景 | HTTP | `data.error` | |------|------|-------------| | 缺少 email/password | 400 | `email and password are required` | | 上游创建失败 | 502 | `Failed to create user` | | 发送验证邮件失败 | 500 | `Failed to send verification email. Please try again.` |
async function createAuthUser(
env: Env,
payload: { email: string; password: string; display_name?: string }
): Promise<{ user?: UserInfo; error?: string }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/create_user?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,
{
method: 'POST',
headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
}
);
const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
return { error: (result.data as ApiErrorData)?.error ?? result.msg };
}
return { user: result.data as UserInfo };
}---
**Endpoint:** `POST {BASE_URL}/api/v1/auth/verify_token?project_name={project_name}`
校验前端登录后拿到的 `id_token`(邮箱密码或 Google 登录均适用)。
**注意:** token 合法但邮箱未验证时返回 `403`,不是 `401`。
{ "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6..." }type VerifyTokenData = {
uid: string
email?: string
tenant_id: string
claims: Record<string, unknown>
}| 场景 | HTTP | `data.error` | |------|------|-------------| | 缺少 `id_token` | 400 | `id_token is required` | | token 无效或过期 | 401 | `Invalid or expired token` | | 邮箱未验证 | 403 | `Email not verified. Please check your inbox and verify your email address.` |
async function verifyAuthToken(
env: Env,
idToken: string
): Promise<{ uid?: string; email?: string; error?: string; emailNotVerified?: boolean }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/verify_token?project_name=${encodeURIComponent(env.PROJECT_NAME)}`,
{
method: 'POST',
headers: { 'X-API-Key': env.API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: idToken }),
}
);
const result = await resp.json() as ApiEnvelope<VerifyTokenData | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
const error = (result.data as ApiErrorData)?.error ?? result.msg;
return { error, emailNotVerified: resp.status === 403 };
}
const data = result.data as VerifyTokenData;
return { uid: data.uid, email: data.email };
}---
**Endpoint:** `GET {BASE_URL}/api/v1/auth/user?project_name={project_name}&uid={uid}`
| 场景 | HTTP | `data.error` | |------|------|-------------| | 缺少 `uid` | 400 | `uid is required` | | 用户不存在 | 404 | `User not found` | | 上游查询失败 | 502 | `Failed to get user` |
async function getAuthUser(env: Env, uid: string): Promise<{ user?: UserInfo; error?: string }> {
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
const resp = await fetch(
`${baseUrl}/api/v1/auth/user?project_name=${encodeURIComponent(env.PROJECT_NAME)}&uid=${encodeURIComponent(uid)}`,
{ method: 'GET', headers: { 'X-API-Key': env.API_KEY } }
);
const result = await resp.json() as ApiEnvelope<UserInfo | ApiErrorData>;
if (!resp.ok || result.code !== 200) {
return { error: (result.data as ApiErrorData)?.error ?? result.msg };
}
return { user: result.data as UserInfo };
}---
**Endpoint:** `GET {BASE_URL}/api/v1/auth/list_users?project_name={project_name}`
默认 `max_results=100`,最大 `1000`。通过 `next_page_token` 循环翻页。
| 参数 | 必填 | 说明 | |------|------|------| | `project_name` | 是 | 项目名 | | `page_token` | 否 | 分页游标 | | `max_results` | 否 | 每页数量,1–1000 |
async function listAuthUse
PinMe is a zero-config deployment CLI focused on one-command creation and deployment for full-stack projects. It lets you quickly set up and launch a complete project with an integrated frontend, Worker backend, and database, without tedious configuration.
Repo: glitternetwork/pinme
Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.
Use this skill when a PinMe project (Worker TypeScript) needs to call OpenRouter-backed LLM APIs, including models, chat/completions, streaming, or OpenRouter…
Use when a PinMe Cloudflare Worker needs R2 object storage, including secure file or image upload, streaming download, metadata lookup, deletion, listing,…
Use this skill when the user wants to share, publish, or upload a static result through PinMe, especially by generating a static HTML share page for a PinMe…
Use when generating, modifying, or reviewing PinMe Worker (Cloudflare Worker TypeScript) code that accepts payments through UniwebPay — payment links,…
Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or full-stack services (including…