[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6AF57S4659WRKPFAPAY209R":3,"skill-same:01M6AF57S4659WRKPFAPAY209R":76},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":52,"commitSha":53,"skillDirectory":54,"forksCount":55,"repositoryHtmlUrl":56,"repositoryHomepageUrl":57,"ownerHtmlUrl":58,"ownerBlogUrl":59,"ownerDescription":60,"updatedAt":61,"install":62,"resources":75},"01M6AF57S4659WRKPFAPAY209R","pb-sdk",null,"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\u002FTS SDK. Covers CRUD, auth flows, authStore, realtime SSE, file handling, batch operations, and query syntax.","davila7\u002Fclaude-code-templates","davila7","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6216945?v=4","01M6ADEWWFPS191NFM0Y1EX1JH","Daniel Avila","01M6ADJHGM78PHQRD3XZTFDVKK",33332,"MIT","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fpocketbase\u002Fpb-sdk\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"sdk","pb sdk","when","frontend","for","usage","javascript sdk","flows","events","file handling","query","calling","pocketbase","files","syntax","node","crud","applications","file","batch","realtime","auth","javascript","2026-11-10 10:12:30",false,"---\nname: pb-sdk\ndescription: \"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\u002FTS SDK. Covers CRUD, auth flows, authStore, realtime SSE, file handling, batch operations, and query syntax.\"\n---\n\n# PocketBase JavaScript SDK\n\n## Installation & Setup\n\n```bash\nnpm install pocketbase\n# or\nyarn add pocketbase\n# or\n\u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fpocketbase@0.36.6\u002Fdist\u002Fpocketbase.umd.js\">\u003C\u002Fscript>\n```\n\n```js\nimport PocketBase from 'pocketbase'\n\nconst pb = new PocketBase('http:\u002F\u002F127.0.0.1:8090')\n```\n\n## CRUD Operations\n\n### List records\n\n```js\nconst records = await pb.collection('posts').getList(1, 20, {\n    filter: 'status = \"active\" && created > \"2024-01-01\"',\n    sort: '-created,title',\n    expand: 'author,tags',\n    fields: 'id,title,author,created',  \u002F\u002F partial response\n    skipTotal: true,  \u002F\u002F skip COUNT query for better performance\n})\n\n\u002F\u002F records.page, records.perPage, records.totalItems, records.totalPages, records.items\n```\n\n### Get full list (auto-paginate)\n\n```js\nconst allRecords = await pb.collection('posts').getFullList({\n    filter: 'status = \"active\"',\n    sort: '-created',\n    batch: 200,  \u002F\u002F records per request (default: 200)\n})\n```\n\n### View single record\n\n```js\nconst record = await pb.collection('posts').getOne('RECORD_ID', {\n    expand: 'author',\n})\n```\n\n### Get first matching record\n\n```js\nconst record = await pb.collection('posts').getFirstListItem('slug = \"my-post\"', {\n    expand: 'author',\n})\n```\n\n### Create record\n\n```js\nconst record = await pb.collection('posts').create({\n    title: 'My Post',\n    body: 'Content here',\n    author: 'USER_ID',\n    status: 'draft',\n})\n```\n\n### Update record\n\n```js\nconst record = await pb.collection('posts').update('RECORD_ID', {\n    title: 'Updated Title',\n    status: 'published',\n})\n```\n\n### Delete record\n\n```js\nawait pb.collection('posts').delete('RECORD_ID')\n```\n\n## Query Parameters\n\n### Filter syntax\n\nSame as API rules filter syntax. Common patterns:\n\n```js\n\u002F\u002F Equality\nfilter: 'status = \"active\"'\n\n\u002F\u002F Contains (LIKE)\nfilter: 'title ~ \"hello\"'\n\n\u002F\u002F Multi-relation contains\nfilter: 'tags ?= \"TAG_ID\"'\n\n\u002F\u002F Date comparison\nfilter: 'created > \"2024-01-01 00:00:00\"'\n\n\u002F\u002F Relative dates\nfilter: 'created > @now - 7d'\n\n\u002F\u002F Logical operators\nfilter: 'status = \"active\" && author = \"USER_ID\"'\nfilter: '(type = \"a\" || type = \"b\") && active = true'\n\n\u002F\u002F Null check\nfilter: 'parent = null'\nfilter: 'parent != null'\n```\n\n### Sort syntax\n\n```js\nsort: '-created'          \u002F\u002F descending by created\nsort: 'title'             \u002F\u002F ascending by title\nsort: '-created,title'    \u002F\u002F multi-field sort\nsort: '@random'           \u002F\u002F random order\n```\n\n### Expand relations\n\n```js\nexpand: 'author'                    \u002F\u002F single relation\nexpand: 'author,tags'               \u002F\u002F multiple relations\nexpand: 'author.team'               \u002F\u002F nested expand (author's team)\nexpand: 'comments_via_post'         \u002F\u002F back-relation (comments that reference this post)\nexpand: 'comments_via_post.author'  \u002F\u002F nested back-relation expand\n```\n\n### Fields (partial response)\n\n```js\nfields: 'id,title,created'\nfields: 'id,expand.author.name'     \u002F\u002F include expanded field\nfields: '*,expand.author.name'      \u002F\u002F all fields + specific expand\n```\n\n## Authentication\n\n### Email\u002Fpassword\n\n```js\nconst authData = await pb.collection('users').authWithPassword('user@example.com', 'password123')\n\u002F\u002F authData.token, authData.record\n```\n\n### OAuth2 (all-in-one)\n\n```js\n\u002F\u002F Opens popup\u002Fredirect for OAuth2 provider\nconst authData = await pb.collection('users').authWithOAuth2({ provider: 'google' })\n\u002F\u002F or with redirect\nconst authData = await pb.collection('users').authWithOAuth2({\n    provider: 'google',\n    urlCallback: (url) => { window.location.href = url }\n})\n```\n\n### OTP (one-time password)\n\n```js\n\u002F\u002F Step 1: Request OTP\nconst result = await pb.collection('users').requestOTP('user@example.com')\n\u002F\u002F result.otpId\n\n\u002F\u002F Step 2: Verify OTP\nconst authData = await pb.collection('users').authWithOTP(result.otpId, '123456')\n```\n\n### MFA (multi-factor authentication)\n\nMFA is triggered automatically when enabled. After primary auth returns a `mfaId`:\n\n```js\ntry {\n    await pb.collection('users').authWithPassword('user@example.com', 'password')\n} catch (err) {\n    if (err.response?.mfaId) {\n        \u002F\u002F Need second factor — e.g., OTP\n        const otpResult = await pb.collection('users').requestOTP('user@example.com')\n        await pb.collection('users').authWithOTP(otpResult.otpId, '123456', {\n            mfaId: err.response.mfaId\n        })\n    }\n}\n```\n\n### Auth store\n\n```js\npb.authStore.token       \u002F\u002F current JWT token\npb.authStore.record      \u002F\u002F current auth record\npb.authStore.isValid     \u002F\u002F token not expired\npb.authStore.isAdmin     \u002F\u002F deprecated — check record.collectionName === '_superusers'\npb.authStore.isSuperuser \u002F\u002F check if superuser\n\n\u002F\u002F Listen for auth changes\npb.authStore.onChange((token, record) => {\n    console.log('Auth changed:', record?.id)\n})\n\n\u002F\u002F Clear auth\npb.authStore.clear()\n\n\u002F\u002F Refresh auth (get fresh token + record)\nawait pb.collection('users').authRefresh()\n```\n\n### Password reset\n\n```js\n\u002F\u002F Request reset email\nawait pb.collection('users').requestPasswordReset('user@example.com')\n\n\u002F\u002F Confirm reset (usually from email link)\nawait pb.collection('users').confirmPasswordReset(token, newPassword, newPasswordConfirm)\n```\n\n### Email verification\n\n```js\nawait pb.collection('users').requestVerification('user@example.com')\nawait pb.collection('users').confirmVerification(token)\n```\n\n### Email change\n\n```js\nawait pb.collection('users').requestEmailChange('new@example.com')\nawait pb.collection('users').confirmEmailChange(token, password)\n```\n\n## Realtime (SSE)\n\n### Subscribe to record changes\n\n```js\n\u002F\u002F Subscribe to all changes in a collection\npb.collection('posts').subscribe('*', function(e) {\n    \u002F\u002F e.action: 'create' | 'update' | 'delete'\n    \u002F\u002F e.record: the affected record\n    console.log(e.action, e.record.id)\n}, {\n    expand: 'author',  \u002F\u002F expand relations in realtime events\n    filter: 'status = \"active\"',  \u002F\u002F only receive matching records\n})\n\n\u002F\u002F Subscribe to a specific record\npb.collection('posts').subscribe('RECORD_ID', function(e) {\n    console.log('Record changed:', e.record)\n})\n\n\u002F\u002F Unsubscribe\npb.collection('posts').unsubscribe('*')        \u002F\u002F from specific topic\npb.collection('posts').unsubscribe('RECORD_ID')\npb.collection('posts').unsubscribe()            \u002F\u002F from all collection topics\npb.realtime.unsubscribe()                       \u002F\u002F from everything\n```\n\n### Connection management\n\n```js\n\u002F\u002F The SDK auto-reconnects on disconnect\n\u002F\u002F You can listen for connect\u002Fdisconnect:\npb.realtime.onConnect = function() {\n    console.log('Connected')\n}\npb.realtime.onDisconnect = function() {\n    console.log('Disconnected')\n}\n```\n\n## File Upload & Download\n\n### Upload files\n\n```js\n\u002F\u002F Via FormData (browser)\nconst formData = new FormData()\nformData.append('title', 'My Post')\nformData.append('document', fileInput.files[0])\nformData.append('images', fileInput1.files[0])  \u002F\u002F multi-file\nformData.append('images', fileInput2.files[0])\n\nconst record = await pb.collection('posts').create(formData)\n\n\u002F\u002F Via object (Node.js or when you have the file as a Blob\u002FFile)\nconst record = await pb.collection('posts').create({\n    title: 'My Post',\n    document: new File([blob], 'file.pdf'),\n})\n```\n\n### Delete a file\n\n```js\n\u002F\u002F Set field to empty to delete\nawait pb.collection('posts').update('RECORD_ID', {\n    document: null,  \u002F\u002F deletes the file\n})\n\n\u002F\u002F For multi-file: remove specific file\nawait pb.collection('posts').update('RECORD_ID', {\n    'images-': ['filename_to_remove.jpg'],  \u002F\u002F minus suffix removes\n})\n```\n\n### Get file URL\n\n```js\nconst url = pb.files.getURL(record, record.document)\n\u002F\u002F https:\u002F\u002Fexample.com\u002Fapi\u002Ffiles\u002FCOLLECTION_ID\u002FRECORD_ID\u002Ffilename.pdf\n\n\u002F\u002F With thumbnail (for image fields)\nconst thumb = pb.files.getURL(record, record.cover, { thumb: '100x100' })\n\u002F\u002F Supported: WxH, WxHt (top), WxHb (bottom), WxHf (fit), 0xH, Wx0\n```\n\n### Protected files\n\nFor files in collections with view rules, include the auth token:\n\n```js\nconst url = pb.files.getURL(record, record.document, { token: pb.authStore.token })\n```\n\n## Batch Operations\n\nSend multiple create\u002Fupdate\u002Fdelete in one request (transactional):\n\n```js\nconst batch = pb.createBatch()\n\nbatch.collection('posts').create({ title: 'Post 1' })\nbatch.collection('posts').create({ title: 'Post 2' })\nbatch.collection('posts').update('RECORD_ID', { title: 'Updated' })\nbatch.collection('comments').delete('COMMENT_ID')\n\nconst results = await batch.send()\n\u002F\u002F results[0], results[1], ... correspond to each operation\n```\n\n## Error Handling\n\n```js\ntry {\n    const record = await pb.collection('posts').create(data)\n} catch (err) {\n    \u002F\u002F err.status — HTTP status code\n    \u002F\u002F err.response — full error response\n    \u002F\u002F err.response.message — error message\n    \u002F\u002F err.response.data — field-level validation errors\n    \u002F\u002F   e.g., { title: { code: \"validation_required\", message: \"Missing required value.\" } }\n    \u002F\u002F err.isAbort — true if request was cancelled\n\n    if (err.status === 400) {\n        \u002F\u002F Validation error\n        for (const [field, error] of Object.entries(err.response.data)) {\n            console.log(`${field}: ${error.message}`)\n        }\n    }\n}\n```\n\n## Advanced\n\n### Auto-cancellation\n\nBy default, duplicate pending requests to the same endpoint are auto-cancelled. Disable per-request:\n\n```js\nawait pb.collection('posts').getList(1, 20, {\n    requestKey: null,  \u002F\u002F disable auto-cancel for this request\n})\n\n\u002F\u002F Or use a custom key to group cancellations\nawait pb.collection('posts').getList(1, 20, {\n    requestKey: 'my-custom-key',\n})\n```\n\n### Custom headers\n\n```js\n\u002F\u002F Per-request\nawait pb.collection('posts').getList(1, 20, {\n    headers: { 'X-Custom': 'value' }\n})\n\n\u002F\u002F Global (all requests)\npb.beforeSend = function(url, options) {\n    options.headers['X-Custom'] = 'value'\n    return { url, options }\n}\n\n\u002F\u002F Intercept response\npb.afterSend = function(response, data) {\n    \u002F\u002F modify data if needed\n    return data\n}\n```\n\n### SSR \u002F Server-side\n\n```js\n\u002F\u002F Load auth from cookie (e.g., in Next.js\u002FSvelteKit)\npb.authStore.loadFromCookie(request.headers.get('cookie') || '')\n\n\u002F\u002F Export auth to cookie\nconst cookie = pb.authStore.exportToCookie({ httpOnly: false })\nresponse.headers.set('set-cookie', cookie)\n```\n\n### Sending as superuser\n\n```js\nconst pb = new PocketBase('http:\u002F\u002F127.0.0.1:8090')\nawait pb.collection('_superusers').authWithPassword('admin@example.com', 'password')\n\u002F\u002F Now all requests are authenticated as superuser\n```\n","# PocketBase JavaScript SDK\n\n## Installation & Setup\n\n```bash\nnpm install pocketbase\n# or\nyarn add pocketbase\n# or\n\u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fpocketbase@0.36.6\u002Fdist\u002Fpocketbase.umd.js\">\u003C\u002Fscript>\n```\n\n```js\nimport PocketBase from 'pocketbase'\n\nconst pb = new PocketBase('http:\u002F\u002F127.0.0.1:8090')\n```\n\n## CRUD Operations\n\n### List records\n\n```js\nconst records = await pb.collection('posts').getList(1, 20, {\n    filter: 'status = \"active\" && created > \"2024-01-01\"',\n    sort: '-created,title',\n    expand: 'author,tags',\n    fields: 'id,title,author,created',  \u002F\u002F partial response\n    skipTotal: true,  \u002F\u002F skip COUNT query for better performance\n})\n\n\u002F\u002F records.page, records.perPage, records.totalItems, records.totalPages, records.items\n```\n\n### Get full list (auto-paginate)\n\n```js\nconst allRecords = await pb.collection('posts').getFullList({\n    filter: 'status = \"active\"',\n    sort: '-created',\n    batch: 200,  \u002F\u002F records per request (default: 200)\n})\n```\n\n### View single record\n\n```js\nconst record = await pb.collection('posts').getOne('RECORD_ID', {\n    expand: 'author',\n})\n```\n\n### Get first matching record\n\n```js\nconst record = await pb.collection('posts').getFirstListItem('slug = \"my-post\"', {\n    expand: 'author',\n})\n```\n\n### Create record\n\n```js\nconst record = await pb.collection('posts').create({\n    title: 'My Post',\n    body: 'Content here',\n    author: 'USER_ID',\n    status: 'draft',\n})\n```\n\n### Update record\n\n```js\nconst record = await pb.collection('posts').update('RECORD_ID', {\n    title: 'Updated Title',\n    status: 'published',\n})\n```\n\n### Delete record\n\n```js\nawait pb.collection('posts').delete('RECORD_ID')\n```\n\n## Query Parameters\n\n### Filter syntax\n\nSame as API rules filter syntax. Common patterns:\n\n```js\n\u002F\u002F Equality\nfilter: 'status = \"active\"'\n\n\u002F\u002F Contains (LIKE)\nfilter: 'title ~ \"hello\"'\n\n\u002F\u002F Multi-relation contains\nfilter: 'tags ?= \"TAG_ID\"'\n\n\u002F\u002F Date comparison\nfilter: 'created > \"2024-01-01 00:00:00\"'\n\n\u002F\u002F Relative dates\nfilter: 'created > @now - 7d'\n\n\u002F\u002F Logical operators\nfilter: 'status = \"active\" && author = \"USER_ID\"'\nfilter: '(type = \"a\" || type = \"b\") && active = true'\n\n\u002F\u002F Null check\nfilter: 'parent = null'\nfilter: 'parent != null'\n```\n\n### Sort syntax\n\n```js\nsort: '-created'          \u002F\u002F descending by created\nsort: 'title'             \u002F\u002F ascending by title\nsort: '-created,title'    \u002F\u002F multi-field sort\nsort: '@random'           \u002F\u002F random order\n```\n\n### Expand relations\n\n```js\nexpand: 'author'                    \u002F\u002F single relation\nexpand: 'author,tags'               \u002F\u002F multiple relations\nexpand: 'author.team'               \u002F\u002F nested expand (author's team)\nexpand: 'comments_via_post'         \u002F\u002F back-relation (comments that reference this post)\nexpand: 'comments_via_post.author'  \u002F\u002F nested back-relation expand\n```\n\n### Fields (partial response)\n\n```js\nfields: 'id,title,created'\nfields: 'id,expand.author.name'     \u002F\u002F include expanded field\nfields: '*,expand.author.name'      \u002F\u002F all fields + specific expand\n```\n\n## Authentication\n\n### Email\u002Fpassword\n\n```js\nconst authData = await pb.collection('users').authWithPassword('user@example.com', 'password123')\n\u002F\u002F authData.token, authData.record\n```\n\n### OAuth2 (all-in-one)\n\n```js\n\u002F\u002F Opens popup\u002Fredirect for OAuth2 provider\nconst authData = await pb.collection('users').authWithOAuth2({ provider: 'google' })\n\u002F\u002F or with redirect\nconst authData = await pb.collection('users').authWithOAuth2({\n    provider: 'google',\n    urlCallback: (url) => { window.location.href = url }\n})\n```\n\n### OTP (one-time password)\n\n```js\n\u002F\u002F Step 1: Request OTP\nconst result = await pb.collection('users').requestOTP('user@example.com')\n\u002F\u002F result.otpId\n\n\u002F\u002F Step 2: Verify OTP\nconst authData = await pb.collection('users').authWithOTP(result.otpId, '123456')\n```\n\n### MFA (multi-factor authentication)\n\nMFA is triggered automatically when enabled. After primary auth returns a `mfaId`:\n\n```js\ntry {\n    await pb.collection('users').authWithPassword('user@example.com', 'password')\n} catch (err) {\n    if (err.response?.mfaId) {\n        \u002F\u002F Need second factor — e.g., OTP\n        const otpResult = await pb.collection('users').requestOTP('user@example.com')\n        await pb.collection('users').authWithOTP(otpResult.otpId, '123456', {\n            mfaId: err.response.mfaId\n        })\n    }\n}\n```\n\n### Auth store\n\n```js\npb.authStore.token       \u002F\u002F current JWT token\npb.authStore.record      \u002F\u002F current auth record\npb.authStore.isValid     \u002F\u002F token not expired\npb.authStore.isAdmin     \u002F\u002F deprecated — check record.collectionName === '_superusers'\npb.authStore.isSuperuser \u002F\u002F check if superuser\n\n\u002F\u002F Listen for auth changes\npb.authStore.onChange((token, record) => {\n    console.log('Auth changed:', record?.id)\n})\n\n\u002F\u002F Clear auth\npb.authStore.clear()\n\n\u002F\u002F Refresh auth (get fresh token + record)\nawait pb.collection('users').authRefresh()\n```\n\n### Password reset\n\n```js\n\u002F\u002F Request reset email\nawait pb.collection('users').requestPasswordReset('user@example.com')\n\n\u002F\u002F Confirm reset (usually from email link)\nawait pb.collection('users').confirmPasswordReset(token, newPassword, newPasswordConfirm)\n```\n\n### Email verification\n\n```js\nawait pb.collection('users').requestVerification('user@example.com')\nawait pb.collection('users').confirmVerification(token)\n```\n\n### Email change\n\n```js\nawait pb.collection('users').requestEmailChange('new@example.com')\nawait pb.collection('users').confirmEmailChange(token, password)\n```\n\n## Realtime (SSE)\n\n### Subscribe to record changes\n\n```js\n\u002F\u002F Subscribe to all changes in a collection\npb.collection('posts').subscribe('*', function(e) {\n    \u002F\u002F e.action: 'create' | 'update' | 'delete'\n    \u002F\u002F e.record: the affected record\n    console.log(e.action, e.record.id)\n}, {\n    expand: 'author',  \u002F\u002F expand relations in realtime events\n    filter: 'status = \"active\"',  \u002F\u002F only receive matching records\n})\n\n\u002F\u002F Subscribe to a specific record\npb.collection('posts').subscribe('RECORD_ID', function(e) {\n    console.log('Record changed:', e.record)\n})\n\n\u002F\u002F Unsubscribe\npb.collection('posts').unsubscribe('*')        \u002F\u002F from specific topic\npb.collection('posts').unsubscribe('RECORD_ID')\npb.collection('posts').unsubscribe()            \u002F\u002F from all collection topics\npb.realtime.unsubscribe()                       \u002F\u002F from everything\n```\n\n### Connection management\n\n```js\n\u002F\u002F The SDK auto-reconnects on disconnect\n\u002F\u002F You can listen for connect\u002Fdisconnect:\npb.realtime.onConnect = function() {\n    console.log('Connected')\n}\npb.realtime.onDisconnect = function() {\n    console.log('Disconnected')\n}\n```\n\n## File Upload & Download\n\n### Upload files\n\n```js\n\u002F\u002F Via FormData (browser)\nconst formData = new FormData()\nformData.append('title', 'My Post')\nformData.append('document', fileInput.files[0])\nformData.append('images', fileInput1.files[0])  \u002F\u002F multi-file\nformData.append('images', fileInput2.files[0])\n\nconst record = await pb.collection('posts').create(formData)\n\n\u002F\u002F Via object (Node.js or when you have the file as a Blob\u002FFile)\nconst record = await pb.collection('posts').create({\n    title: 'My Post',\n    document: new File([blob], 'file.pdf'),\n})\n```\n\n### Delete a file\n\n```js\n\u002F\u002F Set field to empty to delete\nawait pb.collection('posts').update('RECORD_ID', {\n    document: null,  \u002F\u002F deletes the file\n})\n\n\u002F\u002F For multi-file: remove specific file\nawait pb.collection('posts').update('RECORD_ID', {\n    'images-': ['filename_to_remove.jpg'],  \u002F\u002F minus suffix removes\n})\n```\n\n### Get file URL\n\n```js\nconst url = pb.files.getURL(record, record.document)\n\u002F\u002F https:\u002F\u002Fexample.com\u002Fapi\u002Ffiles\u002FCOLLECTION_ID\u002FRECORD_ID\u002Ffilename.pdf\n\n\u002F\u002F With thumbnail (for image fields)\nconst thumb = pb.files.getURL(record, record.cover, { thumb: '100x100' })\n\u002F\u002F Supported: WxH, WxHt (top), WxHb (bottom), WxHf (fit), 0xH, Wx0\n```\n\n### Protected files\n\nFor files in collections with view rules, include the auth token:\n\n```js\nconst url = pb.files.getURL(record, record.document, { token: pb.authStore.token })\n```\n\n## Batch Operations\n\nSend multiple create\u002Fupdate\u002Fdelete in one request (transactional):\n\n```js\nconst batch = pb.createBatch()\n\nbatch.collection('posts').create({ title: 'Post 1' })\nbatch.collection('posts').create({ title: 'Post 2' })\nbatch.collection('posts').update('RECORD_ID', { title: 'Updated' })\nbatch.collection('comments').delete('COMMENT_ID')\n\nconst results = await batch.send()\n\u002F\u002F results[0], results[1], ... correspond to each operation\n```\n\n## Error Handling\n\n```js\ntry {\n    const record = await pb.collection('posts').create(data)\n} catch (err) {\n    \u002F\u002F err.status — HTTP status code\n    \u002F\u002F err.response — full error response\n    \u002F\u002F err.response.message — error message\n    \u002F\u002F err.response.data — field-level validation errors\n    \u002F\u002F   e.g., { title: { code: \"validation_required\", message: \"Missing required value.\" } }\n    \u002F\u002F err.isAbort — true if request was cancelled\n\n    if (err.status === 400) {\n        \u002F\u002F Validation error\n        for (const [field, error] of Object.entries(err.response.data)) {\n            console.log(`${field}: ${error.message}`)\n        }\n    }\n}\n```\n\n## Advanced\n\n### Auto-cancellation\n\nBy default, duplicate pending requests to the same endpoint are auto-cancelled. Disable per-request:\n\n```js\nawait pb.collection('posts').getList(1, 20, {\n    requestKey: null,  \u002F\u002F disable auto-cancel for this request\n})\n\n\u002F\u002F Or use a custom key to group cancellations\nawait pb.collection('posts').getList(1, 20, {\n    requestKey: 'my-custom-key',\n})\n```\n\n### Custom headers\n\n```js\n\u002F\u002F Per-request\nawait pb.collection('posts').getList(1, 20, {\n    headers: { 'X-Custom': 'value' }\n})\n\n\u002F\u002F Global (all requests)\npb.beforeSend = function(url, options) {\n    options.headers['X-Custom'] = 'value'\n    return { url, options }\n}\n\n\u002F\u002F Intercept response\npb.afterSend = function(response, data) {\n    \u002F\u002F modify data if needed\n    return data\n}\n```\n\n### SSR \u002F Server-side\n\n```js\n\u002F\u002F Load auth from cookie (e.g., in Next.js\u002FSvelteKit)\npb.authStore.loadFromCookie(request.headers.get('cookie') || '')\n\n\u002F\u002F Export auth to cookie\nconst cookie = pb.authStore.exportToCookie({ httpOnly: false })\nresponse.headers.set('set-cookie', cookie)\n```\n\n### Sending as superuser\n\n```js\nconst pb = new PocketBase('http:\u002F\u002F127.0.0.1:8090')\nawait pb.collection('_superusers').authWithPassword('admin@example.com', 'password')\n\u002F\u002F Now all requests are authenticated as superuser\n```\n",{"name":5,"description":7},"main","2b749c82b5d11fac39d9a6e021ce3f5b8a541bd1","cli-tool\u002Fcomponents\u002Fskills\u002Fpocketbase\u002Fpb-sdk",3911,"https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates","https:\u002F\u002Faitmpl.com","https:\u002F\u002Fgithub.com\u002Fdavila7","https:\u002F\u002Fdanielavila.me","Building AI dev tools with LLMs","2026-11-11 21:38:31",{"source":8,"skillName":5,"commands":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add davila7\u002Fclaude-code-templates --skill pb-sdk",{"tool":68,"command":69},"bunx","bunx skills add davila7\u002Fclaude-code-templates --skill pb-sdk",{"tool":71,"command":72},"pnpm","pnpm dlx skills add davila7\u002Fclaude-code-templates --skill pb-sdk","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fpocketbase\u002Fpb-sdk\u002FSKILL.md",true,[],[77,105,132,164,195,218],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":86,"publishedAt":47},"01M70NHBTQ8BV0A2SCAZXEPHCX","wealthville-pool-scoring","Score DeFi liquidity pools before providing liquidity. Returns a 0-100 pool score and an Enter\u002FHold\u002FExit\u002FReduce\u002FAvoid 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.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fweb-data\u002Fwealthville-pool-scoring\u002FSKILL.md",[83],{"categoryNo":84,"categoryName":85,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[87,88,89,90,91,28,92,93,94,26,95,96,97,98,99,100,101,102,103,104],"scoring","pool","wealthville pool scoring","liquidity","which","exit","now","use","reduce","with","record","track","verdict","evm","solana","how","public","look",{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":112,"publishedAt":47},"01M70MB6VR8ERJ4EM8D5KHBMEV","technical-debt-auditor","Scans a codebase and produces a quantified technical debt report with a prioritized remediation plan. Analyzes dead code, TODO\u002FFIXME\u002FHACK 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.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdevelopment\u002Ftechnical-debt-auditor\u002FSKILL.md",[111],{"categoryNo":84,"categoryName":85,"taxonomyType":21,"taxonomyTypeDesc":22},[113,114,115,116,117,118,119,120,121,122,123,26,124,125,126,127,128,129,130,131],"technical debt","debt","technical","technical debt auditor","auditor","coverage","complexity","markers","project","cleanup","unused","code","todo","work","plan","focus","signals","audit","dependency",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":147,"publishedAt":47},"01M70KPYH9QNHCNME5GJQGE22K","readonly-sql-guard","Make an agent's database access provably read-only. Use when an agent runs caller-supplied SQL against a production\u002FERP\u002Fanalytics database (a \"query\" MCP tool, text-to-SQL, an admin console), or when reviewing DB-access code for write\u002FDDL\u002Fside-effect\u002Ftransaction-escape risks. Checks what a statement CALLS, not just its shape.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fdatabase\u002Freadonly-sql-guard\u002FSKILL.md",[138,141,142],{"categoryNo":139,"categoryName":140,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":84,"categoryName":85,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":143,"categoryName":144,"taxonomyType":145,"taxonomyTypeDesc":146},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[148,149,150,151,152,153,154,28,155,156,157,158,159,160,161,94,162,163,26,34],"readonly","guard","sql guard","sql","readonly sql guard","erp","effect","read-only","db","just","tool","calls","only","MCP","access","database",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":169,"sourceHtmlUrl":170,"categories":171,"keywords":173,"publishedAt":47},"01M6AFY6F7CC2BBZP1QD6VTNVC","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Futilities\u002Fweb-artifacts-builder\u002FSKILL.md",[172],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[174,175,176,177,178,179,180,181,182,183,27,184,185,42,186,187,188,189,190,191,192,193,28,194],"artifacts builder","web","web artifacts builder","artifacts","builder","state","routing","state management","component","css","ui","Tools","components","shadcn","react","Tailwind","suite","jsx","html","single-file","ui components",{"skillNo":196,"name":197,"nameZh":6,"description":198,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":199,"sourceHtmlUrl":200,"categories":201,"keywords":206,"publishedAt":47},"01M6AFWF33SFV9Z3SF4PEEE4BF","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.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fsecurity\u002Fwebapp-testing\u002FSKILL.md",[202,205],{"categoryNo":203,"categoryName":204,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[207,208,209,210,211,175,41,27,184,212,213,214,215,28,216,96,217],"webapp testing","testing","webapp","browser","playwright","debugging","toolkit","logs","screenshots","local","behavior",{"skillNo":219,"name":220,"nameZh":6,"description":221,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":168,"licenseFileUrl":222,"sourceHtmlUrl":223,"categories":224,"keywords":232,"publishedAt":47},"01M6AF67Q67JJJ5V51JR2P52KA","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.","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fdiscernment-nudge\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fdavila7\u002Fclaude-code-templates\u002Fblob\u002Fmain\u002Fcli-tool\u002Fcomponents\u002Fskills\u002Fproductivity\u002Fdiscernment-nudge\u002FSKILL.md",[225,228,229],{"categoryNo":226,"categoryName":227,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":84,"categoryName":85,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":230,"categoryName":231,"taxonomyType":145,"taxonomyTypeDesc":146},"01JBSEEDCAT000000000000036","内容创作者",[233,234,235,236,237,238,239,240,177,241,42,124,242,243,244,245,246,160,247,26,248,249,250,251,252,102,253],"discernment nudge","nudge","interpretation","help","run","reasoning","data","writing","lookup","content","review","conversation","short","up","invoke","you","analysis","claims","argument","assemble","recommendations"]