Token导航 LogoToken导航

Agent Skill · 运维和基础设施

vercel-blob(Vercel blob 浏览器)

vercel-blob 用于记录任务执行中的错误、用户纠正、经验和能力缺口,适合在 Codex、Claude、Cursor、Gemini CLI 中希望让 Agent 持续沉淀问题、修正和最佳实践时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

vercel-blob 是运维和基础设施类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证为 MIT,第三方扫描已通过,按安装量在运维和基础设施类的 2,449 个 Skill 里排第 246。

总安装 8,007周安装 337GitHub Stars 750下载 2,804核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:vercel-blob(Vercel blob 浏览器)
来源仓库:https://github.com/jezweb/claude-skills
仓库路径:skills/vercel-blob
安装命令:
npx skills add https://github.com/jezweb/claude-skills --skill vercel-blob
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/jezweb/claude-skills --skill vercel-blob

这个 Skill 是做什么的

运维和基础设施类 Skill 处理部署、监控、日志和云资源,多数需要较高的执行权限。

具有预签名令牌和多部分支持的 Next.js 安全文件上传和 CDN 交付。

支持通过 put() 进行服务器端上传 以及通过handleUpload()使用预签名令牌进行客户端上传 以避免暴露凭证 通过自动分段上传处理最大 500MB 的文件;客户端上传绕过 4.5MB 无服务器功能限制 包括带有基于光标的分页、删除和内容类型管理的文件列表,以实现正确的浏览器处理 防止 16 个已记录的问题,包括大文件的令牌过期、文件名冲突、跨浏览器兼容性和路径名验证错误

来源仓库内路径:skills/vercel-blob

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/jezweb/claude-skills --skill vercel-blob;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

vercel-blob 怎么安装?

在终端执行 npx skills add https://github.com/jezweb/claude-skills --skill vercel-blob。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

vercel-blob 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

vercel-blob 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

vercel-blob 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

vercel-blob 用的人多吗?

公开数据是累计安装 8,007 次,近一周安装 337 次,下载 2,804 次,GitHub 750 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

vercel-blob 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理运维和基础设施类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要厂商级技术支持和 SLA 的生产系统。

运维和基础设施类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
brainstorming

头脑风暴 · Codex、Claude

3,148,776173,131操作浏览器MIT通过
copywriting

文案写作 · Codex、Claude

1,996,72425,583需要联网MIT通过
openclaw-secure-linux-cloud

OpenClaw secure linux cloud 命令行 · Codex、Claude

1,853,08840接触敏感数据未明确未通过
xget

xget 命令行 · Codex、Claude

1,799,28040执行命令未明确未通过
requesting-code-review

代码审查请求 · Codex、Claude

1,590,144173,103权限未标注MIT通过
vercel-blob

Vercel blob 浏览器 · 本页

8,007750接触敏感数据MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Vercel Blob

Last Updated: 2026-01-21 Version: @vercel/blob@2.0.0 Skill Version: 2.1.0


Quick Start

# Create Blob store: Vercel Dashboard → Storage → Blob
vercel env pull .env.local  # Creates BLOB_READ_WRITE_TOKEN
npm install @vercel/blob

Server Upload:

'use server';
import { put } from '@vercel/blob';

export async function uploadFile(formData: FormData) {
  const file = formData.get('file') as File;
  const blob = await put(file.name, file, { access: 'public' });
  return blob.url;
}

CRITICAL: Never expose BLOB_READ_WRITE_TOKEN to client. Use handleUpload() for client uploads.


Client Upload (Secure)

Server Action (generates presigned token):

'use server';
import { handleUpload } from '@vercel/blob/client';

export async function getUploadToken(filename: string) {
  return await handleUpload({
    body: {
      type: 'blob.generate-client-token',
      payload: { pathname: `uploads/${filename}`, access: 'public' }
    },
    request: new Request('https://dummy'),
    onBeforeGenerateToken: async (pathname) => ({
      allowedContentTypes: ['image/jpeg', 'image/png'],
      maximumSizeInBytes: 5 * 1024 * 1024
    })
  });
}

Client Component:

'use client';
import { upload } from '@vercel/blob/client';

const tokenResponse = await getUploadToken(file.name);
const blob = await upload(file.name, file, {
  access: 'public',
  handleUploadUrl: tokenResponse.url
});

File Management

List/Delete:

import { list, del } from '@vercel/blob';

// List with pagination
const { blobs, cursor } = await list({ prefix: 'uploads/', cursor });

// Delete
await del(blobUrl);

Multipart (>500MB):

import { createMultipartUpload, uploadPart, completeMultipartUpload } from '@vercel/blob';

const upload = await createMultipartUpload('large-video.mp4', { access: 'public' });
// Upload chunks in loop...
await completeMultipartUpload({ uploadId: upload.uploadId, parts });

Critical Rules

Always:

  • ✅ Use handleUpload() for client uploads (never expose BLOB_READ_WRITE_TOKEN)
  • ✅ Validate file type/size before upload
  • ✅ Use pathname organization (avatars/, uploads/)
  • ✅ Add timestamp/UUID to filenames (avoid collisions)

