pb-sdk
JavaScript SDK usage for PocketBase client applications. Use when calling PocketBase from frontend or Node.js, authenticating users, subscribing to realtime events, uploading files, or working with the PocketBase JS/TS SDK. Covers CRUD, auth flows, authStore, realtime SSE, file handling, batch operations, and query syntax.
- License 许可
- MIT
- 最近更新
- 2026-11-11
- Stars
- ★ 3.3w
- Forks
- 3.9k
01 前言 Front Matter
- name
- pb-sdk
- description
- JavaScript SDK usage for PocketBase client applications. Use when calling PocketBase from frontend or Node.js, authenticating users, subscribing to realtime events, uploading files, or working with the PocketBase JS/TS SDK. Covers CRUD, auth flows, authStore, realtime SSE, file handling, batch operations, and query syntax.
03 SKILL.md 正文
PocketBase JavaScript SDK
Installation & Setup
npm install pocketbase
# or
yarn add pocketbase
# or
<script src="https://cdn.jsdelivr.net/npm/pocketbase@0.36.6/dist/pocketbase.umd.js"></script>
import PocketBase from 'pocketbase'
const pb = new PocketBase('http://127.0.0.1:8090')
CRUD Operations
List records
const records = await pb.collection('posts').getList(1, 20, {
filter: 'status = "active" && created > "2024-01-01"',
sort: '-created,title',
expand: 'author,tags',
fields: 'id,title,author,created', // partial response
skipTotal: true, // skip COUNT query for better performance
})
// records.page, records.perPage, records.totalItems, records.totalPages, records.items
Get full list (auto-paginate)
const allRecords = await pb.collection('posts').getFullList({
filter: 'status = "active"',
sort: '-created',
batch: 200, // records per request (default: 200)
})
View single record
const record = await pb.collection('posts').getOne('RECORD_ID', {
expand: 'author',
})
Get first matching record
const record = await pb.collection('posts').getFirstListItem('slug = "my-post"', {
expand: 'author',
})
Create record
const record = await pb.collection('posts').create({
title: 'My Post',
body: 'Content here',
author: 'USER_ID',
status: 'draft',
})
Update record
const record = await pb.collection('posts').update('RECORD_ID', {
title: 'Updated Title',
status: 'published',
})
Delete record
await pb.collection('posts').delete('RECORD_ID')
Query Parameters
Filter syntax
Same as API rules filter syntax. Common patterns:
// Equality
filter: 'status = "active"'
// Contains (LIKE)
filter: 'title ~ "hello"'
// Multi-relation contains
filter: 'tags ?= "TAG_ID"'
// Date comparison
filter: 'created > "2024-01-01 00:00:00"'
// Relative dates
filter: 'created > @now - 7d'
// Logical operators
filter: 'status = "active" && author = "USER_ID"'
filter: '(type = "a" || type = "b") && active = true'
// Null check
filter: 'parent = null'
filter: 'parent != null'
Sort syntax
sort: '-created' // descending by created
sort: 'title' // ascending by title
sort: '-created,title' // multi-field sort
sort: '@random' // random order
Expand relations
expand: 'author' // single relation
expand: 'author,tags' // multiple relations
expand: 'author.team' // nested expand (author's team)
expand: 'comments_via_post' // back-relation (comments that reference this post)
expand: 'comments_via_post.author' // nested back-relation expand
Fields (partial response)
fields: 'id,title,created'
fields: 'id,expand.author.name' // include expanded field
fields: '*,expand.author.name' // all fields + specific expand
Authentication
Email/password
const authData = await pb.collection('users').authWithPassword('user@example.com', 'password123')
// authData.token, authData.record
OAuth2 (all-in-one)
// Opens popup/redirect for OAuth2 provider
const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' })
// or with redirect
const authData = await pb.collection('users').authWithOAuth2({
provider: 'google',
urlCallback: (url) => { window.location.href = url }
})
OTP (one-time password)
// Step 1: Request OTP
const result = await pb.collection('users').requestOTP('user@example.com')
// result.otpId
// Step 2: Verify OTP
const authData = await pb.collection('users').authWithOTP(result.otpId, '123456')
MFA (multi-factor authentication)
MFA is triggered automatically when enabled. After primary auth returns a mfaId:
try {
await pb.collection('users').authWithPassword('user@example.com', 'password')
} catch (err) {
if (err.response?.mfaId) {
// Need second factor — e.g., OTP
const otpResult = await pb.collection('users').requestOTP('user@example.com')
await pb.collection('users').authWithOTP(otpResult.otpId, '123456', {
mfaId: err.response.mfaId
})
}
}
Auth store
pb.authStore.token // current JWT token
pb.authStore.record // current auth record
pb.authStore.isValid // token not expired
pb.authStore.isAdmin // deprecated — check record.collectionName === '_superusers'
pb.authStore.isSuperuser // check if superuser
// Listen for auth changes
pb.authStore.onChange((token, record) => {
console.log('Auth changed:', record?.id)
})
// Clear auth
pb.authStore.clear()
// Refresh auth (get fresh token + record)
await pb.collection('users').authRefresh()
Password reset
// Request reset email
await pb.collection('users').requestPasswordReset('user@example.com')
// Confirm reset (usually from email link)
await pb.collection('users').confirmPasswordReset(token, newPassword, newPasswordConfirm)
Email verification
await pb.collection('users').requestVerification('user@example.com')
await pb.collection('users').confirmVerification(token)
Email change
await pb.collection('users').requestEmailChange('new@example.com')
await pb.collection('users').confirmEmailChange(token, password)
Realtime (SSE)
Subscribe to record changes
// Subscribe to all changes in a collection
pb.collection('posts').subscribe('*', function(e) {
// e.action: 'create' | 'update' | 'delete'
// e.record: the affected record
console.log(e.action, e.record.id)
}, {
expand: 'author', // expand relations in realtime events
filter: 'status = "active"', // only receive matching records
})
// Subscribe to a specific record
pb.collection('posts').subscribe('RECORD_ID', function(e) {
console.log('Record changed:', e.record)
})
// Unsubscribe
pb.collection('posts').unsubscribe('*') // from specific topic
pb.collection('posts').unsubscribe('RECORD_ID')
pb.collection('posts').unsubscribe() // from all collection topics
pb.realtime.unsubscribe() // from everything
Connection management
// The SDK auto-reconnects on disconnect
// You can listen for connect/disconnect:
pb.realtime.onConnect = function() {
console.log('Connected')
}
pb.realtime.onDisconnect = function() {
console.log('Disconnected')
}
File Upload & Download
Upload files
// Via FormData (browser)
const formData = new FormData()
formData.append('title', 'My Post')
formData.append('document', fileInput.files[0])
formData.append('images', fileInput1.files[0]) // multi-file
formData.append('images', fileInput2.files[0])
const record = await pb.collection('posts').create(formData)
// Via object (Node.js or when you have the file as a Blob/File)
const record = await pb.collection('posts').create({
title: 'My Post',
document: new File([blob], 'file.pdf'),
})
Delete a file
// Set field to empty to delete
await pb.collection('posts').update('RECORD_ID', {
document: null, // deletes the file
})
// For multi-file: remove specific file
await pb.collection('posts').update('RECORD_ID', {
'images-': ['filename_to_remove.jpg'], // minus suffix removes
})
Get file URL
const url = pb.files.getURL(record, record.document)
// https://example.com/api/files/COLLECTION_ID/RECORD_ID/filename.pdf
// With thumbnail (for image fields)
const thumb = pb.files.getURL(record, record.cover, { thumb: '100x100' })
// Supported: WxH, WxHt (top), WxHb (bottom), WxHf (fit), 0xH, Wx0
Protected files
For files in collections with view rules, include the auth token:
const url = pb.files.getURL(record, record.document, { token: pb.authStore.token })
Batch Operations
Send multiple create/update/delete in one request (transactional):
const batch = pb.createBatch()
batch.collection('posts').create({ title: 'Post 1' })
batch.collection('posts').create({ title: 'Post 2' })
batch.collection('posts').update('RECORD_ID', { title: 'Updated' })
batch.collection('comments').delete('COMMENT_ID')
const results = await batch.send()
// results[0], results[1], ... correspond to each operation
Error Handling
try {
const record = await pb.collection('posts').create(data)
} catch (err) {
// err.status — HTTP status code
// err.response — full error response
// err.response.message — error message
// err.response.data — field-level validation errors
// e.g., { title: { code: "validation_required", message: "Missing required value." } }
// err.isAbort — true if request was cancelled
if (err.status === 400) {
// Validation error
for (const [field, error] of Object.entries(err.response.data)) {
console.log(`${field}: ${error.message}`)
}
}
}
Advanced
Auto-cancellation
By default, duplicate pending requests to the same endpoint are auto-cancelled. Disable per-request:
await pb.collection('posts').getList(1, 20, {
requestKey: null, // disable auto-cancel for this request
})
// Or use a custom key to group cancellations
await pb.collection('posts').getList(1, 20, {
requestKey: 'my-custom-key',
})
Custom headers
// Per-request
await pb.collection('posts').getList(1, 20, {
headers: { 'X-Custom': 'value' }
})
// Global (all requests)
pb.beforeSend = function(url, options) {
options.headers['X-Custom'] = 'value'
return { url, options }
}
// Intercept response
pb.afterSend = function(response, data) {
// modify data if needed
return data
}
SSR / Server-side
// Load auth from cookie (e.g., in Next.js/SvelteKit)
pb.authStore.loadFromCookie(request.headers.get('cookie') || '')
// Export auth to cookie
const cookie = pb.authStore.exportToCookie({ httpOnly: false })
response.headers.set('set-cookie', cookie)
Sending as superuser
const pb = new PocketBase('http://127.0.0.1:8090')
await pb.collection('_superusers').authWithPassword('admin@example.com', 'password')
// Now all requests are authenticated as superuser
04 同仓库更多 Skills
wealthville-pool-scoring
Score DeFi liquidity pools before providing liquidity. Returns a 0-100 pool score and an Enter/Hold/Exit/Reduce/Avoid verdict with calibrated confidence for ~68,800 Solana pools and 575 EVM pools, plus a public miss-inclusive track record. Use when asked whether a pool is worth LPing into, which pools look best right now, or how accurate the scores have actually been.
technical-debt-auditor
Scans a codebase and produces a quantified technical debt report with a prioritized remediation plan. Analyzes dead code, TODO/FIXME/HACK markers, dependency staleness, complexity hotspots, code duplication signals, test coverage gaps, unused exports, and outdated patterns. Use this skill when the user asks to audit their codebase for tech debt, wants a health check of their code quality, says things like "where should I focus refactoring", "find code smells", "audit my codebase", "what technical debt do we have", "prioritize cleanup work", or asks about code quality metrics. Also trigger when the user mentions "code rot", "legacy cleanup", "refactoring priorities", or wants to understand the overall health of a project before a major effort. Trigger even if the user doesn't say "technical debt" explicitly — any request to systematically assess code quality and identify improvement priorities belongs here.
readonly-sql-guard
Make an agent's database access provably read-only. Use when an agent runs caller-supplied SQL against a production/ERP/analytics database (a "query" MCP tool, text-to-SQL, an admin console), or when reviewing DB-access code for write/DDL/side-effect/transaction-escape risks. Checks what a statement CALLS, not just its shape.
web-artifacts-builder
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
webapp-testing
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
discernment-nudge
After you give a substantive answer or draft that the user may act on — advice or recommendations, drafted artifacts such as goals, plans, pitches, proposals, or emails, estimates or projections, analysis or interpretation of data, factual claims they may rely on, or a multi-step argument — invoke this skill BEFORE finalizing your reply and then, if it applies, append 2-3 short follow-up questions, each tied to something specific in what you just produced, that help the user check key facts, probe the reasoning or assumptions, and notice missing context. Do this at most once per conversation. Skip it when the user asked a trivial how-to or simple lookup, wants a purely educational explanation, asked you only to format, convert, or assemble a file from content they provided, is writing code they will run, is doing creative writing or casual chat, or already asked you to double-check, cite, or review — the skill file explains these boundaries and the exact output format.