{"id":13409599,"url":"https://github.com/pocketbase/js-sdk","last_synced_at":"2025-05-14T10:09:47.065Z","repository":{"id":43718873,"uuid":"510463319","full_name":"pocketbase/js-sdk","owner":"pocketbase","description":"PocketBase JavaScript SDK","archived":false,"fork":false,"pushed_at":"2025-04-17T12:08:36.000Z","size":2576,"stargazers_count":2448,"open_issues_count":1,"forks_count":143,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-05-14T04:47:45.709Z","etag":null,"topics":["javascript","pocketbase"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/pocketbase","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pocketbase.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-07-04T18:22:29.000Z","updated_at":"2025-05-13T13:47:28.000Z","dependencies_parsed_at":"2024-04-21T22:13:24.726Z","dependency_job_id":"f5670b8b-002c-4528-aab0-043e78295ddb","html_url":"https://github.com/pocketbase/js-sdk","commit_stats":{"total_commits":105,"total_committers":10,"mean_commits":10.5,"dds":"0.11428571428571432","last_synced_commit":"31d5931ba6958e116eb3f1686e6e90cb515b6afe"},"previous_names":[],"tags_count":77,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocketbase%2Fjs-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocketbase%2Fjs-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocketbase%2Fjs-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pocketbase%2Fjs-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pocketbase","download_url":"https://codeload.github.com/pocketbase/js-sdk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254110449,"owners_count":22016392,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","pocketbase"],"created_at":"2024-07-30T20:01:02.228Z","updated_at":"2025-05-14T10:09:47.051Z","avatar_url":"https://github.com/pocketbase.png","language":"TypeScript","readme":"PocketBase JavaScript SDK\n======================================================================\n\nOfficial JavaScript SDK (browser and node) for interacting with the [PocketBase API](https://pocketbase.io/docs).\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Caveats](#caveats)\n    - [Binding filter parameters](#binding-filter-parameters)\n    - [File upload](#file-upload)\n    - [Error handling](#error-handling)\n    - [Auth store](#auth-store)\n        - [LocalAuthStore (default)](#localauthstore-default)\n        - [AsyncAuthStore (_usually used with React Native_)](#asyncauthstore)\n        - [Custom auth store](#custom-auth-store)\n        - [Common auth store fields and methods](#common-auth-store-fields-and-methods)\n    - [Auto cancellation](#auto-cancellation)\n    - [Specify TypeScript definitions](#specify-typescript-definitions)\n    - [Custom request options](#custom-request-options)\n    - [Send hooks](#send-hooks)\n    - [SSR integration](#ssr-integration)\n    - [Security](#security)\n- [Definitions](#definitions)\n- [Development](#development)\n\n\n## Installation\n\n### Browser (manually via script tag)\n\n```html\n\u003cscript src=\"/path/to/dist/pocketbase.umd.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\"\u003e\n    const pb = new PocketBase(\"https://example.com\")\n    ...\n\u003c/script\u003e\n```\n\n_OR if you are using ES modules:_\n```html\n\u003cscript type=\"module\"\u003e\n    import PocketBase from '/path/to/dist/pocketbase.es.mjs'\n\n    const pb = new PocketBase(\"https://example.com\")\n    ...\n\u003c/script\u003e\n```\n\n### Node.js (via npm)\n\n```sh\nnpm install pocketbase --save\n```\n\n```js\n// Using ES modules (default)\nimport PocketBase from 'pocketbase'\n\n// OR if you are using CommonJS modules\nconst PocketBase = require('pocketbase/cjs')\n```\n\n\u003e 🔧 For **Node \u003c 17** you'll need to load a `fetch()` polyfill.\n\u003e I recommend [lquixada/cross-fetch](https://github.com/lquixada/cross-fetch):\n\u003e ```js\n\u003e // npm install cross-fetch --save\n\u003e import 'cross-fetch/polyfill';\n\u003e ```\n---\n\u003e 🔧 Node doesn't have native `EventSource` implementation, so in order to use the realtime subscriptions you'll need to load a `EventSource` polyfill.\n\u003e ```js\n\u003e // for server: npm install eventsource --save\n\u003e import { EventSource } from \"eventsource\";\n\u003e\n\u003e // for React Native: npm install react-native-sse --save\n\u003e import EventSource from \"react-native-sse\";\n\u003e\n\u003e global.EventSource = EventSource;\n\u003e ```\n\n\n## Usage\n\n```js\nimport PocketBase from 'pocketbase';\n\nconst pb = new PocketBase('http://127.0.0.1:8090');\n\n...\n\n// authenticate as auth collection record\nconst userData = await pb.collection('users').authWithPassword('test@example.com', '123456');\n\n// list and filter \"example\" collection records\nconst result = await pb.collection('example').getList(1, 20, {\n    filter: 'status = true \u0026\u0026 created \u003e \"2022-08-01 10:00:00\"'\n});\n\n// and much more...\n```\n\u003e More detailed API docs and copy-paste examples could be found in the [API documentation for each service](https://pocketbase.io/docs/api-records/).\n\n\n## Caveats\n\n### Binding filter parameters\n\nThe SDK comes with a helper `pb.filter(expr, params)` method to generate a filter string with placeholder parameters (`{:paramName}`) populated from an object.\n\n**This method is also recommended when using the SDK in Node/Deno/Bun server-side list queries and accepting untrusted user input as `filter` string arguments, because it will take care to properly escape the generated string expression, avoiding eventual string injection attacks** (_on the client-side this is not much of an issue_).\n\n```js\nconst records = await pb.collection(\"example\").getList(1, 20, {\n  // the same as: \"title ~ 'te\\\\'st' \u0026\u0026 (totalA = 123 || totalB = 123)\"\n  filter: pb.filter(\"title ~ {:title} \u0026\u0026 (totalA = {:num} || totalB = {:num})\", { title: \"te'st\", num: 123 })\n})\n```\n\nThe supported placeholder parameter values are:\n\n- `string` (_single quotes are autoescaped_)\n- `number`\n- `boolean`\n- `Date` object (_will be stringified into the format expected by PocketBase_)\n- `null`\n- everything else is converted to a string using `JSON.stringify()`\n\n\n### File upload\n\nPocketBase Web API supports file upload via `multipart/form-data` requests,\nwhich means that to upload a file it is enough to provide either a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instance OR plain object with `File`/`Blob` prop values.\n\n- Using plain object as body _(this is the same as above and it will be converted to `FormData` behind the scenes)_:\n    ```js\n    const data = {\n      'title':    'lorem ipsum...',\n      'document': new File(...),\n    };\n\n    await pb.collection('example').create(data);\n    ```\n\n- Using `FormData` as body:\n    ```js\n    // the standard way to create multipart/form-data body\n    const data = new FormData();\n    data.set('title', 'lorem ipsum...')\n    data.set('document', new File(...))\n\n    await pb.collection('example').create(data);\n    ```\n\n### Error handling\n\nAll services return a standard [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)-based response, so the error handling is straightforward:\n```js\npb.collection('example').getList(1, 50).then((result) =\u003e {\n  // success...\n  console.log('Result:', result);\n}).catch((error) =\u003e {\n  // error...\n  console.log('Error:', error);\n});\n\n// OR if you are using the async/await syntax:\ntry {\n  const result = await pb.collection('example').getList(1, 50);\n  console.log('Result:', result);\n} catch (error) {\n  console.log('Error:', error);\n}\n```\n\nThe response error is normalized and always returned as `ClientResponseError` object with the following public fields that you could use:\n```js\nClientResponseError {\n    url:           string,     // requested url\n    status:        number,     // response status code\n    response:      { ... },    // the API JSON error response\n    isAbort:       boolean,    // is abort/cancellation error\n    originalError: Error|null, // the original non-normalized error\n}\n```\n\n### Auth store\n\nThe SDK keeps track of the authenticated token and auth model for you via the `pb.authStore` instance.\n\n##### LocalAuthStore (default)\n\nThe default [`LocalAuthStore`](https://github.com/pocketbase/js-sdk/blob/master/src/stores/LocalAuthStore.ts) uses the browser's `LocalStorage` if available, otherwise - will fallback to runtime/memory (aka. on page refresh or service restart you'll have to authenticate again).\n\nConveniently, the default store also takes care to automatically sync the auth store state between multiple tabs.\n\n\u003e _**NB!** Deno also supports `LocalStorage` but keep in mind that, unlike in browsers where the client is the only user, by default Deno `LocalStorage` will be shared by all clients making requests to your server!_\n\n##### AsyncAuthStore\n\nThe SDK comes also with a helper [`AsyncAuthStore`](https://github.com/pocketbase/js-sdk/blob/master/src/stores/AsyncAuthStore.ts) that you can use to integrate with any 3rd party async storage implementation (_usually this is needed when working with React Native_):\n```js\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport PocketBase, { AsyncAuthStore } from 'pocketbase';\n\nconst store = new AsyncAuthStore({\n    save:    async (serialized) =\u003e AsyncStorage.setItem('pb_auth', serialized),\n    initial: AsyncStorage.getItem('pb_auth'),\n});\n\nconst pb = new PocketBase('http://127.0.0.1:8090', store)\n```\n\n##### Custom auth store\n\nIn some situations it could be easier to create your own custom auth store. For this you can extend [`BaseAuthStore`](https://github.com/pocketbase/js-sdk/blob/master/src/stores/BaseAuthStore.ts) and pass the new custom instance as constructor argument to the client:\n\n```js\nimport PocketBase, { BaseAuthStore } from 'pocketbase';\n\nclass CustomAuthStore extends BaseAuthStore {\n    save(token, model) {\n        super.save(token, model);\n\n        // your custom business logic...\n    }\n}\n\nconst pb = new PocketBase('http://127.0.0.1:8090', new CustomAuthStore());\n```\n\n##### Common auth store fields and methods\n\nThe default `pb.authStore` extends [`BaseAuthStore`](https://github.com/pocketbase/js-sdk/blob/master/src/stores/BaseAuthStore.ts) and has the following public members that you can use:\n\n```js\nBaseAuthStore {\n    // base fields\n    record:       RecordModel|null // the authenticated auth record\n    token:        string  // the authenticated token\n    isValid:      boolean // checks if the store has existing and unexpired token\n    isSuperuser:  boolean // checks if the store state is for superuser\n\n    // main methods\n    clear()             // \"logout\" the authenticated record\n    save(token, record) // update the store with the new auth data\n    onChange(callback, fireImmediately = false) // register a callback that will be called on store change\n\n    // cookie parse and serialize helpers\n    loadFromCookie(cookieHeader, key = 'pb_auth')\n    exportToCookie(options = {}, key = 'pb_auth')\n}\n```\n\nTo _\"logout\"_ the authenticated record you can call `pb.authStore.clear()`.\n\nTo _\"listen\"_ for changes in the auth store, you can register a new listener via `pb.authStore.onChange`, eg:\n```js\n// triggered everytime on store change\nconst removeListener1 = pb.authStore.onChange((token, record) =\u003e {\n    console.log('New store data 1:', token, record)\n});\n\n// triggered once right after registration and everytime on store change\nconst removeListener2 = pb.authStore.onChange((token, record) =\u003e {\n    console.log('New store data 2:', token, record)\n}, true);\n\n// (optional) removes the attached listeners\nremoveListener1();\nremoveListener2();\n```\n\n\n### Auto cancellation\n\nThe SDK client will auto cancel duplicated pending requests for you.\nFor example, if you have the following 3 duplicated endpoint calls, only the last one will be executed, while the first 2 will be cancelled with `ClientResponseError` error:\n\n```js\npb.collection('example').getList(1, 20) // cancelled\npb.collection('example').getList(2, 20) // cancelled\npb.collection('example').getList(3, 20) // executed\n```\n\nTo change this behavior per request basis, you can adjust the `requestKey: null|string` special query parameter.\nSet it to `null` to unset the default request identifier and to disable auto cancellation for the specific request.\nOr set it to a unique string that will be used as request identifier and based on which pending requests will be matched (default to `HTTP_METHOD + path`, eg. \"GET /api/users\")\n\nExample:\n\n```js\npb.collection('example').getList(1, 20);                        // cancelled\npb.collection('example').getList(1, 20);                        // executed\npb.collection('example').getList(1, 20, { requestKey: \"test\" }) // cancelled\npb.collection('example').getList(1, 20, { requestKey: \"test\" }) // executed\npb.collection('example').getList(1, 20, { requestKey: null })   // executed\npb.collection('example').getList(1, 20, { requestKey: null })   // executed\n\n// globally disable auto cancellation\npb.autoCancellation(false);\n\npb.collection('example').getList(1, 20); // executed\npb.collection('example').getList(1, 20); // executed\npb.collection('example').getList(1, 20); // executed\n```\n\n**If you want to globally disable the auto cancellation behavior, you could set `pb.autoCancellation(false)`.**\n\nTo manually cancel pending requests, you could use `pb.cancelAllRequests()` or `pb.cancelRequest(requestKey)`.\n\n\n### Specify TypeScript definitions\n\nYou could specify custom TypeScript definitions for your Record models using generics:\n\n```ts\ninterface Task {\n  // type the collection fields you want to use...\n  id:   string;\n  name: string;\n}\n\npb.collection('tasks').getList\u003cTask\u003e(1, 20) // -\u003e results in Promise\u003cListResult\u003cTask\u003e\u003e\npb.collection('tasks').getOne\u003cTask\u003e(\"RECORD_ID\")  // -\u003e results in Promise\u003cTask\u003e\n```\n\nAlternatively, if you don't want to type the generic argument every time you can define a global PocketBase type using type assertion:\n\n```ts\ninterface Task {\n  id:   string;\n  name: string;\n}\n\ninterface Post {\n  id:     string;\n  title:  string;\n  active: boolean;\n}\n\ninterface TypedPocketBase extends PocketBase {\n  collection(idOrName: string): RecordService // default fallback for any other collection\n  collection(idOrName: 'tasks'): RecordService\u003cTask\u003e\n  collection(idOrName: 'posts'): RecordService\u003cPost\u003e\n}\n\n...\n\nconst pb = new PocketBase(\"http://127.0.0.1:8090\") as TypedPocketBase;\n\npb.collection('tasks').getOne(\"RECORD_ID\") // -\u003e results in Promise\u003cTask\u003e\npb.collection('posts').getOne(\"RECORD_ID\") // -\u003e results in Promise\u003cPost\u003e\n```\n\n\n### Custom request options\n\nAll API services accept an optional `options` argument (usually the last one and of type [`SendOptions`](https://github.com/pocketbase/js-sdk/blob/master/src/tools/options.ts)), that can be used to provide:\n\n- custom headers for a single request\n- custom fetch options\n- or even your own `fetch` implementation\n\nFor example:\n\n```js\npb.collection('example').getList(1, 20, {\n    expand:          'someRel',\n    otherQueryParam: '123',\n\n    // custom headers\n    headers: {\n        'X-Custom-Header': 'example',\n    },\n\n    // custom fetch options\n    keepalive: false,\n    cache:     'no-store',\n\n    // or custom fetch implementation\n    fetch: async (url, config) =\u003e { ... },\n})\n```\n\n_Note that for backward compatability and to minimize the verbosity, any \"unknown\" top-level field will be treated as query parameter._\n\n\n### Send hooks\n\nSometimes you may want to modify the request data globally or to customize the response.\n\nTo accomplish this, the SDK provides 2 function hooks:\n\n- `beforeSend` - triggered right before sending the `fetch` request, allowing you to inspect/modify the request config.\n    ```js\n    const pb = new PocketBase('http://127.0.0.1:8090');\n\n    pb.beforeSend = function (url, options) {\n        // For list of the possible request options properties check\n        // https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n        options.headers = Object.assign({}, options.headers, {\n            'X-Custom-Header': 'example',\n        });\n\n        return { url, options };\n    };\n\n    // use the created client as usual...\n    ```\n\n- `afterSend` - triggered after successfully sending the `fetch` request, allowing you to inspect/modify the response object and its parsed data.\n    ```js\n    const pb = new PocketBase('http://127.0.0.1:8090');\n\n    pb.afterSend = function (response, data) {\n        // do something with the response state\n        console.log(response.status);\n\n        return Object.assign(data, {\n            // extend the data...\n            \"additionalField\": 123,\n        });\n    };\n\n    // use the created client as usual...\n    ```\n\n### SSR integration\n\nUnfortunately, **there is no \"one size fits all\" solution** because each framework handle SSR differently (_and even in a single framework there is more than one way of doing things_).\n\nBut in general, the idea is to use a cookie based flow:\n\n1. Create a new `PocketBase` instance for each server-side request\n2. \"Load/Feed\" your `pb.authStore` with data from the request cookie\n3. Perform your application server-side actions\n4. Before returning the response to the client, update the cookie with the latest `pb.authStore` state\n\nAll [`BaseAuthStore`](https://github.com/pocketbase/js-sdk/blob/master/src/stores/BaseAuthStore.ts) instances have 2 helper methods that\nshould make working with cookies a little bit easier:\n\n```js\n// update the store with the parsed data from the cookie string\npb.authStore.loadFromCookie('pb_auth=...');\n\n// exports the store data as cookie, with option to extend the default SameSite, Secure, HttpOnly, Path and Expires attributes\npb.authStore.exportToCookie({ httpOnly: false }); // Output: 'pb_auth=...'\n```\n\nBelow you could find several examples:\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eSvelteKit\u003c/strong\u003e\u003c/summary\u003e\n\nOne way to integrate with SvelteKit SSR could be to create the PocketBase client in a [hook handle](https://kit.svelte.dev/docs/hooks#handle)\nand pass it to the other server-side actions using the `event.locals`.\n\n```js\n// src/hooks.server.js\nimport PocketBase from 'pocketbase';\n\n/** @type {import('@sveltejs/kit').Handle} */\nexport async function handle({ event, resolve }) {\n    event.locals.pb = new PocketBase('http://127.0.0.1:8090');\n\n    // load the store data from the request cookie string\n    event.locals.pb.authStore.loadFromCookie(event.request.headers.get('cookie') || '');\n\n    try {\n        // get an up-to-date auth store state by verifying and refreshing the loaded auth model (if any)\n        event.locals.pb.authStore.isValid \u0026\u0026 await event.locals.pb.collection('users').authRefresh();\n    } catch (_) {\n        // clear the auth store on failed refresh\n        event.locals.pb.authStore.clear();\n    }\n\n    const response = await resolve(event);\n\n    // send back the default 'pb_auth' cookie to the client with the latest store state\n    response.headers.append('set-cookie', event.locals.pb.authStore.exportToCookie());\n\n    return response;\n}\n```\n\nAnd then, in some of your server-side actions, you could directly access the previously created `event.locals.pb` instance:\n\n```js\n// src/routes/login/+server.js\n/**\n * Creates a `POST /login` server-side endpoint\n *\n * @type {import('./$types').RequestHandler}\n */\nexport async function POST({ request, locals }) {\n    const { email, password } = await request.json();\n\n    const { token, record } = await locals.pb.collection('users').authWithPassword(email, password);\n\n    return new Response('Success...');\n}\n```\n\nFor proper `locals.pb` type detection, you can also add `PocketBase` in your your global types definition:\n\n```ts\n// src/app.d.ts\nimport PocketBase from 'pocketbase';\n\ndeclare global {\n    declare namespace App {\n        interface Locals {\n            pb: PocketBase\n        }\n    }\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eAstro\u003c/strong\u003e\u003c/summary\u003e\n\nTo integrate with Astro SSR, you could create the PocketBase client in the [Middleware](https://docs.astro.build/en/guides/middleware) and pass it to the Astro components using the `Astro.locals`.\n\n```ts \n// src/middleware/index.ts\nimport PocketBase from 'pocketbase';\n\nimport { defineMiddleware } from 'astro/middleware';\n\nexport const onRequest = defineMiddleware(async ({ locals, request }: any, next: () =\u003e any) =\u003e {\n    locals.pb = new PocketBase('http://127.0.0.1:8090');\n\n    // load the store data from the request cookie string\n    locals.pb.authStore.loadFromCookie(request.headers.get('cookie') || '');\n\n    try {\n        // get an up-to-date auth store state by verifying and refreshing the loaded auth record (if any)\n        locals.pb.authStore.isValid \u0026\u0026 await locals.pb.collection('users').authRefresh();\n    } catch (_) {\n        // clear the auth store on failed refresh\n        locals.pb.authStore.clear();\n    }\n\n    const response = await next();\n\n    // send back the default 'pb_auth' cookie to the client with the latest store state\n    response.headers.append('set-cookie', locals.pb.authStore.exportToCookie());\n\n    return response;\n});\n```\n\nAnd then, in your Astro file's component script, you could directly access the previously created `locals.pb` instance:\n\n```ts\n// src/pages/index.astro\n---\nconst locals = Astro.locals;\n\nconst userAuth = async () =\u003e {\n    const { token, record } = await locals.pb.collection('users').authWithPassword('test@example.com', '123456');\n\n    return new Response('Success...');\n};\n---\n```\n\nAlthough middleware functionality is available in both `SSG` and `SSR` projects, you would likely want to handle any sensitive data on the server side. Update your `output` configuration to `'server'`:\n\n```mjs\n// astro.config.mjs\nimport { defineConfig } from 'astro/config';\n\nexport default defineConfig({\n    output: 'server'\n});\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eNuxt 3\u003c/strong\u003e\u003c/summary\u003e\n\nOne way to integrate with Nuxt 3 SSR could be to create the PocketBase client in a [nuxt plugin](https://v3.nuxtjs.org/guide/directory-structure/plugins)\nand provide it as a helper to the `nuxtApp` instance:\n\n```js\n// plugins/pocketbase.js\nimport PocketBase from 'pocketbase';\n\nexport default defineNuxtPlugin(async () =\u003e {\n  const pb = new PocketBase('http://127.0.0.1:8090');\n\n  const cookie = useCookie('pb_auth', {\n    path:     '/',\n    secure:   true,\n    sameSite: 'strict',\n    httpOnly: false, // change to \"true\" if you want only server-side access\n    maxAge:   604800,\n  })\n\n  // load the store data from the cookie value\n  pb.authStore.save(cookie.value?.token, cookie.value?.record);\n\n  // send back the default 'pb_auth' cookie to the client with the latest store state\n  pb.authStore.onChange(() =\u003e {\n    cookie.value = {\n      token: pb.authStore.token,\n      record: pb.authStore.record,\n    };\n  });\n\n  try {\n      // get an up-to-date auth store state by verifying and refreshing the loaded auth model (if any)\n      pb.authStore.isValid \u0026\u0026 await pb.collection('users').authRefresh();\n  } catch (_) {\n      // clear the auth store on failed refresh\n      pb.authStore.clear();\n  }\n\n  return {\n    provide: { pb }\n  }\n});\n```\n\nAnd then in your component you could access it like this:\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    Show: {{ data }}\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\n  const { data } = await useAsyncData(async (nuxtApp) =\u003e {\n    // fetch and return all \"example\" records...\n    const records = await nuxtApp.$pb.collection('example').getFullList();\n\n    return structuredClone(records);\n  })\n\u003c/script\u003e\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eNuxt 2\u003c/strong\u003e\u003c/summary\u003e\n\nOne way to integrate with Nuxt 2 SSR could be to create the PocketBase client in a [nuxt plugin](https://nuxtjs.org/docs/directory-structure/plugins#plugins-directory) and provide it as a helper to the `$root` context:\n\n```js\n// plugins/pocketbase.js\nimport PocketBase from  'pocketbase';\n\nexport default async (ctx, inject) =\u003e {\n  const pb = new PocketBase('http://127.0.0.1:8090');\n\n  // load the store data from the request cookie string\n  pb.authStore.loadFromCookie(ctx.req?.headers?.cookie || '');\n\n  // send back the default 'pb_auth' cookie to the client with the latest store state\n  pb.authStore.onChange(() =\u003e {\n    ctx.res?.setHeader('set-cookie', pb.authStore.exportToCookie());\n  });\n\n  try {\n      // get an up-to-date auth store state by verifying and refreshing the loaded auth record (if any)\n      pb.authStore.isValid \u0026\u0026 await pb.collection('users').authRefresh();\n  } catch (_) {\n      // clear the auth store on failed refresh\n      pb.authStore.clear();\n  }\n\n  inject('pocketbase', pb);\n};\n```\n\nAnd then in your component you could access it like this:\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    Show: {{ items }}\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n  export default {\n    async asyncData({ $pocketbase }) {\n      // fetch and return all \"example\" records...\n      const items = await $pocketbase.collection('example').getFullList();\n\n      return { items }\n    }\n  }\n\u003c/script\u003e\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eNext.js\u003c/strong\u003e\u003c/summary\u003e\n\nNext.js doesn't seem to have a central place where you can read/modify the server request and response.\n[There is support for middlewares](https://nextjs.org/docs/advanced-features/middleware),\nbut they are very limited and, at the time of writing, you can't pass data from a middleware to the `getServerSideProps` functions (https://github.com/vercel/next.js/discussions/31792).\n\nOne way to integrate with Next.js SSR could be to create a custom `PocketBase` instance in each of your `getServerSideProps`:\n\n```jsx\nimport PocketBase from 'pocketbase';\n\n// you can place this helper in a separate file so that it can be reused\nasync function initPocketBase(req, res) {\n  const pb = new PocketBase('http://127.0.0.1:8090');\n\n  // load the store data from the request cookie string\n  pb.authStore.loadFromCookie(req?.headers?.cookie || '');\n\n  // send back the default 'pb_auth' cookie to the client with the latest store state\n  pb.authStore.onChange(() =\u003e {\n    res?.setHeader('set-cookie', pb.authStore.exportToCookie());\n  });\n\n  try {\n      // get an up-to-date auth store state by verifying and refreshing the loaded auth record (if any)\n      pb.authStore.isValid \u0026\u0026 await pb.collection('users').authRefresh();\n  } catch (_) {\n      // clear the auth store on failed refresh\n      pb.authStore.clear();\n  }\n\n  return pb\n}\n\nexport async function getServerSideProps({ req, res }) {\n  const pb = await initPocketBase(req, res)\n\n  // fetch example records...\n  const result = await pb.collection('example').getList(1, 30);\n\n  return {\n    props: {\n      // ...\n    },\n  }\n}\n\nexport default function Home() {\n  return (\n    \u003cdiv\u003eHello world!\u003c/div\u003e\n  )\n}\n```\n\u003c/details\u003e\n\n### Security\n\nThe most common frontend related vulnerability is XSS (and CSRF when dealing with cookies).\nFortunately, modern browsers can detect and mitigate most of this type of attacks if [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is provided.\n\n**To prevent a malicious user or 3rd party script to steal your PocketBase auth token, it is recommended to configure a basic CSP for your application (either as `meta` tag or HTTP header).**\n\nThis is out of the scope of the SDK, but you could find more resources about CSP at:\n\n- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP\n- https://content-security-policy.com\n\n\n**Depending on how and where you use the JS SDK, it is also recommended to use the helper `pb.filter(expr, params)` when constructing filter strings with untrusted user input to avoid eventual string injection attacks (see [Binding filter parameters](#binding-filter-parameters)).**\n\n\n## Definitions\n\n### Creating new client instance\n\n```js\nconst pb = new PocketBase(baseURL = '/', authStore = LocalAuthStore);\n```\n\n### Instance methods\n\n\u003e Each instance method returns the `PocketBase` instance allowing chaining.\n\n| Method                            | Description                                                                   |\n|:----------------------------------|:------------------------------------------------------------------------------|\n| `pb.send(path, sendOptions = {})` | Sends an api http request.                                                    |\n| `pb.autoCancellation(enable)`     | Globally enable or disable auto cancellation for pending duplicated requests. |\n| `pb.cancelAllRequests()`          | Cancels all pending requests.                                                 |\n| `pb.cancelRequest(cancelKey)`     | Cancels single request by its cancellation token key.                         |\n| `pb.buildURL(path)`               | Builds a full client url by safely concatenating the provided path.           |\n\n\n### Services\n\n\u003e Each service call returns a `Promise` object with the API response.\n\n##### RecordService\n\n###### _Crud handlers_\n\n```js\n// Returns a paginated records list.\n🔓 pb.collection(collectionIdOrName).getList(page = 1, perPage = 30, options = {});\n\n// Returns a list with all records batch fetched at once\n// (by default 200 items per request; to change it set the `batch` param).\n🔓 pb.collection(collectionIdOrName).getFullList(options = {});\n\n// Returns the first found record matching the specified filter.\n🔓 pb.collection(collectionIdOrName).getFirstListItem(filter, options = {});\n\n// Returns a single record by its id.\n🔓 pb.collection(collectionIdOrName).getOne(recordId, options = {});\n\n// Creates (aka. register) a new record.\n🔓 pb.collection(collectionIdOrName).create(bodyParams = {}, options = {});\n\n// Updates an existing record by its id.\n🔓 pb.collection(collectionIdOrName).update(recordId, bodyParams = {}, options = {});\n\n// Deletes a single record by its id.\n🔓 pb.collection(collectionIdOrName).delete(recordId, options = {});\n\n```\n\n###### _Realtime handlers_\n\n```js\n// Subscribe to realtime changes to the specified topic (\"*\" or recordId).\n//\n// It is safe to subscribe multiple times to the same topic.\n//\n// You can use the returned UnsubscribeFunc to remove a single registered subscription.\n// If you want to remove all subscriptions related to the topic use unsubscribe(topic).\n🔓 pb.collection(collectionIdOrName).subscribe(topic, callback, options = {});\n\n// Unsubscribe from all registered subscriptions to the specified topic (\"*\" or recordId).\n// If topic is not set, then it will remove all registered collection subscriptions.\n🔓 pb.collection(collectionIdOrName).unsubscribe([topic]);\n```\n\n###### _Auth handlers_\n\n\u003e Available only for \"auth\" type collections.\n\n```js\n// Returns all available application auth methods.\n🔓 pb.collection(collectionIdOrName).listAuthMethods(options = {});\n\n// Authenticates a record with their username/email and password.\n🔓 pb.collection(collectionIdOrName).authWithPassword(usernameOrEmail, password, options = {});\n\n// Authenticates a record with an OTP.\n🔓 pb.collection(collectionIdOrName).authWithOTP(otpId, password, options = {});\n\n// Authenticates a record with OAuth2 provider without custom redirects, deeplinks or even page reload.\n🔓 pb.collection(collectionIdOrName).authWithOAuth2(authConfig);\n\n// Authenticates a record with OAuth2 code.\n🔓 pb.collection(collectionIdOrName).authWithOAuth2Code(provider, code, codeVerifier, redirectUrl, createData = {}, options = {});\n\n// Refreshes the current authenticated record and auth token.\n🔐 pb.collection(collectionIdOrName).authRefresh(options = {});\n\n// Sends a record OTP email request.\n🔓 pb.collection(collectionIdOrName).requestOTP(email, options = {});\n\n// Sends a record password reset email.\n🔓 pb.collection(collectionIdOrName).requestPasswordReset(email, options = {});\n\n// Confirms a record password reset request.\n🔓 pb.collection(collectionIdOrName).confirmPasswordReset(resetToken, newPassword, newPasswordConfirm, options = {});\n\n// Sends a record verification email request.\n🔓 pb.collection(collectionIdOrName).requestVerification(email, options = {});\n\n// Confirms a record email verification request.\n🔓 pb.collection(collectionIdOrName).confirmVerification(verificationToken, options = {});\n\n// Sends a record email change request to the provider email.\n🔐 pb.collection(collectionIdOrName).requestEmailChange(newEmail, options = {});\n\n// Confirms record new email address.\n🔓 pb.collection(collectionIdOrName).confirmEmailChange(emailChangeToken, userPassword, options = {});\n\n// Lists all linked external auth providers for the specified record.\n🔐 pb.collection(collectionIdOrName).listExternalAuths(recordId, options = {});\n\n// Unlinks a single external auth provider relation from the specified record.\n🔐 pb.collection(collectionIdOrName).unlinkExternalAuth(recordId, provider, options = {});\n\n// Impersonate authenticates with the specified recordId and returns a new client with the received auth token in a memory store.\n🔐 pb.collection(collectionIdOrName).impersonate(recordId, duration, options = {});\n```\n\n---\n\n#### BatchService\n\n```js\n// create a new batch instance\nconst batch = pb.createBatch();\n\n// register create/update/delete/upsert requests to the created batch\nbatch.collection('example1').create({ ... });\nbatch.collection('example2').update('RECORD_ID', { ... });\nbatch.collection('example3').delete('RECORD_ID');\nbatch.collection('example4').upsert({ ... });\n\n// send the batch request\nconst result = await batch.send()\n```\n\n---\n\n##### FileService\n\n```js\n// Builds and returns an absolute record file url for the provided filename.\n🔓 pb.files.getURL(record, filename, options = {});\n\n// Requests a new private file access token for the current authenticated record.\n🔐 pb.files.getToken(options = {});\n```\n\n---\n\n##### CollectionService\n\n```js\n// Returns a paginated collections list.\n🔐 pb.collections.getList(page = 1, perPage = 30, options = {});\n\n// Returns a list with all collections batch fetched at once\n// (by default 200 items per request; to change it set the `batch` query param).\n🔐 pb.collections.getFullList(options = {});\n\n// Returns the first found collection matching the specified filter.\n🔐 pb.collections.getFirstListItem(filter, options = {});\n\n// Returns a single collection by its id or name.\n🔐 pb.collections.getOne(idOrName, options = {});\n\n// Creates (aka. register) a new collection.\n🔐 pb.collections.create(bodyParams = {}, options = {});\n\n// Updates an existing collection by its id or name.\n🔐 pb.collections.update(idOrName, bodyParams = {}, options = {});\n\n// Deletes a single collection by its id or name.\n🔐 pb.collections.delete(idOrName, options = {});\n\n// Deletes all records associated with the specified collection.\n🔐 pb.collections.truncate(idOrName, options = {});\n\n// Imports the provided collections.\n🔐 pb.collections.import(collections, deleteMissing = false, options = {});\n\n// Returns type indexed map with scaffolded collection models populated with their default field values.\n🔐 pb.collections.getScaffolds(options = {});\n```\n\n---\n\n##### LogService\n\n```js\n// Returns a paginated logs list.\n🔐 pb.logs.getList(page = 1, perPage = 30, options = {});\n\n// Returns a single log by its id.\n🔐 pb.logs.getOne(id, options = {});\n\n// Returns logs statistics.\n🔐 pb.logs.getStats(options = {});\n```\n\n---\n\n##### SettingsService\n\n```js\n// Returns a map with all available app settings.\n🔐 pb.settings.getAll(options = {});\n\n// Bulk updates app settings.\n🔐 pb.settings.update(bodyParams = {}, options = {});\n\n// Performs a S3 storage connection test.\n🔐 pb.settings.testS3(filesystem = \"storage\", options = {});\n\n// Sends a test email (verification, password-reset, email-change).\n🔐 pb.settings.testEmail(collectionIdOrName, toEmail, template, options = {});\n\n// Generates a new Apple OAuth2 client secret.\n🔐 pb.settings.generateAppleClientSecret(clientId, teamId, keyId, privateKey, duration, options = {});\n```\n\n---\n\n##### RealtimeService\n\n\u003e This service is usually used with custom realtime actions.\n\u003e For records realtime subscriptions you can use the subscribe/unsubscribe\n\u003e methods available in the `pb.collection()` RecordService.\n\n```js\n// Initialize the realtime connection (if not already) and register the subscription listener.\n//\n// You can subscribe to the `PB_CONNECT` event if you want to listen to the realtime connection connect/reconnect events.\n🔓 pb.realtime.subscribe(topic, callback, options = {});\n\n// Unsubscribe from all subscription listeners with the specified topic.\n🔓 pb.realtime.unsubscribe(topic?);\n\n// Unsubscribe from all subscription listeners starting with the specified topic prefix.\n🔓 pb.realtime.unsubscribeByPrefix(topicPrefix);\n\n// Unsubscribe from all subscriptions matching the specified topic and listener function.\n🔓 pb.realtime.unsubscribeByTopicAndListener(topic, callback);\n\n// Getter that checks whether the realtime connection has been established.\npb.realtime.isConnected\n\n// An optional hook that is invoked when the realtime client disconnects\n// either when unsubscribing from all subscriptions or when the connection\n// was interrupted or closed by the server.\n//\n// Note that the realtime client autoreconnect on its own and this hook is\n// useful only for the cases where you want to apply a special behavior on\n// server error or after closing the realtime connection.\npb.realtime.onDisconnect = function(activeSubscriptions)\n```\n\n---\n\n##### BackupService\n\n```js\n// Returns list with all available backup files.\n🔐 pb.backups.getFullList(options = {});\n\n// Initializes a new backup.\n🔐 pb.backups.create(basename = \"\", options = {});\n\n// Upload an existing app data backup.\n🔐 pb.backups.upload({ file: File/Blob }, options = {});\n\n// Deletes a single backup by its name.\n🔐 pb.backups.delete(key, options = {});\n\n// Initializes an app data restore from an existing backup.\n🔐 pb.backups.restore(key, options = {});\n\n// Builds a download url for a single existing backup using a\n// superuser file token and the backup file key.\n🔐 pb.backups.getDownloadURL(token, key);\n```\n\n##### CronService\n\n```js\n// Returns list with all available cron jobs.\n🔐 pb.crons.getFullList(options = {});\n\n// Runs the specified cron job.\n🔐 pb.crons.run(jobId, options = {});\n```\n\n---\n\n##### HealthService\n\n```js\n// Checks the health status of the api.\n🔓 pb.health.check(options = {});\n```\n\n\n## Development\n```sh\n# run unit tests\nnpm test\n\n# run prettier\nnpm run format\n\n# build and minify for production\nnpm run build\n```\n","funding_links":[],"categories":["Official Packages","TypeScript","javascript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocketbase%2Fjs-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpocketbase%2Fjs-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpocketbase%2Fjs-sdk/lists"}