Never:

  • ❌ Expose BLOB_READ_WRITE_TOKEN to client
  • ❌ Upload >500MB without multipart
  • ❌ Skip file validation

Known Issues Prevention

This skill prevents 16 documented issues:

Issue #1: Missing Environment Variable

Error: Error: BLOB_READ_WRITE_TOKEN is not defined Source: https://vercel.com/docs/storage/vercel-blob Why It Happens: Token not set in environment Prevention: Run vercel env pull.env.local and ensure .env.local in .gitignore.

Issue #2: Client Upload Token Exposed

Error: Security vulnerability, unauthorized uploads Source: https://vercel.com/docs/storage/vercel-blob/client-upload Why It Happens: Using BLOB_READ_WRITE_TOKEN directly in client code Prevention: Use handleUpload() to generate client-specific tokens with constraints.

Issue #3: File Size Limit Exceeded

Error: Error: File size exceeds limit (500MB) Source: https://vercel.com/docs/storage/vercel-blob/limits Why It Happens: Uploading file >500MB without multipart upload Prevention: Validate file size before upload, use multipart upload for large files.

Issue #4: Wrong Content-Type

Error: Browser downloads file instead of displaying (e.g., PDF opens as text) Source: Production debugging Why It Happens: Not setting contentType option, Blob guesses incorrectly Prevention: Always set contentType: file.type or explicit MIME type.

Issue #5: Public File Not Cached

Error: Slow file delivery, high egress costs Source: Vercel Blob best practices Why It Happens: Using access: 'private' for files that should be public Prevention: Use access: 'public' for publicly accessible files (CDN caching).

Issue #6: List Pagination Not Handled

Error: Only first 1000 files returned, missing files Source: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#list Why It Happens: Not iterating with cursor for large file lists Prevention: Use cursor-based pagination in loop until cursor is undefined.

Issue #7: Delete Fails Silently

Error: Files not deleted, storage quota fills up Source: https://github.com/vercel/storage/issues/150 Why It Happens: Using wrong URL format, blob not found Prevention: Use full blob URL from put() response, check deletion result.

Issue #8: Upload Timeout (Large Files) + Server-Side 4.5MB Limit

Error: Error: Request timeout for files >100MB (server) OR file upload fails at 4.5MB (serverless function limit) Source: Vercel function timeout limits + 4.5MB serverless limit + Community Discussion Why It Happens:

  • Serverless function timeout (10s free tier, 60s pro) for server-side uploads
  • CRITICAL: Vercel serverless functions have a hard 4.5MB request body limit. Using put() in server actions/API routes fails for files >4.5MB.

Prevention: Use client-side upload with handleUpload() for files >4.5MB OR use multipart upload.

// ❌ Server-side upload fails at 4.5MB
export async function POST(request: Request) {
  const formData = await request.formData();
  const file = formData.get('file') as File; // Fails if >4.5MB
  await put(file.name, file, { access: 'public' });
}

// ✅ Client upload bypasses 4.5MB limit (supports up to 500MB)
const blob = await upload(file.name, file, {
  access: 'public',
  handleUploadUrl: '/api/upload/token',
  multipart: true, // For files >500MB, use multipart
});

Issue #9: Filename Collisions

Error: Files overwritten, data loss Source: Production debugging Why It Happens: Using same filename for multiple uploads Prevention: Add timestamp/UUID: ` uploads/${Date.now()}-${file.name} or addRandomSuffix: true`.

Issue #10: Missing Upload Callback

Error: Upload completes but app state not updated Source: https://vercel.com/docs/storage/vercel-blob/client-upload#callback-after-upload Why It Happens: Not implementing onUploadCompleted callback Prevention: Use onUploadCompleted in handleUpload() to update database/state.

Issue #11: Client Upload Token Expiration for Large Files

Error: Error: Access denied, please provide a valid token for this resource Source: GitHub Issue #443 Why It Happens: Default token expires after 30 seconds. Large files (>100MB) take longer to upload, causing token expiration before validation. Prevention: Set validUntil parameter for large file uploads.

// For large files (>100MB), extend token expiration
const jsonResponse = await handleUpload({
  body,
  request,
  onBeforeGenerateToken: async (pathname) => {
    return {
      maximumSizeInBytes: 200 * 1024 * 1024,
      validUntil: Date.now() + 300000, // 5 minutes
    };
  },
});

Issue #12: v2.0.0 Breaking Change - onUploadCompleted Requires callbackUrl (Non-Vercel Hosting)

Error: onUploadCompleted callback doesn't fire when not hosted on Vercel Source: Release Notes @vercel/blob@2.0.0 Why It Happens: v2.0.0 removed automatic callback URL inference from client-side location.href for security. When not using Vercel system environment variables, you must explicitly provide callbackUrl. Prevention: Explicitly provide callbackUrl in onBeforeGenerateToken for non-Vercel hosting.

