Skip to content

v0.17.0 Release

Compare
Choose a tag to compare
@ganigeorgiev ganigeorgiev released this 26 Aug 07:24
· 85 commits to master since this release

⚠️ Please read carefully the release notes as there are some minor breaking changes!

  • To simplify file uploads, we now allow sending the multipart/form-data request body also as plain object if at least one of the object props has File or Blob value.

    // the standard way to create multipart/form-data body
    const data = new FormData();
    data.set("title", "lorem ipsum...")
    data.set("document", new File(...))
    
    // this is the same as above
    // (it will be converted behind the scenes to FormData)
    const data = {
      "title":    "lorem ipsum...",
      "document": new File(...),
    };
    
    await pb.collection("example").create(data);
  • Added new pb.authStore.isAdmin and pb.authStore.isAuthRecord helpers to check the type of the current auth state.

  • The default LocalAuthStore now listen to the browser storage event,
    so that we can sync automatically the pb.authStore state between multiple tabs.

  • Added new helper AsyncAuthStore class that can be used to integrate with any 3rd party async storage implementation (usually this is needed when working with React Native):

    import AsyncStorage from "@react-native-async-storage/async-storage";
    import PocketBase, { AsyncAuthStore } from "pocketbase";
    
    const store = new AsyncAuthStore({
        save:    async (serialized) => AsyncStorage.setItem("pb_auth", serialized),
        initial: await AsyncStorage.getItem("pb_auth"),
    });
    
    const pb = new PocketBase("https://example.com", store)
  • pb.files.getUrl() now returns empty string in case an empty filename is passed.

  • ⚠️ All API actions now return plain object (POJO) as response, aka. the custom class wrapping was removed and you no longer need to manually call structuredClone(response) when using with SSR frameworks.

    This could be a breaking change if you use the below classes (and respectively their helper methods like $isNew, $load(), etc.) since they were replaced with plain TS interfaces:

    class BaseModel    -> interface BaseModel
    class Admin        -> interface AdminModel
    class Record       -> interface RecordModel
    class LogRequest   -> interface LogRequestModel
    class ExternalAuth -> interface ExternalAuthModel
    class Collection   -> interface CollectionModel
    class SchemaField  -> interface SchemaField
    class ListResult   -> interface ListResult

    Side-note: If you use somewhere in your code the Record and Admin classes to determine the type of your pb.authStore.model,
    you can safely replace it with the new pb.authStore.isAdmin and pb.authStore.isAuthRecord getters.

  • ⚠️ Added support for per-request fetch options, including also specifying completely custom fetch implementation.

    In addition to the default fetch options, the following configurable fields are supported:

    interface SendOptions extends RequestInit {
        // any other custom key will be merged with the query parameters
        // for backward compatibility and to minimize the verbosity
        [key: string]: any;
    
        // optional custom fetch function to use for sending the request
        fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response>;
    
        // custom headers to send with the requests
        headers?: { [key: string]: string };
    
        // the body of the request (serialized automatically for json requests)
        body?: any;
    
        // query params that will be appended to the request url
        query?: { [key: string]: any };
    
        // the request identifier that can be used to cancel pending requests
        requestKey?:  string|null;
    
        // @deprecated use `requestKey:string` instead
        $cancelKey?:  string;
    
        // @deprecated use `requestKey:null` instead
        $autoCancel?: boolean;
    }

    For most users the above will not be a breaking change since there are available function overloads (when possible) to preserve the old behavior, but you can get a warning message in the console to update to the new format.
    For example:

    // OLD (should still work but with a warning in the console)
    await pb.collection("example").authRefresh({}, {
      "expand": "someRelField",
    })
    
    // NEW
    await pb.collection("example").authRefresh({
      "expand": "someRelField",
      // send some additional header
      "headers": {
        "X-Custom-Header": "123",
      },
      "cache": "no-store" // also usually used by frameworks like Next.js
    })
  • Eagerly open the default OAuth2 signin popup in case no custom urlCallback is provided as a workaround for Safari.

  • Internal refactoring (updated dev dependencies, refactored the tests to use Vitest instead of Mocha, etc.).