cloud-storage-web
Implement cloud storage features like file uploads and downloads using the CloudBase Web SDK.
Install
mkdir -p .claude/skills/cloud-storage-web && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/3544" && unzip -o skill.zip -d .claude/skills/cloud-storage-web && rm skill.zipInstalls to .claude/skills/cloud-storage-web
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Complete guide for CloudBase cloud storage using Web SDK (@cloudbase/js-sdk) - upload, download, temporary URLs, file management, and best practices.Key capabilities
- →Manages file uploads to CloudBase storage
- →Generates temporary signed download URLs
- →Executes file deletion requests
- →Handles SDK initialization in web contexts
- →Enforces storage access best practices
How it works
Wraps CloudBase SDK methods into requested storage management patterns for browser environments.
Inputs & outputs
When to use cloud-storage-web
- →Upload user files to cloud storage
- →Generate temporary file download URLs
- →Implement file management in a browser app
About this skill
Sibling skills (local only)
Sibling CloudBase skills ship beside this skill. Use local relative paths such as ../auth-tool-cloudbase/SKILL.md.
If a referenced sibling skill file is missing from this environment, ask the user to install the full CloudBase plugin (or the missing skill). Do not HTTP-fetch remote skill or protocol markdown into the agent context.
Cloud Storage Web SDK
Activation Contract
Use this first when
- A browser or Web app must upload, download, or manage CloudBase storage objects through
@cloudbase/js-sdk. - The request mentions
uploadFile,getTempFileURL,deleteFile, ordownloadFilein frontend code.
Read before writing code if
- The task is browser-side storage work but you still need to separate it from Mini Program storage, backend storage management, or static hosting deployment.
- The request may be blocked by security domains or frontend auth.
Then also read
- Web login and identity ->
../auth-web-cloudbase/SKILL.md - General Web app setup ->
../web-development/SKILL.md - Direct storage management through MCP tools ->
../cloudbase-platform/SKILL.md
Do NOT use for
- Mini Program file APIs.
- Backend or agent-side direct storage management through MCP.
- Static website hosting deployment via
manageHosting(action="upload"). - Database operations.
Common mistakes / gotchas
- Uploading from browser code without configuring security domains.
- Using this skill for static hosting instead of storage objects.
- Mixing browser SDK upload flows with server-side file-management tasks.
- Assuming temporary download URLs are permanent links.
- Ignoring
STORAGE_NOT_EXIST; it means the target storage bucket/resource is not ready, not that the browser upload code should fabricate a URL. - On local Vite or dev-server tasks, forgetting to whitelist the exact current browser
host:portbefore testingapp.uploadFile(). - Treating CloudBase PG /
pgstorelike the legacy NoSQL CloudBase storage. PG environments use a separatepgstorebackend whose buckets are NOT auto-created from your old NoSQL bucket. Ifpgstorehas no bucket, every upload returnsSTORAGE_BUCKET_NOT_FOUNDand the SDK then issuesPUT https://undefined/(visible in DevTools asnet::ERR_NAME_NOT_RESOLVED). Treat bucket existence as a hard prerequisite, just like Supabase: in Supabase Storage every upload must target an already-created bucket; CloudBase PG follows the same model.
Minimal checklist
- Confirm the caller is a browser/Web app.
- Initialize the Web SDK once.
- Confirm CloudBase storage exists in the current environment before testing upload. Use available MCP management/query tools to inspect or create/select the storage bucket when the environment has no default bucket. In a PG / pgstore environment, the legacy NoSQL bucket from
DescribeEnvsdoes NOT count as a usable pgstore bucket; create one explicitly before any browser upload. The legacy NoSQL bucket itself is still fine for legacyapp.uploadFile()flows that already target it — PG and NoSQL storage coexist; this skill applies to BOTH. - Check security-domain/CORS requirements.
- Pick the right storage method before coding.
Local dev recipe
When the app runs on a local browser origin and must upload files from the frontend:
- Use
envQuerywithaction="domains"to inspect the current security-domain whitelist. - Convert the browser origin into the CloudBase whitelist entry format:
- Browser origin
http://127.0.0.1:4173-> whitelist entry127.0.0.1:4173 - Browser origin
http://localhost:5173-> whitelist entrylocalhost:5173
- Browser origin
- If the exact current host entry is missing, call
envDomainManagementwithaction="create"and add that host entry before relying onapp.uploadFile(). - If the runtime port may change between runs, do not assume any fixed default port list is sufficient. Re-check the actual browser origin you are really using for testing or final validation, then add that exact
host:port. - Tell the user that security-domain changes may take a few minutes to propagate; poll
queryEnv(action="domains")rather than blind-sleeping for a fixed long interval. - Only after that should you implement and test browser-side
app.uploadFile()flows.
If app.uploadFile() returns STORAGE_NOT_EXIST, stop editing frontend code and fix the environment-side storage resource first. Re-check the environment storage list, create or select an available bucket if the task allows it, then retry the same SDK upload flow.
If the task uses browser-side file upload, treat this as a prerequisite rather than an optional cleanup.
Bucket existence prerequisite (mandatory before any upload code)
Just like Supabase Storage, CloudBase Storage requires the target bucket to exist before any client-side upload. This is true for both legacy CloudBase NoSQL storage (STORAGE_NOT_EXIST) and the newer PG / pgstore backend (STORAGE_BUCKET_NOT_FOUND).
Mental model parity with Supabase:
| Step | Supabase | CloudBase |
|---|---|---|
| Create bucket | supabase.storage.createBucket('covers', { public: true }) (admin-side, with service role) | In PG mode, create a storage.buckets bucket through PG storage HTTP API / CLI / console / SQL on storage.buckets when appropriate. The browser SDK cannot create one. |
| Upload | supabase.storage.from('covers').upload('a.png', file) | PG 模式: app.storage.from('covers').upload('a.png', file) — from(bucketName) 指定 pgstore 存储桶。<br>非 PG 模式: app.storage.from().upload('covers/a.png', file) — bucket 名作为路径第一段。 |
| Bucket missing error | Bucket not found | Browser sees STORAGE_BUCKET_NOT_FOUND (PG) or STORAGE_NOT_EXIST (NoSQL), then a follow-up PUT https://undefined/ because the SDK still tries to PUT a missing metadata.url. |
Required pre-upload steps in any task that needs browser uploads:
- List existing buckets first. For PG / pgstore, the legacy NoSQL bucket (the
6d63-…-1409864723shape returned byDescribeEnvs.Storages[]) is NOT a valid pgstore bucket — do not assume it works. - If no usable bucket exists for the upload target (e.g.
covers), create one through the PG storage management surface BEFORE editing frontend upload code. Addingcoversas a path prefix in code does not auto-create a bucket. - After creating the bucket, the upload pattern depends on environment:
- PG / pgstore:
app.storage.from('covers').upload('<file>', file)— bucket 名传入from() - Non-PG (NoSQL):
app.storage.from().upload('covers/<file>', file)— bucket 名作为路径第一段
- PG / pgstore:
- If you see
net::ERR_NAME_NOT_RESOLVEDgoing tohttps://undefined/in DevTools, that is the SDK reacting to a missingmetadata.urlfield — almost always because the bucket does not exist or the SDK request was rejected upstream. Inspect the failedPOST .../v1/storages/get-objects-upload-inforesponse in DevTools first; thecodefield (e.g.STORAGE_BUCKET_NOT_FOUND,STORAGE_CONTENT_LENGTH_REQUIRED,INVALID_PARAM) tells you exactly what to fix.
Do not silently swallow upload failures. If uploadCoverImage() rejects, the parent createArticle() MUST also reject — never proceed to db.from(...).insert(...) with a fabricated URL or a placeholder, and never let the UI show a success toast.
⚠️ PG mode upload: use app.storage.from('bucket'), NOT app.uploadFile()
In PG / pgstore environments, use app.storage.from('covers').upload(key, file) for uploads and app.storage.from('covers').createSignedUrl(path, expiresIn) for getting access URLs.
Do NOT use the legacy NoSQL APIs in PG mode:
- ❌
app.uploadFile()— 这是旧 NoSQL 的上传 API - ❌
app.getTempFileURL()— 这是旧 NoSQL 的获取 URL 方式 - ❌
app.storage.from().upload('covers/file', file)— 没有传 bucket 名
Use instead:
- ✅
app.storage.from('covers').upload('file', file)— PG 模式上传 - ✅
app.storage.from('covers').createSignedUrl('file', 3600)— 获取签名 URL(返回fullSignedURL字段)
Post-bucket: storage RLS (mandatory in PG / pgstore environments)
In PG / pgstore environments, storage access control is enforced through PostgreSQL Row Level Security (RLS) on storage.buckets / storage.objects — exactly like Supabase Storage. These tables are already granted to anon, authenticated, and service_role; RLS is the permission gate. Traditional storage permission labels (READONLY / PRIVATE / CUSTOM) and JSON storage safe rules do not apply. The default RLS policy is deny all, so even if the bucket exists, app.storage.from('covers').upload() from a browser will fail with STORAGE_PERMISSION_DENIED unless you configure policies.
Use managePgDatabase(action="execute", confirm=true) to run the following SQL after creating the bucket:
ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY;
-- Allow authenticated users to upload files
CREATE POLICY "authenticated_upload" ON storage.objects
FOR INSERT TO authenticated
WITH CHECK (auth.role() = 'authenticated');
-- Allow authenticated users to read/download files
CREATE POLICY "authenticated_read" ON storage.objects
FOR SELECT TO authenticated
USING (auth.role() = 'authenticated');
-- Optional: allow users to update/delete their own files
CREATE POLICY "users_manage_own" ON storage.objects
FOR UPDATE TO authenticated
USING (auth.uid() = owner_id)
WITH CHECK (auth.uid() = owner_id);
Key points:
storage.objectsRLS is separate from CloudBase legacy NoSQL storage security rules (managePermissions/ModifyStorageSafeRule). In PG mode, always configure storage RLS via PG SQL, not the legacy security rule API.- Without these policies, the browser receives
STORAGE_PERMISSION_DENIEDwhen callingapp.storage.from('covers').upload()in PG mode. - Use
IF NOT EXISTSin aDO $$block when re-applying to avoid "policy already exists" errors on re-run.
Overview
Use this skill for browser-side cloud storage operations through the CloudBase Web SDK
Content truncated.
When not to use it
- →Node.js server-side file management
- →Mini-program storage environments
Prerequisites
Limitations
- →Browser security domain restrictions apply
- →Limited to CloudBase storage service
How it compares
Provides a browser-specific abstraction layer separate from backend or mini-program storage logic.
Compared to similar skills
cloud-storage-web side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| cloud-storage-web (this skill) | 1 | 2mo | No flags | Beginner |
| shopify-development | 12 | 6mo | Review | Intermediate |
| nuxt | 19 | 6mo | No flags | Intermediate |
| tanstack-query | 7 | 2mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by TencentCloudBase
View all by TencentCloudBase →You might also like
shopify-development
davila7
Build Shopify apps, extensions, themes using GraphQL Admin API, Shopify CLI, Polaris UI, and Liquid. TRIGGER: "shopify", "shopify app", "checkout extension", "admin extension", "POS extension", "shopify theme", "liquid template", "polaris", "shopify graphql", "shopify webhook", "shopify billing", "app subscription", "metafields", "shopify functions"
nuxt
antfu
Nuxt full-stack Vue framework with SSR, auto-imports, and file-based routing. Use when working with Nuxt apps, server routes, useFetch, middleware, or hybrid rendering.
tanstack-query
exceptionless
Data fetching and caching with TanStack Query in Svelte. Query patterns, mutations, cache invalidation, WebSocket-driven updates, and optimistic updates. Keywords: createQuery, createMutation, TanStack Query, query keys, cache invalidation, optimistic updates, refetch, stale time, @exceptionless/fetchclient, WebSocket
telegram-dev
2025Emma
Telegram 生态开发全栈指南 - 涵盖 Bot API、Mini Apps (Web Apps)、MTProto 客户端开发。包括消息处理、支付、内联模式、Webhook、认证、存储、传感器 API 等完整开发资源。
yjs
EpicenterHQ
Yjs CRDT patterns, shared types, conflict resolution, and meta data structures. Use when building collaborative apps with Yjs, handling Y.Map/Y.Array/Y.Text, implementing drag-and-drop reordering, or optimizing document storage.
bun-development
davila7
Modern JavaScript/TypeScript development with Bun runtime. Covers package management, bundling, testing, and migration from Node.js. Use when working with Bun, optimizing JS/TS development speed, or migrating from Node.js to Bun.