// v2.0.0+ for non-Vercel hosting
await handleUpload({
  body,
  request,
  onBeforeGenerateToken: async (pathname) => {
    return {
      callbackUrl: 'https://example.com', // Required for non-Vercel hosting
    };
  },
  onUploadCompleted: async ({ blob, tokenPayload }) => {
    // Now fires correctly
  },
});

// For local development with ngrok:
// VERCEL_BLOB_CALLBACK_URL=https://abc123.ngrok-free.app

Issue #13: ReadableStream Upload Not Supported in Firefox

Error: Upload never completes in Firefox Source: GitHub Issue #881 Why It Happens: The TypeScript interface accepts ReadableStream as a body type, but Firefox does not support ReadableStream as a fetch body. Prevention: Convert stream to Blob or ArrayBuffer for cross-browser support.

// ❌ Works in Chrome/Edge, hangs in Firefox
const stream = new ReadableStream({ /* ... */ });
await put('file.bin', stream, { access: 'public' }); // Never completes in Firefox

// ✅ Convert stream to Blob for cross-browser support
const chunks: Uint8Array[] = [];
const reader = stream.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  chunks.push(value);
}
const blob = new Blob(chunks);
await put('file.bin', blob, { access: 'public' });

Issue #14: Pathname Cannot Be Modified in onBeforeGenerateToken

Error: File uploaded to wrong path despite server-side pathname override attempt Source: GitHub Issue #863 Why It Happens: The pathname parameter in onBeforeGenerateToken cannot be changed. It's set at upload(pathname,...) time on the client side. Prevention: Construct pathname on client, validate on server. Use clientPayload to pass metadata.

// Client: Construct pathname before upload
await upload(`uploads/${Date.now()}-${file.name}`, file, {
  access: 'public',
  handleUploadUrl: '/api/upload',
  clientPayload: JSON.stringify({ userId: '123' }),
});

// Server: Validate pathname matches expected pattern
await handleUpload({
  body,
  request,
  onBeforeGenerateToken: async (pathname, clientPayload) => {
    const { userId } = JSON.parse(clientPayload || '{}');

    // Validate pathname starts with expected prefix
    if (!pathname.startsWith(`uploads/`)) {
      throw new Error('Invalid upload path');
    }

    return {
      allowedContentTypes: ['image/jpeg', 'image/png'],
      tokenPayload: JSON.stringify({ userId }), // Pass to onUploadCompleted
    };
  },
});

Issue #15: Multipart Upload Minimum Chunk Size (5MB)

Error: Manual multipart upload fails with small chunks Source: Official Docs + Community Discussion Why It Happens: Each part in manual multipart upload must be at least 5MB (except the last part). This conflicts with Vercel's 4.5MB serverless function limit, making manual multipart uploads impossible via server-side routes. Prevention: Use automatic multipart (multipart: true in put()) or client uploads.

// ❌ Manual multipart upload fails (can't upload 5MB chunks via serverless function)
const upload = await createMultipartUpload('large.mp4', { access: 'public' });
// uploadPart() requires 5MB minimum - hits serverless limit

// ✅ Use automatic multipart via client upload
await upload('large.mp4', file, {
  access: 'public',
  handleUploadUrl: '/api/upload',
  multipart: true, // Automatically handles 5MB+ chunks
});

Issue #16: Missing File Extension Causes Access Denied Error

Error: Error: Access denied, please provide a valid token for this resource Source: GitHub Issue #664 Why It Happens: Pathname without file extension causes non-descriptive access denied error. Prevention: Always include file extension in pathname.

// ❌ Fails with confusing error
await upload('user-12345', file, {
  access: 'public',
  handleUploadUrl: '/api/upload',
}); // Error: Access denied

// ✅ Extract extension and include in pathname
const extension = file.name.split('.').pop();
await upload(`user-${userId}.${extension}`, file, {
  access: 'public',
  handleUploadUrl: '/api/upload',
});

Common Patterns

Avatar Upload with Replacement:

'use server';
import { put, del } from '@vercel/blob';

export async function updateAvatar(userId: string, formData: FormData) {
  const file = formData.get('avatar') as File;
  if (!file.type.startsWith('image/')) throw new Error('Only images allowed');

  const user = await db.query.users.findFirst({ where: eq(users.id, userId) });
  if (user?.avatarUrl) await del(user.avatarUrl); // Delete old

  const blob = await put(`avatars/${userId}.jpg`, file, { access: 'public' });
  await db.update(users).set({ avatarUrl: blob.url }).where(eq(users.id, userId));
  return blob.url;
}

Protected Upload (access: 'private'):

const blob = await put(`documents/${userId}/${file.name}`, file, { access: 'private' });

平台分布

Claude Code

29.01%
按下载量换算813

Gemini CLI

21.53%
按下载量换算604

Antigravity

17.71%
按下载量换算497

Cursor

11.26%
按下载量换算316

OpenCode

7.49%
按下载量换算210

Codex

3.31%
按下载量换算93

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills